IPC机制
具体方式有很多,比如可以在Intent中附加Extra来传递信息,或者通过共享文件的方式来共享数据,还可以采用Binder方式来跨进程通信,另外,Content Provider天生就是支持跨进程访问的,因此,我们也可以使用它来进行IPC,另外通过网络通信也是可以实现数据传递的,所以Socket也可以实现IPC。
1.使用Bundle
由于Bundle实现了Parcelable接口,所以它可以方便地在不同进程间传输。
除了直接传递数据这种典型的使用场景,他还有一种特殊的使用场景,如A进程正在进行计算,计算完成之后需要把结果传递给B进程,但是这个结果不支持放入Bundle中,那么可以这样考虑,A中,通过Intent启动B进程的一个Service组件(如IntentService),让Service进行后台计算,计算完毕之后,再启动B进程中真正想要启动的组件由于Service也在B进程中,所以目标组件就可以直接获取结果。
findViewById(R.id. button).setOnClickListener( new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setClass(MainActivity. this, SecondActivity.class);
User user = new User(0, "jake", true);
user. book = new Book();
intent.putExtra( "extra_user", (Serializable) user);
startActivity( intent);
}
});
2.使用文件共享
两个进程通过读写同一个文化夹来交换数据,比如A进程把数据写进文件,B进程通过读取这个文件来获取数据。Linux使得并发读写文件可以没有限制,甚至两个线程同时对一个文件进行读写都是运行的。
希望在ManActivity中的onResume中序列化一个User对象到SDk卡上面的一个文件里面,在SecondActivity的onResume中去反序列化。
MainActivity:onResume执行下面的方法
private void persistToFile() {
new Thread( new Runnable() {
@Override
public void run() {
User user = new User(1, “hello world”, false);
File dir = new File(MyConstants. CHAPTER_2_PATH);
if (! dir.exists()) {
dir.mkdirs();
}
File cachedFile = new File(MyConstants. CACHE_FILE_PATH );
ObjectOutputStream objectOutputStream = null;
try {
objectOutputStream = new ObjectOutputStream(
new FileOutputStream(cachedFile));
objectOutputStream.writeObject( user);
Log. d(TAG, “persist user:” + user);
} catch (IOException e) {
e.printStackTrace();
} finally {
MyUtils. close(objectOutputStream);
}
}
}).start();
}
SecondActivity中取:
private void recoverFromFile() {
new Thread(new Runnable() {
@Override
public void run() {
User user = null;
File cachedFile = new File(MyConstants. CACHE_FILE_PATH);
if ( cachedFile.exists()) {
ObjectInputStream objectInputStream = null;
try {
objectInputStream = new ObjectInputStream(
new FileInputStream( cachedFile));
user = (User) objectInputStream.readObject();
Log. d(TAG, "recover user:" + user);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
MyUtils. close(objectInputStream);
}
}
}
}).start();
}
当然这种不支持并发,如果想要并发,需要使用线程同步机制来解决。SharePreferences是个特例,通过键值对来存储数据,底层采用xml来存储键值对,位置在/data/data/packagename/shared_prefs目录下面,从本质来说SharePreferences也属于文件的一种,但是由于系统对它的读写有一定的缓存策略,即在内存里面有一份SharePreferences文件的缓存,因此在多进程模式下,系统对他的读写变得不可靠,当面对高并发的读写访问就有很大几率丢失数据,因此不建议进程间通信使用SP。
3.使用Messenger
Messenger是一种轻量级的IPC方案,它的底层实现是AIDL。从构造方法可以很明显的看出AIDL的痕迹。
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
Messenger的使用方法很简单,它对AIDL做了封装,使得我们可以更简单地进行线程间通信,同时由于它一次处理一个请求,因此在服务端我们不用考虑线程同步的问题,这个是因为服务端不存在并发执行的情况。
步骤:
1.服务端进程,首先我们要创建一个Service来处理客户端的请求,同时创建一个Handler并通过它来创建一个Messenger对象,在Service的onBind里面返回这个Messenger对象底层的Binder即可。
2.客户端进程,首先要绑定服务端的Service,绑定成功之后用服务端返回的IBinder对象创建一个Messenger,通过这个Messenger就可以向服务端发送消息了发送消息类型为Message对象。
如果要服务端能够回应客户端,就和服务端一样,需要创建一个Handler并创建一个新的Messenger,并把这个Messenger对象通过Message的replyTo参数传递给服务端,服务端通过这个replyTo参数就可以回应客户端。
服务端:
public class MessengerService extends Service {
private static final String TAG = “MessengerService”;
private static class MessengerHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch ( msg. what) {
case MyConstants. MSG_FROM_CLIENT:
Log. i(TAG, “receive msg from Client:” + msg.getData().getString( “msg”));
Messenger client = msg. replyTo;
Message relpyMessage = Message. obtain(null, MyConstants.MSG_FROM_SERVICE );
Bundle bundle = new Bundle();
bundle.putString( “reply”, “嗯,你的消息我已经收到,稍后会回复你。” );
relpyMessage.setData( bundle);
try {
client. send(relpyMessage);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
default:
super.handleMessage( msg);
}
}
}
private final Messenger mMessenger = new Messenger( new MessengerHandler());
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand( intent, flags, startId);
}
}
客户端:
public class MessengerActivity extends Activity {
private static final String TAG = “MessengerActivity”;
private Messenger mService;
private Messenger mGetReplyMessenger = new Messenger( new MessengerHandler());
private static class MessengerHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch ( msg. what) {
case MyConstants. MSG_FROM_SERVICE:
Log. i(TAG, “receive msg from Service:” + msg.getData().getString( “reply”));
break;
default:
super.handleMessage( msg);
}
}
}
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
mService = new Messenger( service);
Log. d(TAG, “bind service”);
Message msg = Message. obtain(null, MyConstants.MSG_FROM_CLIENT );
Bundle data = new Bundle();
data.putString( “msg”, “hello, this is client.”);
msg.setData( data);
msg. replyTo = mGetReplyMessenger;
try {
mService.send( msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
public void onServiceDisconnected(ComponentName className) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate( savedInstanceState);
setContentView(R.layout. activity_messenger);
Intent intent = new Intent( “com.ryg.MessengerService.launch”);
bindService( intent, mConnection, Context. BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
unbindService( mConnection);
super.onDestroy();
}
}
Mainfest里面: