核心内容摘要
蓝桥杯研究生组Java题解:从数位倍数到原料采购的8题实战复盘
4.
3 Activity登堂入室分类Android 基础入门教程
ActivityWindow与View的关系好吧本来就想了解下他们几个的关系然后手多多然后就开始看起他们的调用过程来了...结果扣了两个小时只理解了很小很小的一部分果然到底层撸源码的都是大神比如老罗还没到那个等级下面是自己查阅资料看了下一点源码的归纳所得如果哪写错了欢迎指出下面贴下小结图流程解析Activity调用startActivity后最后会调用attach方法然后在PolicyManager实现一个Ipolicy接口接着实现一个Policy对象接着调用makenewwindow(Context)方法该方法会返回一个PhoneWindow对象而PhoneWindow 是Window的子类在这个PhoneWindow中有一个DecorView的内部类是所有应用窗口的根View即View的老大 直接控制Activity是否显示(引用老司机原话..)好吧接着里面有一个LinearLayout里面又有两个FrameLayout他们分别拿来装ActionBar和CustomView而我们setContentView()加载的布局就放到这个CustomView中
总结下这三者的关系打个牵强的比喻 我们可以把这三个类分别堪称画家画布画笔画出的东西 画家通过画笔(LayoutInflater.infalte)画出图案再绘制在画布(addView)上 最后显示出来(setContentView)
ActivityTask和Back Stack的一些概念接着我们来了解Android中Activity的管理机制这就涉及到了两个名词Task和Back Stack了概念解析我们的APP一般都是由多个Activity构成的而在Android中给我们提供了一个Task(任务)的概念 就是将多个相关的Activity收集起来然后进行Activity的跳转与返回当然这个Task只是一个 frameworker层的概念而在Android中实现了Task的数据结构就是Back Stack回退堆栈 相信大家对于栈这种数据结构并不陌生Java中也有个Stack的集合类栈具有如下特点后进先出(LIFO)常用操作入栈(push)出栈(pop)处于最顶部的叫栈顶最底部叫栈底而Android中的Stack Stack也具有上述特点他是这样来管理Activity的当切换到新的Activity那么该Activity会被压入栈中成为栈顶 而当用户点击Back键栈顶的Activity出栈紧随其后的Activity来到栈顶我们来看下官方文档给出的一个流程图流程解析应用程序中存在A1,A2,A3三个activity当用户在Launcher或Home Screen点击应用程序图标时 启动主A1接着A1开启A2A2开启A3这时栈中有三个Activity并且这三个Activity默认在 同一个任务Task中当用户按返回时弹出A3栈中只剩A1和A2再按返回键 弹出A2栈中只剩A1再继续按返回键弹出A1任务被移除即程序退出接着在官方文档中又看到了另外两个图处于好奇我又看了下解释然后跟群里的人讨论了下然后还有这段解释然后
总结下了结论Task是Activity的集合是一个概念实际使用的Back Stack来存储Activity可以有多个Task但是 同一时刻只有一个栈在最前面其他的都在后台那栈是如何产生的呢答当我们通过主屏幕点击图标打开一个新的App此时会创建一个新的Task举个例子我们通过点击通信录APP的图标打开APP这个时候会新建一个栈1然后开始把新产生的Activity添加进来可能我们在通讯录的APP中打开了短信APP的页面但是此时不会新建一个栈而是继续添加到栈1中这是 Android推崇一种用户体验方式即不同应用程序之间的切换能使用户感觉就像是同一个应用程序 很连贯的用户体验官方称其为seamless (无缝衔接 ——————这个时候假如我们点击Home键回到主屏幕此时栈1进入后台我们可能有下述两种操作1点击菜单键(正方形那个按钮)点击打开刚刚的程序然后栈1又回到前台了 又或者我们点击主屏幕上通信录的图标打开APP此时也不会创建新的栈栈1回到前台2如果此时我们点击另一个图标打开一个新的APP那么此时则会创建一个新的栈2栈2就会到前台 而栈1继续呆在后台
后面也是这样...以此类推
Task的管理1文档翻译好的继续走文档从文档中的ManagingTasks开始大概的翻译如下1文档翻译继续走文档从文档中的ManagingTasks开始翻译如下如上面所述Android会将新成功启动的Activity添加到同一个Task中并且按照以先进先出方式管理多个Task 和Back Stack用户就无需去担心Activites如何与Task任务进行交互又或者它们是如何存在于Back Stack中 或许你想改变这种正常的管理方式。
比如你希望你的某个Activity能够在一个新的Task中进行管理 或者你只想对某个Activity进行实例化又或者你想在用户离开任务时清理Task中除了根Activity所有Activities。
你可以做这些事或者更多只需要通过修改AndroidManifest.xml中 activity 的相关属性值或者在代码中通过传递特殊标识的Intent给startActivity( )就可以轻松的实现 对Actvitiy的管理了。
activity 中我们可以使用的属性如下taskAffinitylaunchModeallowTaskReparentingclearTaskOnLaunchalwaysRetainTaskStatefinishOnTaskLaunch你能用的主要的Intent标志有FLAG_ACTIVITY_NEW_TASKFLAG_ACTIVITY_CLEAR_TOPFLAG_ACTIVITY_SINGLE_TOP好的接下来逐个介绍这些怎么用2taskAffinity和allowTaskReparenting默认情况下一个应用程序中的所有activity都有一个Affinity这让它们属于同一个Task。
你可以理解为是否处于同一个Task的标志然而每个Activity可以通过 activity中的taskAffinity属性设置单独的Affinity。
不同应用程序中的Activity可以共享同一个Affinity同一个应用程序中的不同Activity 也可以设置成不同的Affinity。
Affinity属性在2种情况下起作用1当启动 activity的Intent对象包含FLAG_ACTIVITY_NEW_TASK标记 当传递给startActivity()的Intent对象包含 FLAG_ACTIVITY_NEW_TASK标记时系统会为需要启动的Activity寻找与当前Activity不同Task。
如果要启动的 Activity的Affinity属性与当前所有的Task的Affinity属性都不相同系统会新建一个带那个Affinity属性的Task并将要启动的Activity压到新建的Task栈中否则将Activity压入那个Affinity属性相同的栈中。
2allowTaskReparenting属性设置为true 如果一个activity的allowTaskReparenting属性为true 那么它可以从一个TaskTask1移到另外一个有相同Affinity的TaskTask2中Task2带到前台时。
如果一个.apk文件从用户角度来看包含了多个应用程序你可能需要对那些 Activity赋不同的Affinity值。
3launchMode四个可选值启动模式我们研究的核心下面再详细讲! 他们分别是standard(默认)singleTopsingleTasksingleInstance4清空栈当用户长时间离开Task当前task被转移到后台时系统会清除task中栈底Activity外的所有Activity 。
这样当用户返回到Task时只留下那个task最初始的Activity了。
我们可以通过修改下面这些属性来 改变这种行为alwaysRetainTaskState 如果栈底Activity的这个属性被设置为true上述的情况就不会发生。
Task中的所有activity将被长时间保存。
clearTaskOnLaunch如果栈底activity的这个属性被设置为true一旦用户离开Task 则 Task栈中的Activity将被清空到只剩下栈底activity。
这种情况刚好与 alwaysRetainTaskState相反。
即使用户只是短暂地离开task也会返回到初始状态 只剩下栈底acitivty。
finishOnTaskLaunch与clearTaskOnLaunch相似但它只对单独的activity操 作而不是整个Task。
它可以结束任何Activity包括栈底的Activity。
当它设置为true时当前的Activity只在当前会话期间作为Task的一部分存在 当用户退出Activity再返回时它将不存在。
Activity的四种加载模式详解接下来我们来详细地讲解下四种加载模式 他们分别是standard(默认)singleTopsingleTasksingleInstance在泡在网上的日子看到一篇图文并茂的讲解启动模式的很赞可能更容易理解吧这里借鉴下原文链接Activity启动模式图文详解standard, singleTop, singleTask 以及 singleInstance英文原文Understand Android Activitys launchMode: standard, singleTop, singleTask and singleInstance 另外还有一篇详细讲解加载模式的Android中Activity四种启动模式和taskAffinity属性详解先来看看
总结图模式详解standard模式标准启动模式也是activity的默认启动模式。
在这种模式下启动的activity可以被多次实例化即在同一个任务中可以存在多个activity的实例每个实例都会处理一个Intent对象。
如果Activity A的启动模式为standard并且A已经启动在A中再次启动Activity A即调用startActivitynew IntentthisA.class会在A的上面再次启动一个A的实例即当前的桟中的状态为A--A。
singleTop模式如果一个以singleTop模式启动的Activity的实例已经存在于任务栈的栈顶 那么再启动这个Activity时不会创建新的实例而是重用位于栈顶的那个实例 并且会调用该实例的onNewIntent()方法将Intent对象传递到这个实例中。
举例来说如果A的启动模式为singleTop并且A的一个实例已经存在于栈顶中 那么再调用startActivitynew IntentthisA.class启动A时 不会再次创建A的实例而是重用原来的实例并且调用原来实例的onNewIntent()方法。
这时任务栈中还是这有一个A的实例。
如果以singleTop模式启动的activity的一个实例 已经存在与任务栈中但是不在栈顶那么它的行为和standard模式相同也会创建多个实例。
singleTask模式只允许在系统中有一个Activity实例。
如果系统中已经有了一个实例 持有这个实例的任务将移动到顶部同时intent将被通过onNewIntent()发送。
如果没有则会创建一个新的Activity并置放在合适的任务中。
官方文档中提到的一个问题系统会创建一个新的任务并将这个Activity实例化为新任务的根部root 这个则需要我们对taskAffinity进行设置了使用taskAffinity后的解雇singleInstance模式保证系统无论从哪个Task启动Activity都只会创建一个Activity实例,并将它加入新的Task栈顶 也就是说被该实例启动的其他activity会自动运行于另一个Task中。
当再次启动该activity的实例时会重用已存在的任务和实例。
并且会调用这个实例 的onNewIntent()方法将Intent实例传递到该实例中。
和singleTask相同 同一时刻在系统中只会存在一个这样的Activity实例。
Activity拾遗对于Activity可能有些东西还没讲到这里预留一个位置漏掉的都会在这里补上 首先是群友珠海-坤的建议把开源中国的Activity管理类也贴上嗯这就贴上大家可以直接用到 项目中~1开源中国客户端Activity管理类package net.oschina.app; import java.util.Stack; import android.app.Activity; import android.app.ActivityManager; import android.content.Context; public class AppManager { private static StackActivity activityStack; private static AppManager instance; private AppManager(){} /** * 单一实例 */ public static AppManager getAppManager(){ if(instancenull){ instancenew AppManager(); } return instance; } /** * 添加Activity到堆栈 */ public void addActivity(Activity activity){ if(activityStacknull){ activityStacknew StackActivity(); } activityStack.add(activity); } /** * 获取当前Activity堆栈中最后一个压入的 */ public Activity currentActivity(){ Activity activityactivityStack.lastElement(); return activity; } /** * 结束当前Activity堆栈中最后一个压入的 */ public void finishActivity(){ Activity activityactivityStack.lastElement(); finishActivity(activity); } /** * 结束指定的Activity */ public void finishActivity(Activity activity){ if(activity!null){ activityStack.remove(activity); activity.finish(); activitynull; } } /** * 结束指定类名的Activity */ public void finishActivity(Class? cls){ for (Activity activity : activityStack) { if(activity.getClass().equals(cls) ){ finishActivity(activity); } } } /** * 结束所有Activity */ public void finishAllActivity(){ for (int i 0, size activityStack.size(); i size; i){ if (null ! activityStack.get(i)){ activityStack.get(i).finish(); } } activityStack.clear(); } /** * 退出应用程序 */ public void AppExit(Context context) { try { finishAllActivity(); ActivityManager activityMgr (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); activityMgr.restartPackage(context.getPackageName()); System.exit(
; } catch (Exception e) { } } }本节小结好的本节就到这里东西都比较苦涩难懂暂时知道下即可
总结下Task进行整体调度的 相关操作吧按Home键将之前的Task切换到后台长按Home键会显示出最近执行过的Task列表在Launcher或HomeScreen点击app图标开启一个新Task或者是将已有的Task调度到前台启动singleTask模式的Activity时会在系统中搜寻是否已经存在一个合适的Task若存在则会将这个Task调度到前台以重用这个Task。
如果这个Task中已经存在一个要启动的Activity的实例则清除这个实例之上的所有Activity将这个实例显示给用户。
如果这个已存在的Task中不存在一个要启动的Activity的实例则在这个Task的顶端启动一个实例。
若这个Task不存在则会启动一个新的Task在这个新的Task中启动这个singleTask模式的Activity的一个实例。
启动singleInstance的Activity时会在系统中搜寻是否已经存在一个这个Activity的实例如果存在会将这个实例所在的Task调度到前台重用这个Activity的实例该Task中只有这一个Activity如果不存在会开启一个新任务并在这个新Task中启动这个singleInstance模式的Activity的一个实例。
好的本节就到这里关于Task与Activity加载模式的东西还是比较复杂的下面给大家贴下编写该文的 时候的一些参考文献可以自己看看~