博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Activity启动模式联想到多进程相关的一些东西
阅读量:7103 次
发布时间:2019-06-28

本文共 5159 字,大约阅读时间需要 17 分钟。

看到这个题目估计又有人说我标题党了,启动模式跟多进程有什么关系,没啥关系,我只是在写Activity启动模式的demo的时候,用到了多进程进行测试,顺便一起交代一下。


Task与Process

不知道有没有人想当然的混淆上述两个概念,我是见过有这样想的开发者。

Task

Task就是一堆Activity的集合,你可以这样想,一个栈中,有多个Activity,当用户在多个activity之间跳转时,执行压栈操作,当用户按返回键时,执行出栈操作。 在做测试之前,我们需要先介绍一下Task相关的代码。 在Activity中,直接调用getTaskId()可以获取当前Activity所在的Task_id。 我们也可以调用系统方法,获取Task的相关信息:

public static void getTask(Context context){        ActivityManager  mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);        List
list = mAm.getAppTasks(); for (AppTask appTask:list){ Log.e("Utils",context.getClass().getName()+" "+appTask.getTaskInfo().affiliatedTaskId+"的num = "+appTask.getTaskInfo().numActivities); } }复制代码

standard

我们设置四个Activity,每个Activity的启动模式都设置成standard。来看一下Task的相关情况。

上图是用上面介绍的代码完成的一个demo,从第一个Actvity切换到第四个Activity,每增加一个ActivityTask都会增加一个Activity,如果按返回键,即销毁一个Activity,根据上图所知,ActivityTask会减少一个。如果不断的startActivity则ActivityTask数量不断增加。

singleTask

我们设置四个Activity,每个Activity的启动模式都设置成singleTask。来看一下Task的相关情况。

由上图可知,如果一个activity的启动模式为singleTask,那么Task栈中将会只有一个该Activity的实例。所以从第一个activity,跳到第四个Activity,再跳回第一个的时候,只是将第一个Activity启动了,同时调用了第一个Activity的onNewIntent 这里还有一个有趣的事,注意观察上图,再回到第一个Activity的时候,Task中Activity的数量变为了1,也就是singleTask除了启动了第一个Activity,并将第一个Activity顺序之上的activity全部销毁了。

singleTop

我们设置四个Activity,每个Activity的启动模式都设置成singleTop。来看一下Task的相关情况。

根据上图可知,你可能感觉这个跟standard模式没什么区别啊,的确是这样的,如果被启动的Activity不处于栈顶,那么跟standard没有什么区别,当要启动的Activity处于栈顶,不会再次创建这个Activity的实例,而是重用原来的实例,并且调用原来实例的onNewIntent()方法。

singleInstance

我们设置四个Activity,每个Activity的启动模式都设置成singleInstance。来看一下Task的相关情况。

由上图可知,这次的变化是很明显的。每次启动Activity都会重新创建一个Task,并且这个Task中只有这一个实例。也就是说被该实例启动的其他activity会自动运行于另一个任务中。当再次启动该activity的实例时,会重用已存在的任务和实例。并且会调用这个实例的onNewIntent()方法。

Process

现在聊一下与进程相关的东西

taskAffinity属性

首先先说的是taskAffinity,为什么在Process标题下聊taskAffinity,因为进程间我们可以看到的taskAffinity属性,更明显的特性。 接着需要引出的概念就是taskAffinity,taskAffinity表示当前activity具有亲和力的一个Task,可以这样理解, taskAffinity表示一个Task的名字,这个Task就是当前activity所在的Task。一个Task的taskAffinity取决于跟Activity的taskAffinity。 如果一个Activity没有显式的指明该 Activity的taskAffinity,那么它的这个属性就等于Application指明的taskAffinity,如果 Application也没有指明,那么该taskAffinity的值就等于包名。 现在来示范一个例子(所有的例子,都有demo,在文章的最后),新建两个应用,app,app2,每个应用都有MainActivity,和SecondActivity,从MainActivity可以跳到SecondActivity,为了方便描述,我们appMain,appSecond,app2Main,app2Second来代替。 我们将appSecond和app2Second设置成同样的taskAffinity:

复制代码

启动这两个Activity,发现没有什么特殊效果,appSecond都在各自应用的应用根Activity的Task中。 这时我们改一下代码将appSecond设置成singleTask,这样appSecond所在的Task就是带有taskAffinity属性的了。 然后这时我们再启动app2Second:

