1.多进程的应用场景
在Android开发中,大多数应用的所有组件都会在同一个进程中,但是比如播放音乐,或者需要进程常驻后台,又或者是一个大型应用里有地图模块、自定义WebView模块、大图浏览模块等等的应用场景,就需要多进程来让我们的应用更高效。
2.开启多进程
首先声明一个Service
public class MyService extends Service {
private static final String TAG = "MyService";
@Override
public void onCreate() {
Log.e(TAG, "myService onCreate");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "myService onStartCommand");
return START_STICKY;
}
@Override
public void onDestroy() {
Log.e(TAG, "myService onDestroy");
super.onDestroy();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
然后在清单文件中配置Service
<service
android:name=".MyService"
android:label="@string/app_name"
android:process=":remote" />
接着在Activity中打开
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, MyService.class);
startService(intent);
}
}
此时,在AndroidStudio的进程显示栏目中,便可以看到开启了两个线程,这里有一点需要注意的是,开启进程前的符号,:表示为私有进程,其他符号表示公有进程。
在开启多进程的时候,会出现一个小问题,就是Application会被调用两次。通过实现Application查看
public class MyApplication extends Application {
private static final String TAG = "MyApplication";
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "MyApplication onCreate");
}
}
在Logcat下可以看到,两个进程下分别打印出了onCreate,这并不是我们想要的结果,因为在onCreate里会初始化的一些资源可能大多只是一个进程所需要的。我们可以拿到进程的属性,根据属性来判断目前是哪一个进程,然后Application初始化其所需要的对应资源。
public class MyApplication extends Application {
private static final String TAG = "MyApplication";
@Override
public void onCreate() {
super.onCreate();
int pid = android.os.Process.myPid();
Log.e(TAG, "MyApplication id is : " + pid);
String processNameString = "";
ActivityManager activityManager = (ActivityManager) this.getSystemService(getApplicationContext().ACTIVITY_SERVICE);
for (ActivityManager.RunningAppProcessInfo appProcess : activityManager.getRunningAppProcesses()) {
if (appProcess.pid == pid) {
processNameString = appProcess.processName;
}
}
if ("com.study.ipctest".equals(processNameString)) {
Log.e(TAG, "main process");
} else {
Log.e(TAG, "remote process");
}
}
}
3.使用Messager实现进程之间的通信
创建好了多进程之后,那么不由的会想到,怎么在两个进程之间进行通信呢,我们先来看Messager,Messager是一种轻量级的IPC方案并对AIDL实现了简单的封装,Messager可以在不同的进程之间传递Message,而在Message中可以携带我们想要传递的信息。
首先我们创建一个MessengerService代表服务端,使用Handler来接收消息
public class MessengerService extends Service {
public static final String TAG = "MessengerService";
public static final int MSG_FROMCLIENT = 10086;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case MSG_FROMCLIENT: {
Log.e(TAG, "recieve message from client :" + msg.getData().get("msg"));
break;
}
}
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new Messenger(mHandler).getBinder();
}
}
然后在代表客户端的MainActivity中像服务端发送一条消息
public class MainActivity extends AppCompatActivity {
private Messenger mMessenger;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, MessengerService.class);
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
}
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mMessenger = new Messenger(service);
Message message = Message.obtain(null, MessengerService.MSG_FROMCLIENT);
Bundle mBundle = new Bundle();
mBundle.putString("msg", "client send msg to service");
message.setData(mBundle);
try {
mMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mServiceConnection);
}
}
这个时候,在Logcat下,选择服务端进程,就可以看到服务端收到客户端发过来的消息了,那么服务端怎么发消息给客户端呢,还是同样的思路,使用Messager发送,Handler接收。
public class MainActivity extends AppCompatActivity {
private Messenger mMessenger;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MessengerService.MSG_FROMCLIENT:
Log.e(MessengerService.TAG, "client : " + msg.getData().get("rep"));
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, MessengerService.class);
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
}
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mMessenger = new Messenger(service);
Message message = Message.obtain(null, MessengerService.MSG_FROMCLIENT);
Bundle mBundle = new Bundle();
Log.e(MessengerService.TAG, "client : " + "this is client, send a message to service");
mBundle.putString("msg", "this is client, send a message to service");
message.setData(mBundle);
message.replyTo = new Messenger(mHandler); // 1
try {
mMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mServiceConnection);
}
}
1处在发送给服务端的Message里必须带上客户端的Handler,这样便可以实现跨进程的消息传递。但是使用Messager来进行进程之间的通信,会有两个不足之处,第一是Messager是以串行的方式发送消息的,如果有大量的消息发送的话,显然是不合适的;第二是Messager只能用于进程之间的消息传递,却不能夸进程调用方法。所以Messager适用于轻量级的应用场景,那么针对于较复杂的场景,就需要使用AIDL。