下面小编给大家带来Android中的Theme和Style(共含10篇),希望能帮助到大家!同时,但愿您也能像本文投稿人“YxE”一样,积极向本站投稿分享好文章。
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
,
(1)布局文件
(2)在values中新建xml文件
(3)如果要修改Android默认的主题需要在清单文件中修改,下图圈出的位置就是需要修改的地方
(4)其他问阿金都可以默认无需修改!
一、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中数据库升级 @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开源库进行对数据库操作!详情可见 点击打开链接
其实这些个drawable的使用并不难,也不需要去哪里百度或者Google找答案,直接自己试验一下即可, 如:ic-launcher图标具体大小是多少,如有的人把一张512 x 512的图片当成ic-launcher,在高分辨率手机上没有问题,但是在一些低分辨率手机上发现桌面上找不到自己应用的图标,或者显示名称但看不到图标,想找ic-launcher标准大小吗?创建一个Android项目不就有了吗?看系统生成的那些ic-launcher在各种drawable上的大小即可,这就是最标准的了,何需百度,出图标的时候就让美工按着那些图标大小出就不会有问题了。 又如,通知栏图标要多大呢?如果大小不合适,则显示通知的时候看到的图标可能显示不全或者其它问题,要想知道通知栏图标多大合适,找Android系统设计的那些呀,路径为:sdkplatformsandroid-15data es,在这里搜索notification,然后看看相同名字的通知栏图标在不同的drawable中的大小是多少,这样你就知道你应该让美工给你切多大的通知栏图标了^_^ 接下来了解本质的东西,下面的内容都是我拿真实手机测试出来的结果,所以应该比百度出来的那些更有真实性。 一般手机的分辨率对应的各参数为: scale 为缩放系数,标准的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的图片怎么切就有答案了: 就目前情况来说,切图切4套就够了。 假如,有一张图片,你并不知道它是在哪个分辨率的基础上进行设计的,那你就不知道这张图片应该放在哪个drawable文件夹中,这种情况经常会遇到,比如我们学习Android时的那些图片,根本不知道是谁设计的,也不知道是在哪个分辨率的基础上设计的,那你怎么知道放在哪个drawable文件夹中比较合适呢?一般人会选择放在drawable-hdpi 文件夹中,或许吧,多人这么做肯定是这样做一般没什么问题,但是,同一张图片,注:只有一张图片哦,把它放到不同的drawable文件夹中,然后在同一台手机上的显示效果会不一样哦,为什么会这样呢?嗯,夜已深,我先睡觉,有时间再来写完它。。。 本文结合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()操作。这样, 此操作有可能会对系统产生影响,建议先进行备份后再操作, 前提条件: 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工作结束。重启手机。 策略模式(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= ; // 连接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链接以及链接成功,当然,这是只是模拟实现,实际上整个过程没这么简单,比如需要先获得卡号,然后异步链接,获得返回的信息,链接是否成功等。 日志如下: 好了,到这里,策略模式的介绍就完成了,稍后会把项目代码上传,希望对大家有帮助。 最近在项目中需要将读取的数据按照时间的降序进行排序, 具体的步骤如下: 1.读取数据,存入List中 2.取出数据中的时间戳,由String转换成Date 3.使用冒泡排序对List中元素按照Date进行排序 具体代码如下: //将List按照时间倒序排列 @SuppressLint(SimpleDateFormat) private List篇4:Android中进程管理
篇5:Android中数据库升级
篇6:Android中各种drawable的使用
篇7:Android中RemoteViews的实现
篇8:如何删除android中的一些程序
篇9:策略模式在android中使用
篇10:Android中对日期进行排序