由图可知,app2Second仍然在app2Main的Task中,这是由于app2Second的启动模式是标准,没有自主选择task的能力,我们再将app2Second改成singleTask:
然后使用
adb shell dumpsys activity activities查看一下activity的堆栈信息:
#733 与#734标识的为Task,与上面app截图不同是由于,我又运行了一次,所以Task id增加了,但是Activity与Task的归属关系是一样的。 所以我们发现app2Second所在的task跟appSecond所在的task一样了,这说明app2Second可以根据taskAffinity选择Task了,而且这个Task还可以不是当前Process。

多进程

关于多进程,可以共用Task的例子,也可以这样证明:

复制代码

在一个app中启用多进程,但所有的Activity都是标准模式,可以发现,所有的Activity都在同一个Task中。

全局变量的访问

Activity都可以设置进程的归属关系,但是如果不是Activity,而是一个全局变量呢?可以试一下,我们建立一个全局变量:

public class StaticParam {    public static String a = "default";    public static Object o = new Object();}复制代码

首先在Application中初始化:

@Override    public void onCreate() {        super.onCreate();        StaticParam.a ="init";        Log.e("xxxxxx","application:"+Utils.getCurProcessName(this)+ "    "+StaticParam.a.getClass().toString());    }复制代码

然后在上面例子中的四个Activity中的onCreate添加如下代码:

StaticParam.a = StaticParam.a+ " "+getClass().getSimpleName();Log.e("xxxxxx","a="+StaticParam.a+"      "+StaticParam.o+"    "+Utils.getCurProcessName(this));复制代码

执行一遍所有的activity,看一下效果:

12-27 10:56:32.993 31195-31195/umeng.com.testlauncher E/xxxxxx: application:umeng.com.testlauncher    class java.lang.String12-27 10:56:33.053 31195-31195/umeng.com.testlauncher E/xxxxxx: a=init MainActivity      java.lang.Object@76794cc    umeng.com.testlauncher12-27 10:56:40.000 31325-31325/? E/xxxxxx: application:com.deep1    class java.lang.String12-27 10:56:40.057 31325-31325/? E/xxxxxx: a=init SecondActivity      java.lang.Object@76794cc    com.deep112-27 10:56:49.618 31486-31486/com.deep2 E/xxxxxx: application:com.deep2    class java.lang.String12-27 10:56:49.674 31486-31486/com.deep2 E/xxxxxx: a=init ThirdActivity      java.lang.Object@76794cc    com.deep212-27 10:56:51.202 31195-31195/umeng.com.testlauncher E/xxxxxx: a=init MainActivity FourthActivity      java.lang.Object@76794cc    umeng.com.testlauncher复制代码

根据log,我们发现几个问题:

  • 当从MainActivity跳到SecondActivity的时候,由于SecondActivity属于进程com.deep1,所以会在com.deep1 进程中再次执行Application的初始化。
  • MainActivity已经将StaticParam.a置成了a=init MainActivity但是SecondActivity添加了自己的名字却是a=init SecondActivity,等到与MainActivity同进程的FourthActivity的时候,又变回a=init MainActivity FourthActivity,这说明全局静态变量在各个进程间是不通用的,每个进程各自维护各自的,互不干扰。

总结

demo地址:https://github.com/mymdeep/activityTest 暂时就想到了这些,写的有点乱,想到哪写到哪,如有问题,欢迎进一步讨论 也欢迎关注我的公众号,之后会推荐更多好用的组件库。

转载地址:http://mrkhl.baihongyu.com/

你可能感兴趣的文章
前端那些事之react--redux篇
查看>>
Ubuntu 16.04 U盘安装过程
查看>>
UIApplication、AppDelegate、委托
查看>>
hadoop单机安装
查看>>
Android实用笔记——使用GridView以表格的形式显示多张图片
查看>>
内部类使用外部类的成员属性
查看>>
基于const的重载
查看>>
虹软AI 人脸识别SDK接入 — 性能优化篇(多线程)
查看>>
Spark examples 源码解析 (Spark SQL)
查看>>
无线路由器软件开发面试-曙光
查看>>
mac os x 查看网络端口情况
查看>>
编写shell脚本处理test文件
查看>>
搭建网络ghost服务器
查看>>
MySQL集群搭建步骤详解
查看>>
什么是活动目录
查看>>
spark install
查看>>
Postgres Hooks
查看>>
如何写好一篇技术博客?
查看>>
SQLserver将一张表a的数据插入另一张表b
查看>>
HTTP状态码详解
查看>>