为什么不将初始化工作放在Application中?
之前在使用其他服务的sdk时,经常需要对其进行全局的初始化,在我的想法中,既然是全局的初始化肯定应该放到 Application的onCreate中,但大部分都SDK要求将初始化操作放到应用第一个activity中。开始不太理解这样的做法。直到有一次意外地发现Application竟然被多次的创建,他的onCreate方法被多次执行,因此其初始化操作也被多次执行。细想之下,突然恍然大悟
因为在应用中使用了多进程,而每一个进程都代表一个独立的虚拟机,每一个虚拟机又代表独立的内存空间,所以需要多次创建应用的上下文。可能你会想,添加一个变量来标识应用是否初始化,防止应用进行多次初始化。他们在不同的内存空间,不同的进程,不同的线程,便是添加类变量,也是不起作用的。
其实,控制初始化最简单的方式莫过于判断当前代码所处的进程名。这里就会用到安卓进程名的生成规则。
Android进程名生成规则
Android中,默认一个APK包就对应一个进程,其进程名就为AndroidManifest.xml文件中 指定的package名。可以通过Activity, Service, BroadCastReceiver, ContentProvider的android:process属性来实现单APK多进程。
- 如果android:process的value不是”:”开头,则系统里有同样名字的进程的话,会放到已存在的同名进程里运行,这样能减小消耗。
eg:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.daniel.test"
android:versionCode="1"
android:versionName="1.0" >
...
<service android:name=".Service" android:process="com.daniel.service">
</service>
会产生两个进程
进程1: com.daniel.test
进程2: com.daniel.service
- 如果android:process的value是以”:”开头,则启动一个名字为value的进程。
eg:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.daniel.test"
android:versionCode="1"
android:versionName="1.0" >
...
<service android:name=".Service" android:process=":service">
</service>
会产生两个进程
进程1: com.daniel.test
进程2: com.daniel.test.service
获取当前进程名
String getCurProcessName(Context context) {
int pid = android.os.Process.myPid();
ActivityManager mActivityManager = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningAppProcessInfo appProcess : mActivityManager
.getRunningAppProcesses()) {
if (appProcess.pid == pid) {
return appProcess.processName;
}
}
return null;
}
为什么要注意多进程Application初始化
多次初始化代表着多分的资源占用,而大部分都是不必要的。而大部分应用都使用了多进程,许多SDK同样如此,比如百度云推送。所以,保持良好的初始化习惯是非常必要的。