Android多进程总结一:生成多进程(android:process属性)

Android多进程总结⼀:⽣成多进程(android:process属
性)
前⾔
正常情况下,⼀个apk启动后只会运⾏在⼀个进程中,其进程名为apk的包名,所有的组件都会在这个进程中运⾏,以下为DDMS的进程截屏:
com.biyou.multiprocess为进程名,也是apk的包名,
但是如果需要将某些组件(如Service,Activity等)运⾏在单独的进程中,就需要⽤到android:process属性了。我们可以给android的组件设置android:process属性来使其运⾏在指定的进程中。
设置该属性可以使每个组件均在各⾃的进程中运⾏,或者使⼀些组件共享⼀个进程
(默认值为包名)
为何要使⽤多进程
1.分散内存的占⽤
我们知道Android系统对每个应⽤进程的内存占⽤是有限制的,⽽且占⽤内存越⼤的进程,通常被系统杀死的可能性越⼤。让⼀个组件运⾏在单独的进程中,可以减少主进程所占⽤的内存,避免OOM问题,降低被系统杀死的概率,
2.实现多模块
⽐如我做的应⽤⼤⽽全,⾥⾯肯定会有很多模块,假如有地图模块、⼤图浏览、⾃定义WebView等等(这些都是吃内存⼤户),还会有⼀些诸如下载服务,监控服务等等,⼀个成熟的应⽤⼀定是多模块化的。
当我们的应⽤开发越来越⼤,模块越来越多,团队规模也越来越⼤,协作开发也是个很⿇烦的事情。项⽬解耦,模块化,是这阶段的⽬标。通过模块解耦,开辟新的进程,独⽴的JVM,来达到数据解耦⽬的。模块之间互不⼲预,团队并⾏开发,责任分⼯也明确。
3.⼦进程奔溃,主进程可以继续⼯作
如果⼦进程因为某种原因崩溃了,不会直接导致主程序的崩溃,可以降低我们程序的崩溃率。
4.主进程退出,⼦进程可以继续⼯作
即使主进程退出了,我们的⼦进程仍然可以继续⼯作,假设⼦进程是推送服务,在主进程退出的情况下,仍然能够保证⽤户可以收到推送消息。
5.实现守护进程
如果主线程中的服务要从开机起持续运⾏,若由于内存等原因被系统kill掉,守护进程可以重新启动主线程的服务。
通过JNI利⽤C/C++,调⽤fork()⽅法来⽣成⼦进程,⼀般开发者会利⽤这种⽅法来做⼀些daemon(守护进程)进程,来实现防杀保活等效果。
另外:
还能通过监控进程,将这个错误上报给系统,告知他在什么机型、环境下、产⽣了什么样的Bug,提升⽤户体验。
实现
1 . 如果android:process的值以冒号开头的话,那么该进程就是私有进程,如下:
配置:
<application
……
<service android:name=".ProcessTestService" android:process=":secondProcess"/>
……
</application>
进程:
2 . 以⼩写字母开头(如com.secondProcess),那么就是公有进程,android:process值⼀定要有个点号:
不能以数字开头,并且要符合命名规范,必须要有.否则将会出现这种错误: Invalid process name simon in package
com.wind.check: must have at least one ‘.’
配置:
磁石电话机
<application
……
<service android:name=".LocalService" android:process="com.secondProcess"/>
……
</application>
进程:
3 . 私有进程和公有进程的区别:
android:process=":remote",以冒号开头,冒号后⾯的字符串原则上是可以随意指定的。如果我们的包名
为“com.biyou.multiprocess”,则实际的进程名
为“com.biyou.multiprocess:remote”。这种设置形式表⽰该进程为当前应⽤的私有进程,其他应⽤的组件不可以和它跑在同⼀个进程中。
全局进程
进程名称不以“:”开头的进程都可以叫全局进程,如android:process="com.secondProcess",以⼩写字母开头,表⽰运⾏在⼀个以这个名字命名的全局进程中,其他应⽤通过设置相同的ShareUID可以和它跑在同⼀个进程。
ps:ShareUID :
ShareUserId,在Android⾥⾯每个app都有⼀个唯⼀的linux user ID,则这样权限就被设置成该应⽤程序的⽂件只对该⽤户可见,只对该应⽤程序⾃⾝可见,⽽我们可以使他们对其他的应⽤程序可见,这会使我们⽤到SharedUserId,也就是让两个apk使⽤相同的userID,这样它们就可以看到对⽅的⽂件。为了节省资源,具有相同ID的apk也可以在相同的linux进程中进⾏(注意,并不是⼀定要在⼀个进
程⾥⾯运⾏),共享⼀个虚拟机。
ShareUserId的作⽤,数据共享、调⽤其他程序资源。
进程⽣命周期与优先级
Android 系统将尽量长时间地保持应⽤进程,但为了新建进程或运⾏更重要的进程,最终需要移除旧进程来回收内存。 为了确定保留或终⽌哪些进程,系统会根据进程中正在运⾏的组件以及这些组件的状态,将每个进程放⼊“重要性层次结构”中。 必要时,系统会⾸先消除重要性最低的进程,然后是重要性略逊的进程,依此类推,以回收系统资源。
重要性层次结构⼀共有 5 级。以下列表按照重要程度列出了各类进程(第⼀个进程最重要,将是最后⼀个被终⽌的进程):
1.前台进程:(foreground process)
⽤户当前操作所必需的进程。如果⼀个进程满⾜以下任⼀条件,即视为前台进程:
托管⽤户正在交互的 Activity(已调⽤ Activity 的 onResume() ⽅法)
托管某个 Service,后者绑定到⽤户正在交互的 Activity
托管正在“前台”运⾏的 Service(服务已调⽤ startForeground())
托管正执⾏⼀个⽣命周期回调的 Service(onCreate()、onStart() 或 onDestroy())
液冷散热器托管正执⾏其 onReceive() ⽅法的 BroadcastReceiver
通常,在任意给定时间前台进程都为数不多。只有在内存不⾜以⽀持它们同时继续运⾏这⼀万不得已的情况下,系统才会终⽌它们。 此时,设备往往已达到内存分页状态,因此需要终⽌⼀些前台进程来确保⽤户界⾯正常响应。
2.可见进程
没有任何前台组件、但仍会影响⽤户在屏幕上所见内容的进程。 如果⼀个进程满⾜以下任⼀条件,即视为可见进程:铅板加工
托管不在前台、但仍对⽤户可见的 Activity(已调⽤其 onPause() ⽅法)。例如,如果前台 Activity 启动了⼀个对话框,允许在其后显⽰上⼀ Activity,则有可能会发⽣这种情况。
托管绑定到可见(或前台)Activity 的 Service。
可见进程被视为是极其重要的进程,除⾮为了维持所有前台进程同时运⾏⽽必须终⽌,否则系统不会终⽌这些进程。
3.服务进程
正在运⾏已使⽤ startService() ⽅法启动的服务且不属于上述两个更⾼类别进程的进程。尽管服务进程与⽤户所见内容没有直接关联,但是它们通常在执⾏⼀些⽤户关⼼的操作(例如,在后台播放⾳乐或从⽹络下载数据)。因此,除⾮内存不⾜以维持所有前台进程和可见进程同时运⾏,否则系统会让服务进程保持运⾏状态。
4.后台进程
包含⽬前对⽤户不可见的 Activity 的进程(已调⽤ Activity 的 onStop() ⽅法)。这些进程对⽤户体验没有直接影响,系统可能随时终⽌它们,以回收内存供前台进程、可见进程或服务进程使⽤。 通常会有很多后台进程在运⾏,因此它们会保存在 LRU (最近最少使⽤)列表中,以确保包含⽤户最近查看的 Activity 的进程最后⼀个被终⽌。如果某个 Activity 正确实现了⽣命周期⽅法,并保存了其当前状态,则终⽌其进程不会对⽤户体验产⽣明显影响,因为当⽤户导航回该 Activity 时,Activity 会恢复其所有可见状态。 有关保存和恢复状态的信息,请参阅 Activity⽂档。
5.空进程
不含任何活动应⽤组件的进程。保留这种进程的的唯⼀⽬的是⽤作缓存,以缩短下次在其中运⾏组件所需的启动时间。 为使总体系统资源在进程缓存和底层内核缓存之间保持平衡,系统往往会终⽌这些进程。
根据进程中当前活动组件的重要程度,Android 会将进程评定为它可能达到的最⾼级别。例如,如果某进程托管着服务和可见 Activity,则会将此进程评定为可见进程,⽽不是服务进程。
此外,⼀个进程的级别可能会因其他进程对它的依赖⽽有所提⾼,即服务于另⼀进程的进程其级别永远不会低于其所服务的进程。 例如,如果进程 A 中的内容提供程序为进程 B 中的客户端提供服务,或者如果进程 A 中的服务绑定到进程 B 中的组件,则进程 A 始终被视为⾄少与进程 B 同样重要。
由于运⾏服务的进程其级别⾼于托管后台 Activity 的进程,因此启动长时间运⾏操作的 Activity 最好为该操作启动服务,⽽不是简单地创建⼯作线程,当操作有可能⽐ Activity 更加持久时尤要如此。例如,正在将图⽚上传到⽹站的 Activity 应该启动服务来执⾏上传,这样⼀来,即使⽤户退出 Activity,仍可在后台继续执⾏上传操作。使⽤服务可以保证,⽆论 Activity 发⽣什么情况,该操作⾄少具备“服务进程”优先级。 同理,⼴播接收器也应使⽤服务,⽽不是简单地将耗时冗长的操作放⼊线程中。
注意的地⽅
有⼀点⼀定要记住:进程间的内存空间是不可见的。从⽽,开启多进程后,我们需要⾯临这样⼏个问题:
1. Application的多次重建。
Manifest⽂件如上⾯提到的,定义了两个类:ProcessTestActivity和ProcessTestService,我们只是在Activity的onCreate⽅法中直接启动了该Service,同时,我们⾃定义了⾃⼰的Application类。代码如下:
public class MyApplication extends Application {
public static final String TAG = "viclee";
@Override
public void onCreate() {
int pid = android.Pid();
usb flashLog.d(TAG, "MyApplication onCreate");
Log.d(TAG, "MyApplication pid is " + pid);
}
}
public class ProcessTestActivity extends Activity {
public final static String TAG = "viclee";
@Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_process_test);
Log.i(TAG, "ProcessTestActivity onCreate");
this.startService(new Intent(this, ProcessTestService.class));
}
}
public class ProcessTestService extends Service {
public static final String TAG = "viclee";
@Override
public void onCreate() {
Log.i(TAG, "ProcessTestService onCreate");
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}
}
  我们发现MyApplication的onCreate⽅法调⽤了两次,分别是在启动ProcessTestActivity和ProcessTestService的时候,⽽且我们发现打印出来的pid也不相同。由于通常会在Application的onCreate⽅法中做⼀些全局的初始化操作,它被初始化多次是完全没有必要的。出现这种情况,是由于即使是通过指定process属性启动新进程的情况下,系统也会新建⼀个独⽴的虚拟机,⾃然需要重新初始化⼀遍Application。那么怎么来解决这个问题呢?
下⾯给出解决⽅案:
思路:判断是否为主进程,只有主进程的时候才执⾏下⾯的操作
String processName = ProcessName();
//判断进程名,保证只有主进程运⾏
if (!TextUtils.isEmpty(processName) &&processName.PackageName())) {
//在这⾥进⾏主进程初始化逻辑操作
Log.i(">>>>>>","oncreate");
}
获取进程名的⽅法,这个⽅法是效率最好的:
public static String getProcessName() {
try {
File file = new File("/proc/" + android.Pid() + "/" + "cmdline");
BufferedReader mBufferedReader = new BufferedReader(new FileReader(file));
String processName = adLine().trim();
艾灸仪mBufferedReader.close();
return processName;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
2. 静态成员的失效。
将之前定义的Activity和Service的代码进⾏简单的修改,代码如下:eoo

本文发布于:2024-09-22 14:28:36,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/2/277044.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:进程   服务   系统   前台   可见   操作   组件
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议