下面是小编为大家带来的Android中Activity Window View ViewGroup之间,本文共9篇,希望大家能够喜欢!本文原稿由网友“茶水间”提供。
篇1:Android中Activity Window View ViewGroup之间
Activity:是Android四大组件之一,用于展示一个与用户交互的界面
----展示界面
----与用户交互
Activity相当于控制器,负责调用业务类的方法,简单的业务可以直接在Activity中处理。
Activity通过内置是Window对象的setContentView(资源位置.资源类型.资源)方法来展示界面。
用户通过View操作界面。
与用户交互时,通过View来捕获事件,再通过WindowManagerService传递消息(当前操作的控件,事件的类型)。Android框架再回调相应的Activity方法,实现与用户的交互。
Window:是Android中的窗口,表示顶级窗口,也就是主窗口,每一个主窗口,都有一个view,称之为DecorView(装饰视图),它是主窗口的顶级View(DecorView必须是一个布局容器,因为它要容纳其他的View)。当Activity调用setContentView时,实际上就是调用
Window对象的setContentView()方法,执行该方法,把用户定义的View添加到DecorView中,最终完成对View的展示。
View:视图,是用户接口组件的基本构建块,它在屏幕中占用一个矩形区域,它是所 有UI控件的基类,如一个按钮或文本框,
View负责图形界面渲染及事件处理
Android已经为我们提供了一系列的标准UI控件供我们直接使用,同时,我们也可以通过继承于View或View的子类,来实现我们自定义的UI控件
ViewGroup:Android中的视图组。包含多个View,也可以包含ViewGroup。
ViewGroup是一个特殊的View,能够容纳其它的View(子控件),它是布局和视图容器的基类
* ViewGroup.LayoutParams 布局参数类属性:
android:layout_width 相对于父控件的宽度 (wrap_content, match_parent,fill_parent)
android:layout_height 相对于父控件高度 (wrap_content,match_parent,fill_parent)
* ViewGroup常用的方法
addView(): 向视图组添加View
removeView():从视图组移去View
getChildCount:获得视图组子控件的数量
getChildAt() : 获得具体某个子控件
在Android中ViewGroup是View的子类,布局管理器是ViewGroup的子类。
篇2:Android中AsyncTask使用
一、AsyncTask的作用:
代替Thread+Handler的组合,使创建异步任务变得简单,
AsyncTask执行后台操作,并在用户界面上发布结果,而不必处理线程。
二、AsyncTask的定义:
public abstract class AsyncTask
extends Object
AsyncTask必须子类可以使用。子类将覆盖至少一个方法(doInBackground执行异步任务),通常会覆盖一次(onPostExecute显示结果,更新UI)
AsyncTask三种类型如下:
》Params,参数的类型发送到任务执行时。
》Progress,在后台计算过程中公布的进度单元类型。
》Result,计算结果的类型。
不是所有类型都是异步任务所使用的。要标记为未使用的类型,设置该类型Void:
三、AsyncTask的方法:
1、onPreExecute()
在任务开始后立即调用,在UI线程执行。这一步通常用于设置任务,例如在用户界面中初始化进度条。
2、doInBackground(Params...)
后台线程调用onPreExecute()完成后立即执行。这一步后台进程执行,可能会花费很长时间。
3、onProgressUpdate(Progress...)
调用publishProgress,在UI线程上执行,
这种方法是用来显示用户进度界面,后台进程仍在执行。例如,它可用于显示一个进度条或在文本中显示日志。
4、onPostExecute(Result)
后台进程处理完后,在UI线程上执行。后台进程的结果被传递到这一步作为参数。
常用的写法如下:
class MyTask extends AsyncTask new MyTask().execute();//执行任务 三、AsyncTask的规则: 1、任务实例必须在用户界面线程中创建。 2、execute(Params... params)方法必须在UI线程中调用。 3、不要手动调用onPreExecute,doInBackground,onProgressUpdate,onPostExecute这些方法 4、一个任务实例只能执行一次,如果执行第二次将会抛出异常 在android中,进程这个概念被淡化了,我们知道Android的每一个应用都是运行在一个独立的DVM中,他们之间互不影响;应用退出之后,并没有立马杀死进程,进程依然停留在内存中,这么做的目的是为了提高下次启动时的速度,而在Android中管理进程的模块是AMS,主要有LRU weight,OOM adj,Low Memory Killer共同来完成进程的管理。 1 LRU weightLRU(最近最少使用)weight 主要用来衡量LRU的权重,在android进程启动之后,会以ProcessRecord类型的方式创建一个实例,保存到AMS的mLruProcesses变量中,mLurProcesses会以LRU的顺序来存储进程信息。当有一下情况时会更新mLruProcesses: 1.应用程序异常退出 2.调用AMS显式杀死进程 3.启动和调度四大组件 这里以启动和调度四大组件为例,它最终会调用AMS的updateLruProcessLock方法: final void updateLruProcessLocked(ProcessRecord app,boolean oomAdj, boolean updateActivityTime) { mLruSeq++;//lru序号加一 updateLruProcessInternalLocked(app, oomAdj, updateActivityTime, 0); } 先将LRU序号加一,用于标记一次更新LRU的操作,然后调用updateLruProcessInternalLocked: private final void updateLruProcessInternalLocked(ProcessRecord app,boolean oomAdj, boolean updateActivityTime, int bestPos) { // put it on the LRU to keep track of when it should be exited. int lrui = mLruProcesses.indexOf(app); if (lrui >= 0) mLruProcesses.remove(lrui); int i = mLruProcesses.size-1; int skipTop = 0; app.lruSeq = mLruSeq; // compute the new weight for this process. if (updateActivityTime) {app.lastActivityTime = SystemClock.uptimeMillis(); } if (app.activities.size() >0) {// If this process has activities, we more strongly want to keep// it around.app.lruWeight = app.lastActivityTime; } else if (app.pubProviders.size() >0) {// If this process contains content providers, we want to keep// it a little more strongly.app.lruWeight = app.lastActivityTime - ProcessList.CONTENT_APP_IDLE_OFFSET;// Also don't let it kick out the first few real hidden processes.skipTop = ProcessList.MIN_HIDDEN_APPS; } else {// If this process doesn't have activities, we less strongly// want to keep it around, and generally want to avoid getting// in front of any very recently used activities.app.lruWeight = app.lastActivityTime - ProcessList.EMPTY_APP_IDLE_OFFSET;// Also don't let it kick out the first few real hidden processes.skipTop = ProcessList.MIN_HIDDEN_APPS; } while (i >= 0) {ProcessRecord p = mLruProcesses.get(i);// If this app shouldn't be in front of the first N background// apps, then skip over that many that are currently hidden.if (skipTop >0 && p.setAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) { skipTop--;}if (p.lruWeight <= app.lruWeight || i < bestPos) { mLruProcesses.add(i+1, app);//添加到mLruProcesses合适的位置 break;}i--; } if (i < 0) {mLruProcesses.add(0, app); } // 如果这个进程之后总有cotent provider或者Service,重新计算 // If the app is currently using a content provider or service, // bump those processes as well. if (app.connections.size() >0) {for (ConnectionRecord cr : app.connections) { if (cr.binding != null && cr.binding.service != null&& cr.binding.service.app != null&& cr.binding.service.app.lruSeq != mLruSeq) { updateLruProcessInternalLocked(cr.binding.service.app, oomAdj,updateActivityTime, i+1); }} } if (app.conProviders.size() >0) {for (ContentProviderRecord cpr : app.conProviders.keySet()) { if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq) { updateLruProcessInternalLocked(cpr.proc, oomAdj, updateActivityTime, i+1); }} } if (oomAdj) {updateOomAdjLocked();调用updateOomAdjLocked 更新oom adj值 } } 这个函数主要作用 1.为该进程计算LRU序列号和LRU weight 2.根据计算出来的LRU weight,将该进程信息插入到mLRUProcesses合适的位置之中 3.如果该进程之中有content provider或者service,重新计算LRU weight 4.判断是否需要调用updateOomAdjLocked函数来更新oom adj的值 到此为止updateLruProcessLocked结束,可以看出,这个函数只是调整进程的LRU weight和在mLruProcesses中的位置,并没有直接参与进程的管理,真正参与进程管理的是updateOomAdjLocked函数,这个函数用来更新oom adj的值,这个值影响着进程的回收 2 OOM adjOOM adj 定义了一系列的OOM的调整级别,从-17到15。在Low Memory Killer机制中已经介绍过,这里看一下Android中定义了13个调整级别,在ProcessList文件中 class ProcessList { // OOM adjustments for processes in various states: // This is a process without anything currently running in it. Definitely // the first to go! Value set in system/rootdir/init.rc on startup. // This value is initalized in the constructor, careful when refering to // this static variable externally. static final int EMPTY_APP_ADJ = 15; // This is a process only hosting activities that are not visible, // so it can be killed without any disruption. Value set in // system/rootdir/init.rc on startup. static final int HIDDEN_APP_MAX_ADJ = 15; static int HIDDEN_APP_MIN_ADJ = 7; // This is a process holding the home application -- we want to try // avoiding killing it, even if it would normally be in the background, // because the user interacts with it so much. static final int HOME_APP_ADJ = 6; // This is a process holding a secondary server -- killing it will not // have much of an impact as far as the user is concerned. Value set in // system/rootdir/init.rc on startup. static final int SECONDARY_SERVER_ADJ = 5; // This is a process currently hosting a backup operation. Killing it // is not entirely fatal but is generally a bad idea. static final int BACKUP_APP_ADJ = 4; // This is a process with a heavy-weight application. It is in the // background, but we want to try to avoid killing it. Value set in // system/rootdir/init.rc on startup. static final int HEAVY_WEIGHT_APP_ADJ = 3; // This is a process only hosting components that are perceptible to the // user, and we really want to avoid killing them, but they are not // immediately visible. An example is background music playback. Value set in // system/rootdir/init.rc on startup. static final int PERCEPTIBLE_APP_ADJ = 2; // This is a process only hosting activities that are visible to the // user, so we'd prefer they don't disappear. Value set in // system/rootdir/init.rc on startup. static final int VISIBLE_APP_ADJ = 1; // This is the process running the current foreground app. We'd really // rather not kill it! Value set in system/rootdir/init.rc on startup. static final int FOREGROUND_APP_ADJ = 0; // This is a process running a core server, such as telephony. Definitely // don't want to kill it, but doing so is not completely fatal. static final int CORE_SERVER_ADJ = -12; // The system process runs at the default adjustment. static final int SYSTEM_ADJ = -16; .....} AMS提供了函数来改变这个值:updateOomAdjLocked final void updateOomAdjLocked() { final ActivityRecord TOP_ACT = resumedAppLocked(); final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null; if (false) {RuntimeException e = new RuntimeException();e.fillInStackTrace();Slog.i(TAG, updateOomAdj: top= + TOP_ACT, e); } mAdjSeq++; // Let's determine how many processes we have running vs. // how many slots we have for background processes; we may want // to put multiple processes in a slot of there are enough of // them. int numSlots = ProcessList.HIDDEN_APP_MAX_ADJ - ProcessList.HIDDEN_APP_MIN_ADJ + 1; int factor = (mLruProcesses.size()-4)/numSlots; if (factor < 1) factor = 1; int step = 0; int numHidden = 0; // First update the OOM adjustment for each of the // application processes based on their current state. int i = mLruProcesses.size(); int curHiddenAdj = ProcessList.HIDDEN_APP_MIN_ADJ; int numBg = 0; while (i >0) {i--;ProcessRecord app = mLruProcesses.get(i);//Slog.i(TAG, OOM + app + : cur hidden= + curHiddenAdj); //调用重载函数updateOomAdjLocked,更新OOM adj的值updateOomAdjLocked(app, curHiddenAdj, TOP_APP);if (curHiddenAdj < ProcessList.EMPTY_APP_ADJ && app.curAdj == curHiddenAdj) { step++; if (step >= factor) { step = 0; curHiddenAdj++; }}if (!app.killedBackground) { // 如果adj的值大于等于ProcessList.HIDDEN_APP_MIN_ADJ if (app.curAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) { numHidden++; if (numHidden >mProcessLimit) {Slog.i(TAG, No longer want + app.processName + (pid + app.pid + ): hidden # + numHidden);EventLog.writeEvent(EventLogTags.AM_KILL, app.pid, app.processName, app.setAdj, too many background);app.killedBackground = true;Process.killProcessQuiet(app.pid);//杀死进程 } else {numBg++; } } else if (app.curAdj >= ProcessList.HOME_APP_ADJ) { numBg++; }} } ...... } 其中调用了重载函数updateOomAdjLocked,具体代码如下: private final boolean updateOomAdjLocked(ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) { app.hiddenAdj = hiddenAdj; if (app.thread == null) {return false; } final boolean wasKeeping = app.keeping; boolean success = true; // 1调用computeOomAdjLocked方法计算oom adj的值 computeOomAdjLocked(app, hiddenAdj, TOP_APP, false); if (app.curRawAdj != app.setRawAdj) {if (false) { // Removing for now. Forcing GCs is not so useful anymore // with Dalvik, and the new memory level hint facility is // better for what we need to do these days. if (app.curRawAdj >ProcessList.FOREGROUND_APP_ADJ&& app.setRawAdj <= ProcessList.FOREGROUND_APP_ADJ) { // If this app is transitioning from foreground to // non-foreground, have it do a gc. scheduleAppGcLocked(app); } else if (app.curRawAdj >= ProcessList.HIDDEN_APP_MIN_ADJ&& app.setRawAdj < ProcessList.HIDDEN_APP_MIN_ADJ) { // Likewise do a gc when an app is moving in to the // background (such as a service stopping). scheduleAppGcLocked(app); }}if (wasKeeping && !app.keeping) { // This app is no longer something we want to keep. Note // its current wake lock time to later know to kill it if // it is not behaving well. BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics(); synchronized (stats) { app.lastWakeTime = stats.getProcessWakeTime(app.info.uid, app.pid, SystemClock.elapsedRealtime()); } app.lastCpuTime = app.curCpuTime;}app.setRawAdj = app.curRawAdj; } if (app.curAdj != app.setAdj) {// 2 调用setOomAdj来修改进程的oom adj的值 if (Process.setOomAdj(app.pid, app.curAdj)) { if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v( TAG, Set app + app.processName + oom adj to + app.curAdj + because + app.adjType); app.setAdj = app.curAdj;} else { success = false; Slog.w(TAG, Failed setting oom adj of + app + to + app.curAdj);} } if (app.setSchedGroup != app.curSchedGroup) {app.setSchedGroup = app.curSchedGroup;if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG, Setting process group of + app.processName + to + app.curSchedGroup);if (app.waitingToKill != null && app.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) { Slog.i(TAG, Killing + app.toShortString() + : + app.waitingToKill); EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,app.processName, app.setAdj, app.waitingToKill); // 3 调用killProcessQuiet杀死进程 Process.killProcessQuiet(app.pid); success = false;} else { if (true) { long ldId = Binder.clearCallingIdentity(); try { // 4调用setProcessGroup修改进程的调度组 Process.setProcessGroup(app.pid, app.curSchedGroup); } catch (Exception e) {Slog.w(TAG, Failed setting process group of + app.pid + to + app.curSchedGroup);e.printStackTrace(); } finally {Binder.restoreCallingIdentity(oldId); } } else { if (app.thread != null) {try { app.thread.setSchedulingGroup(app.curSchedGroup);} catch (RemoteException e) {} } }} } return success; } 函数updateOomAdjLocked,更新OOM adj的值,这一部分的主要工作有: 1.调用computeOomAdjLocked方法计算oom adj的值,这个函数比较复杂,通过一系列的运算,计算出oom adj的值 2.调用setOomAdj来修改进程的oom adj的值,这个函数就是向进程的/proc/ /oom_adj文件写入计算出来的oom adj值 3.调用killProcessQuiet杀死进程 4.调用setProcessGroup修改进程的调度组 这里主要看第三步killProcessQuiet,这个函数在Process.java文件中: public static final void killProcessQuiet(int pid) { sendSignalQuiet(pid, SIGNAL_KILL); }调用了 sendSignalQuiet函数,这是一个native函数: public static final native void sendSignalQuiet(int pid, int signal);对应的实现在android_util_Process.cpp文件中: void android_os_Process_sendSignalQuiet(JNIEnv* env, jobject clazz, jint pid, jint sig){ if (pid >0) { kill(pid, sig);//杀死进程 }}到此为止进程杀死了,这种方式是直接杀死进程的方式,同样android还提供了一个被动杀死进程的机制 Low Memory Killer机制 3 Low Memory Killer机制 这一机制的主要思想就是定义不同的oom adj级别,并为每一个级别指定最小剩余阈值, 当内存中可用内存小于该阈值时,就杀死所有等于或者大于该级别的进程,这部分参看 Low Memory Killer机制 public class MySQLiteHelper extends SQLiteOpenHelper {public static final String SQL_CREATE= “create table news (” + “_id integer primary key autoincrement, ” + “nametext, ” + “agetext, )”; public MySQLiteHelper(Context context, String name, CursorFactory factory, int version) { super(context, name, factory, version);} @Overridepublic void onCreate(SQLiteDatabase db) { db.execSQL(SQL_CREATE); } @Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {} } 当我们如上创建了个SQLiteHelper,我们知道会在本地的目录database中生成了个.db数据库文件! 可是我们遇到版本迭代往往要做更多的事情 这时候的会再创建个新的数据库 这时候我们编译完成之后发现没有在database相对应的目录下生成一个相对应的表, Android中数据库升级篇3:Android中进程管理
篇4:Android中数据库升级
@Override“ int=”int“ name=”code“ newversion=”newVersion)“ oldversion=”oldVersion,“ oncreatedb=”onCreate(db);“ onupgradesqlitedatabase=”onUpgrade(SQLiteDatabase“ pre=”pre“ public=”public“ void=”void“>主要思路就是更新version,就是说你用户现有装的app上version是1的时候,在迭代版本更新的时候要更新version为>1的值 这样我们在new MySQLiteHelper() 的时候就会执行onUpgrade()方法,然后在在该方法中写入相对应的操作就会在database下生产相对应的表而不需要用户去清除应用的数据。
当然这种方法有一个很严重的弊端就是 可能我们在发布版本的时候忘记修改该version导致无法操作数据引起一系列不可收拾的bug。 所以推荐使用LitePal开源库进行对数据库操作!详情可见 点击打开链接
篇5:Android中各种drawable的使用
其实这些个drawable的使用并不难,也不需要去哪里百度或者Google找答案,直接自己试验一下即可,
如:ic-launcher图标具体大小是多少,如有的人把一张512 x 512的图片当成ic-launcher,在高分辨率手机上没有问题,但是在一些低分辨率手机上发现桌面上找不到自己应用的图标,或者显示名称但看不到图标,想找ic-launcher标准大小吗?创建一个Android项目不就有了吗?看系统生成的那些ic-launcher在各种drawable上的大小即可,这就是最标准的了,何需百度,出图标的时候就让美工按着那些图标大小出就不会有问题了。
又如,通知栏图标要多大呢?如果大小不合适,则显示通知的时候看到的图标可能显示不全或者其它问题,要想知道通知栏图标多大合适,找Android系统设计的那些呀,路径为:sdkplatformsandroid-15data es,在这里搜索notification,然后看看相同名字的通知栏图标在不同的drawable中的大小是多少,这样你就知道你应该让美工给你切多大的通知栏图标了^_^
接下来了解本质的东西,下面的内容都是我拿真实手机测试出来的结果,所以应该比百度出来的那些更有真实性。
一般手机的分辨率对应的各参数为:
drawable-ldpi 文件夹: 低密度屏幕:dpi = 120dp,scale = ??, 超级元老,不用管它,不会再有这种dpi的手机的啦!drawable-mdpi 文件夹: 中等密度屏 幕:dpi = 160dp,scale = 1.0,分辨率:320 x 480drawable-hdpi 文件夹: 高密度屏幕:dpi = 240dp,scale = 1.5,分辨率:480 x 854drawable-xhdpi 文件夹: 超高密度屏幕:dpi = 320dp,scale = 2.0,分辨率:720 x 1280drawable-xxhdpi文件夹: 超超高密度屏幕:dpi = 480dp,scale= 3.0,分辨率:1080 x 1920scale 为缩放系数,标准的dpi是160dpi,所以160dpi的scale为1.0,其它dpi的缩放系数都是与160相比算出来的,如320dpi,它除以160dpi结果为2,所以320dpi的scale为2.0
好,有了这个scale之后呢创建图片就简单了,怎么个简单法?先找出160dpi对应的大小就OK了,
如,美工设计了一张很美的图片,而且是以720 x 1080的分辨率为基础进行设计,假如宽高都为300像素,则这张图放在720 x1280的手机上显示肯定是完美的,如果放到其它分辨就有可能会被压缩或者放大,那效果就会大打折扣,所以我们大家都知道要切多套图片放到不同的drawable目录中,那问题来了,美工如果她不懂,她问你,其它分辨率怎么切图?
怎么切呢?我们就先算出160dpi对应的大小就行了,它切的图是以720 x 1080的手机为基础设计的,这个分辨率对应的是xhdpi,scale是2.0,所以160dpi对应的大小就是:300 / 2.0 = 150像素,那这样的话4种drawable的图片怎么切就有答案了:
160dpi 的图片大小为150像素,那其它的就按scale去算就好了,如下:drawable-hdpi: 150* 1.5 = 225drawable-xhdpi: 150 *2.0 = 300drawable-xxhdpi: 150 *3.0 = 450就目前情况来说,切图切4套就够了。
假如,有一张图片,你并不知道它是在哪个分辨率的基础上进行设计的,那你就不知道这张图片应该放在哪个drawable文件夹中,这种情况经常会遇到,比如我们学习Android时的那些图片,根本不知道是谁设计的,也不知道是在哪个分辨率的基础上设计的,那你怎么知道放在哪个drawable文件夹中比较合适呢?一般人会选择放在drawable-hdpi 文件夹中,或许吧,多人这么做肯定是这样做一般没什么问题,但是,同一张图片,注:只有一张图片哦,把它放到不同的drawable文件夹中,然后在同一台手机上的显示效果会不一样哦,为什么会这样呢?嗯,夜已深,我先睡觉,有时间再来写完它。。。
篇6:Android中的Theme和Style
1.首先,Theme属性详解:
android:theme=”@android:style/Theme.Dialog“ //Activity显示为对话框模式
android:theme=”@android:style/Theme.NoTitleBar“ //不显示应用程序标题栏
android:theme=”@android:style/Theme.NoTitleBar.Fullscreen“ //不显示应用程序标题栏,并全屏
android:theme=”Theme.Light “ //背景为白色
android:theme=”Theme.Light.NoTitleBar“ //白色背景并无标题栏
android:theme=”Theme.Light.NoTitleBar.Fullscreen“ //白色背景,无标题栏,全屏
android:theme=”Theme.Black“ //背景黑色
android:theme=”Theme.Black.NoTitleBar“ //黑色背景并无标题栏
android:theme=”Theme.Black.NoTitleBar.Fullscreen“ //黑色背景,无标题栏,全屏
android:theme=”Theme.Wallpaper“ //用系统桌面为应用程序背景
android:theme=”Theme.Wallpaper.NoTitleBar“ //用系统桌面为应用程序背景,且无标题栏
android:theme=”Theme.Wallpaper.NoTitleBar.Fullscreen“ //用系统桌面为应用程序背景,无标题栏,全屏
android:theme=”Theme.Translucent“ //透明背景
android:theme=”Theme.Translucent.NoTitleBar“ //透明背景并无标题
android:theme=”Theme.Translucent.NoTitleBar.Fullscreen“ //透明背景并无标题,全屏
android:theme=”Theme.Panel “ //面板风格显示
android:theme=”Theme.Light.Panel“ //平板风格显示
2.其次,Theme和Style区别:
前者主要用于Application和Activity,后者主要用于View,
Android中的Theme和Style
,
篇7:Android中RemoteViews的实现
本文结合AppWidget的应用场景,分析Android中RemoteViews的内部具体实现,
从前文《Android中AppWidget的分析与应用:AppWidgetProvider》和《Android中Launcher对于AppWidget的处理的分析:AppWidgetHost角色》中得知,Android中AppWidget的图形资源是由AppWidgetProvider通过RemoteViews提供的;而显示是由AppWidgetHost通过AppWidgetHostView把RemoteView提供的内容显示在本地View上的。AppWidgetProvider和AppWidgetHostView运行在不同的程序中,而它们沟通的图形元素和点击回馈的桥梁就是RemoteViews。
下面为了行文方便和一致,把RemoteViews的内容提供方AppWidgetProvoder称作Remote端;而显示RemoteViews内容的一方AppWidgetHost称作Local端。
一、给RemoteViews提供内容——SettingsAppWidgetProvider
下图是SettingsAppWidgetProvider(位于Settings中的com.android.settings.widget包中)作为AppWidgetProvider得到update通知之后,创建RemoteViews,并把Remote端的响应Intent以及图形元素放进RemoteViews中的顺序图。
图一、为RemoteViews提供内容和侦听
图中,
1. Settings创建RemoteViews时,把packageName和layoutId传进去并保存起来。packageName相当重要,因为这里的layoutId和各种其他资源都是相对这个程序来说的,只有通过packageName获得相应的Context,才能进而获得资源,否则其他程序是无法获得这些资源的[Seq#1]。
2. Settings把layoutId中的viewId指示的View被点击之后获得响应的PendingIntent设置到RemoteViews中[Seq#2~ #5]。
RemoteViews创建SetOnClickPendingIntent并把id和intent传入,SetOnClickPendingIntent保存这些值;
SetOnClickPendingIntent是RemoteViews.Action的子类,通过addAction把SetOnClickPendingIntent加入到mActions:ArrayList
3. Settings把layoutId中的viewId指示的View的ImageSourceID设置到RemoteViews中[Seq#6~ #10]。
RemoteViews中有很多setXYZ()的方法,用来根据不同的要设置值的类型来设置;
setXYZ()创建ReflectionAction并把viewId和value,以及“setImageResource”作为methodName传入,ReflectionAction保存这些值;
ReflectionAction是RemoteViews.Action的子类,通过addAction()把ReflectionAction加入到mActions:ArrayList
这里描述的是一个子过程,后续会通过AppWidgetManager把这个创建好的RemoteViews放进AppWidget系统中,从而使得AppWidget的AppWidgetHost端更新显示RemoteViews里承载的内容,
Remote端设置内容的过程,只是设置这些参数,而RemoteViews也只是用不同的RemoteViews.Action保存了这些参数。下文描述内部结构。
注意:这里的参数都是在Remote端的,在RemoteContext有效。
二、RemoteViews的内部结构
下图是RemoteViews相关的类图。
图二、RemoteViews类图
RemoteViews中保存Remote端的mPackage和mLayoutId;并用mActions:ArrayList
mPackage和mLayoutId是在构造RemoteViews时传进去的[上文图中的seq#1];
mActions是设置各种Remote端的响应Intent以及图形元素的时候,保存到相应的Action中,然后把Action加入到这里保存的;
mLayoutId里的各种控件通过setTextViewText()/ setImageViewResource() / setProgressBar(),等函数在remote端设置的。这些方法再调用setType() [Type可为Boolean / Byte / Short / Int/ Long / Char / String / Uri / Bitmap/ Bundle, etc]保存到ReflectionAction中。
SetOnClickPendingIntent是用来在local端用户点击viewId时,发出pendingIntent通知的。在SetOnClickPendingIntent的构造方法中保存viewId和pendingIntent。
ReflectionAction用来在local端显示时,通过Reflect机制执行获得Remote端资源的。在ReflectionAction的构造方法中保存viewId,methodName,type以及value。
ViewGroupAction和SetDrawableParameters也是RemoteViews.Action的子类,在这个场景中并未用到,基本原理相似,读者可自行分析。
三、显示RemoteViews内容——AppWidgetHostView
图一中为RemoteViews提供了内容之后,AppWidgetHost会通过IAppWidgetHost.updateAppWidget()被通知到Remote端有更新,本地端把RemoteViews提供的内容显示在AppWidgetHostView上。下面的顺序图描述这一过程。
图三、本地显示RemoteViews里的内容
图中:
1. 获取RemoteViews里Remote端(AppWidgetProvider)的packageName和layoutId,通过packageName创建远端的context——remoteContext。[Seq#1~ 6]
2. 通过RemoteViews的apply()方法,真正开始执行侦听Click操作的动作;通过远端Layout获得本地使用的View。[Seq#7~ 20]
2.1. 克隆一个本地的LayoutInflater;[Seq#8]
2.2. 用克隆出的LayoutInflater对remote端的layoutId执行Inflate,获得Layout所描述的View的Hierarchy,亦即后面用到的rootView;[Seq#9~ 10]
2.3. 对2.2中获得的view执行performApply。[Seq#11~ 19]
performApply()对所有mActions中的Action都执行apply()操作。这样,
篇8:如何删除android中的一些程序
此操作有可能会对系统产生影响,建议先进行备份后再操作,
前提条件:
1、操作系统建议为Windows XP、32位Windows Vista、32位Windows 7
2、USB数据线、Desire电量高于30%、电脑系统能正确识别Desire
3、Android SDK(2.1版本下载 / 2.2版本下载)
4、良好的心理素质以及动手能力
5、已取得root权限
6、rooting文件包(立即下载)
具体操作方法如下:
1、手机连接USB线后,用音量键”下“+电源键开机,出现红色叹号后,运行rooting包的recovery-windows.bat进入绿色recovery界面(不要关闭cmd窗口)
2、另开一个cmd窗口,进入rooting文件所在目录,装载/system目录
操作代码:
adb-windows shell mount /system
3、显示系统已安装的程序
操作代码:
adb-windows shell ls /system/app/
显示结果如下:
AccountAndSyncSettings.apk
ApplicationsProvider.apk
Bluetooth.apk
...........
HtcStreamPlayer.apk
htcsettingwidgets.apk
HtcSyncwidget.apk
HtcTwitter.apk
...........
4、有两种移除程序的方式:彻底删除或者移到SD卡上
A、彻底删除,
举例,操作代码:
adb-windows shell rm /system/app/Stock.apk
adb-windows shell rm /system/app/com.htc.StockWidget.apk
B、移到SD卡的某个目录下。
举例,操作代码:
adb-windows shell mkdir /sdcard/device_files (注释:这行代码是创建文件夹)
adb-windows mv /system/app/Stock.apk /sdcard/device-files
adb-windows mv /system/app/com.htc.StockWidget.apk /sdcard/device-files
5、至此,删除”无用\"app工作结束。重启手机。
篇9:策略模式在android中使用
策略模式(Strategy)
策略模式是对象的行为模式,它的用意是针对一组算法,将每一个算法封装到具有共同接口的独立类中,从而使得它们可以相互替换。策略模式使得算法可以在不修改或影响到调用端的情况下发生变化。
下面来讨论下策略模式的结构类图,具体如下:
从上面的结构图中,我们可以看出策略模式涉及到了三个角色,具体角色如下所示:
A、抽象策略角色:这是个抽象角色,通常是由一个接口或是抽象类来实现。它为所有的具体策略类提供了需要的接口。
B、具体策略角色:这个角色包装了相关的算法和行为,用来执行对应的策略事件。
C、环境角色:这个角色中含有一个对抽象策略类的引用,也是供外部调用直接接触的角色。
下面具体举个例子来使用策略模式。例子是这样的:现在要做一个上网使用得app,接入的网络类型有三种,分别为CMCC、ChinaNet及普通的Wifi类型,所以针对这几种类型的网络,我们需要定义一个抽象的策略角色,然后再定义三个具体角色,每个具体的角色中实现具体的功能细节,最后,我们在前端放置三个按钮,点击对应的按钮调用对应的具体角色逻辑(通过调用抽象角色)。下面为我的代码逻辑实现以及部分说明文字:
抽象策略角色(WifiConnectStrategy):
/**
* 抽象策略角色
*/
public abstract classWifiConnectStrategyimplementsCallback{
privateWifiConnectStrategyListener listener =null;
protectedWifiState wifiState =null;
protectedHandler handler =null;
protected static final longCONN_WIFI_TIME= 2000; // 连接wifi的时间(模拟)
publicWifiConnectStrategy() {
handler =newHandler(WifiConnectStrategy.this);
}
public voidsetWifiConnectStrategyListener(WifiConnectStrategyListener listener) {
this.listener = listener;
}
/**
* 创建一个策略,根据wifitype
*/
public staticWifiConnectStrategycreateWithWifiType(WifiType wifiType) {
WifiConnectStrategy result =null;
switch(wifiType) {
caseCMCC:
result =newCMCCWifiConnectStrategy();
break;
caseCHINANET:
result =newChinaNetWifiConnectStrategy();
break;
caseCOMMON:
result =newCommonWifiConnectStrategy();
break;
default:
break;
}
returnresult;
}
public voidconfigWifiState(WifiState wifiState) {
this.wifiState = wifiState;
}
/**
* 连接到网络的方法
*/
public abstract voidexecuteConnectNetRun();
/**
* 模拟链接后返回的结果
*/
public abstract voidconnectResult();
// 模拟网络链接延迟
protected voidsimulateConnect() {
this.handler.removeMessages(1);
this.handler.sendEmptyMessageDelayed(1,CONN_WIFI_TIME);
}
@Override
public booleanhandleMessage(Message msg) {
connectResult();
return true;
}
publicWifiConnectStrategyListener getListener() {
returnlistener;
}
public voidsetListener(WifiConnectStrategyListener listener) {
this.listener = listener;
}
public voidlog(String log) {
Log.d(WifiConnectStrategy, log);
}
}
具体策略角色(CMCC):
/**
* 具体策略角色
*/
public classCMCCWifiConnectStrategyextendsWifiConnectStrategy {
publicCMCCWifiConnectStrategy() {
super();
}
@Override
public voidexecuteConnectNetRun() {
log(cmcc connect ...);
// 链接网络核心代码(异步)
//TODO
// 模拟网络链接延迟
simulateConnect();
}
@Override
public voidconnectResult(){
getListener().cmccConnResult(this.wifiState.getWifiLabel() +连接成功!);
}
}
具体策略角色(ChinaNet):
public classChinaNetWifiConnectStrategyextendsWifiConnectStrategy {
publicChinaNetWifiConnectStrategy() {
super();
}
@Override
public voidexecuteConnectNetRun() {
log(chinanet connect ...);
// 链接网络核心代码
//TODO
// 模拟网络链接延迟
simulateConnect();
}
@Override
public voidconnectResult(){
getListener().cmccConnResult(this.wifiState.getWifiLabel() +连接成功!);
}
}
具体策略角色(Common wifi):
public classCommonWifiConnectStrategyextendsWifiConnectStrategy {
publicCommonWifiConnectStrategy() {
super();
}
@Override
public voidexecuteConnectNetRun(){
log(common connect ...);
// 链接网络核心代码
//TODO
// 模拟网络链接延迟
simulateConnect();
}
@Override
public voidconnectResult(){
getListener().cmccConnResult(this.wifiState.getWifiLabel() +连接成功!);
}
}
下面为我们具体的环境角色,主要就是引用一个抽象策略角色,以及根据不同网络类型创建对应的具体策略角色,具体如下:
public classMainActivityextendsActivityimplementsOnClickListener {
privateButton btnCmcc =null;
privateButton btnChinanet =null;
privateButton btnCommon =null;
privateWifiConnectStrategy wifiConnectStrategy;
privateWifiState selectedState =newWifiState();
privateWifiConnectStrategyListener listener =newWifiConnectStrategyListener() {
@Override
public voidcmccConnResult(String state) {
log(state);
}
@Override
public voidchinanetConnResult(Stringstate) {
log(state);
}
@Override
public voidcommonConnResult(String state) {
log(state);
}
};
@Override
protected voidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnCmcc = (Button) findViewById(R.id.btnCmcc);
btnChinanet = (Button) findViewById(R.id.btnChinanet);
btnCommon = (Button) findViewById(R.id.btnCommon);
btnCmcc.setOnClickListener(this);
btnChinanet.setOnClickListener(this);
btnCommon.setOnClickListener(this);
}
@Override
public voidonClick(View v) {
if(null!= wifiConnectStrategy) {
wifiConnectStrategy =null;
}
if(v.getId() == R.id.btnCmcc) {
selectedState.setCardNo(cmcc+1167278922);
selectedState.setIpAddress(192168013);
selectedState.setPassword(123456);
selectedState.setWifiLabel(CMCC);
selectedState.setSsid(dafadfdadada);
selectedState.setWifiType(WifiType.CMCC);
wifiConnSpecial(selectedState);
}
else if(v.getId() == R.id.btnChinanet) {
selectedState.setCardNo(cmcc+1167272222);
selectedState.setIpAddress(192168433);
selectedState.setPassword(123456777);
selectedState.setWifiLabel(ChinaNet);
selectedState.setSsid(dafadeeeedada);
selectedState.setWifiType(WifiType.CHINANET);
wifiConnSpecial(selectedState);
}
else{
selectedState.setIpAddress(192168111);
selectedState.setPassword(123456789);
selectedState.setWifiLabel(COMMON);
selectedState.setSsid(dafadeeeSSDASF);
selectedState.setWifiType(WifiType.COMMON);
wifiConnCommon(selectedState);
}
}
private voidwifiConnSpecial(WifiState wifiState) {
wifiConnectStrategy = WifiConnectStrategy.createWithWifiType(selectedState.getWifiType());
wifiConnectStrategy.configWifiState(wifiState);
wifiConnectStrategy.setWifiConnectStrategyListener(listener);
wifiConnectStrategy.executeConnectNetRun();
}
private voidwifiConnCommon(WifiState wifiState) {
wifiConnectStrategy = WifiConnectStrategy.createWithWifiType(selectedState.getWifiType());
wifiConnectStrategy.configWifiState(wifiState);
wifiConnectStrategy.setWifiConnectStrategyListener(listener);
wifiConnectStrategy.executeConnectNetRun();
}
private voidlog(String log) {
Log.d(WifiConnectStrategy,log);
}
}
注意:这里的WifiState类为wifi的封装类,WifiConnectStrategyListener为监听网络链接的接口,
接下来,我会在下面罗列出他们的代码构成。
WifiState:
public classWifiState {
//wifiname
privateString wifiLabel;
//wifi ip
private intipAddress;
//wifi ssid
privateString ssid;
//wifipassword
privateString password;
// card no
privateString cardNo;
// 类型
privateWifiType wifiType;
//wifi类型
public enumWifiType {
CMCC(1),
CHINANET(2),
COMMON(3);
private final inttype;
privateWifiType(inttype) {
this.type = type;
}
public intgetType() {
returntype;
}
public staticWifiTypegetType(intwifiType) {
WifiTypetype =null;
if(WifiType.CMCC.getType() == wifiType) {
type = WifiType.CMCC;
}
else if(WifiType.CHINANET.getType() == wifiType) {
type = WifiType.CHINANET;
}
else if(WifiType.COMMON.getType() == wifiType) {
type = WifiType.COMMON;
}
returntype;
}
}
public intgetIpAddress() {
returnipAddress;
}
public voidsetIpAddress(intipAddress) {
this.ipAddress = ipAddress;
}
publicString getSsid() {
returnssid;
}
public voidsetSsid(String ssid) {
this.ssid = ssid;
}
publicString getPassword() {
returnpassword;
}
public voidsetPassword(String password) {
this.password = password;
}
publicString getCardNo() {
returncardNo;
}
public voidsetCardNo(StringcardNo) {
this.cardNo = cardNo;
}
publicString getWifiLabel() {
returnwifiLabel;
}
public voidsetWifiLabel(String wifiLabel) {
this.wifiLabel = wifiLabel;
}
publicWifiType getWifiType() {
returnwifiType;
}
public voidsetWifiType(WifiType wifiType) {
this.wifiType = wifiType;
}
}
WifiConnectStrategyListener:
/**
*wifi链接的监听
*/
public interfaceWifiConnectStrategyListener {
public voidcmccConnResult(String state);
public voidchinanetConnResult(String state);
public voidcommonConnResult(String state);
}
好了,运行下代码,页面效果如下:
当我们点击对应的按钮链接网络时,会在输出日志打印对应的wifi链接以及链接成功,当然,这是只是模拟实现,实际上整个过程没这么简单,比如需要先获得卡号,然后异步链接,获得返回的信息,链接是否成功等。
日志如下:
好了,到这里,策略模式的介绍就完成了,稍后会把项目代码上传,希望对大家有帮助。
- Android 面试题经典(上)2022-12-11
- 管理你的Android电池使用2023-06-18
- 单位与单位之间的感谢信2024-01-12
- 恋人之间的说说2023-11-06
- 同事之间的感谢信2024-04-27
- 心念之间心情随笔2024-05-04
- 半梦半醒之间的散文2023-08-15
- 动静之间散文2024-06-05
- 贷款人之间协议书2025-01-21
- 爱情之间的句子2022-12-14