开启多进程
首先我们写一个Activity并启动一个service
package com.example.infatuated;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent MyServiceIntent = new Intent(this, MyService.class);
this.startService(MyServiceIntent);
}
}
service的代码:
package com.example.infatuated;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;
public class MyService extends Service {
private static final String TAG = "qmsggg";
@Override
public void onCreate() {
Log.i(TAG, "MyService is oncreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "MyProcessActivity is created: ");
return START_STICKY;
}
@Override
public void onDestroy() {
Log.i(TAG, "ODestroy");
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
最后我们只需要在AndroidManifest.xml中的配置 android:process就可以了
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".MyService" android:label="@string/app_name" android:process=":test"/>
</application>
需要特别说明的是,android:process=":test" 中的test名字是自定义的,而冒号":"的含义是当前进程名前附加上当前的包名。那么刚刚所创建出的Service的完整进程名就为com.example.infatuated:test.
当然你也可以自己设置完整地进程名,如android:process="com.example.double:test"这便是一种完整地命名方式。
而更重要的是两种命名方式的区别在于:
- ":"开头的,则这个新的进程,对于这个应用来说是私有的,当它被需要或者这个服务需要在新进程中运行- 时,这个新进程就会被创建。
- 如果这个进程的名字是以小写字符开头的,则这个服务将在一个以该名字命名的全局的进程中运行。当然前提是,它要有相应的权限,这将允许它在不同应用中的各个组件可以共享一个进程。从而减少资源的占用。
接下来我们测试验证一下:
public class MyApplication extends Application {
private static final String TAG = "MyApplication";
@Override
public void onCreate() {
super.onCreate();
int pid = android.os.Process.myPid();
Log.i(TAG, "MyApplication is oncreate===="+"pid="+pid);
}
}
日志结果如下:
多进程log1.png可以看到MyApplication的OnCreate方法执行了两次。
分别是在com.example.infatuated和com.example.infatuated:test 两个进程之中各执行了一次。
所以这就衍生出了一个问题,很多开发者都习惯在Application的子类里面去做相应的初始化和数据化存储操作,如果我们开启多个进程让Application的子类各个回调方法都执行多次,这显然是有问题的。
所以,我们应该区分进程,如果是应用进程,则做应用的相关操作,如果是其他进程(在这里是一个服务),就做其他的操作
package com.example.infatuated;
import android.app.ActivityManager;
import android.app.Application;
import android.util.Log;
public class MyApplication extends Application {
private static final String TAG = "MyApplication";
@Override
public void onCreate() {
super.onCreate();
int pid = android.os.Process.myPid();
Log.i(TAG, "MyApplication is onCreate===="+"pid="+pid);
String processnameString = "";
ActivityManager manager =(ActivityManager)this.getSystemService(getApplicationContext().ACTIVITY_SERVICE);
for (ActivityManager.RunningAppProcessInfo appProcessInfo : manager.getRunningAppProcesses()) {
if (appProcessInfo.pid == pid) {
processnameString = appProcessInfo.processName;
Log.i(TAG, "processName=" + processnameString);
}
}
if ("com.example.infatuated:test".equals(processnameString)) {
Log.i(TAG, "processName = " + processnameString);
}
}
多进程log2.png
- 虚拟机上分配了不同的地址空间,修改静态成员只会在自己的进程中有效,同样单例模式也只有在自己的进程中是单例,多个进程就不能称之为单例了,因为很可能多个进程都会存在这个所谓的单例。
- 于此同时因为SharedPreferences并不支持并发的读写缘故,在多个进程的使用过程中,就可能存在并发的情况,这样SharedPreferences的读写就会变得不可靠。
总结:
- 所以最后我们可以回答一开始提出的问题,一个应用程序能否开启多个进程,答案是:可以的
- 然而还有一点需要说明的是,因为多个进程首先会拥有多个Application,数据会被初始化多次,其次进程之间的通信又比较麻烦,再者每一个进程都有其单独的虚拟机,多个进程自然也会消耗较多的内存。
网友评论