开个头
萌新刚接触Binder的时候,那个头大的啊。。。可以说学Binder的日子是灾难性的。。但如今咱从坑里爬出来了,自然不能忘记报这一箭之仇。。现在来攻略它吧。
- Binder
Android中,Binder最常见的应用场景是在四大组件之一的Service(服务)中,例如:
/***来个实例吧***/
public class MyService extends Service{
class DownloadBinder extends Binder{
public void startDownload(){
Log.d("MyService","startDownload executed");
}
public int getProgress(){
Log.d("Myservice","getProgress executed");
return 0;
}
}
private DownloadBinder mBinder = new DownloadBinder();//构建实例
@Override
public IBinder onBinder(Intent intent){
return mBinder;
}
}
//在这里我们新建一个DownloadBinder类,让他继承自Binder,然后实例化它,最后在onBinder中使用它
这是最简单的Binder,太复杂的这里先不讨论,接下来走近Android中的IPC机制吧
- Bundle
Android中的三大组件(Activity,Service,Receiver)都支持在Intent中传递Bundle数据,又因为Bundle实现了Parcelable接口,所以Bundle也能很方便地在不同进程间传输被序列化的数据。 - 文件共享
文件共享也是一种不错的进程间通信方式,简单讲来就是两个进程通过读/写同一个文件来交换数据,尽管这可能出现问题,但这么好用的方法,萌新是不可能放过的。例如
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("main","persist user"+user);
}catch (IOException e){
e.printStackTrace();
}finally {
MyUtils.close(objectOutputStream);
}
}
}).start();
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("main","recover user:" + user);
}catch (IOException e){
e.printStackTrace();
}catch (ClassNotFoundException e){
e.printStackTrace();
}finally {
MyUtils.close(objectInputStream);
}
}
}
}).start();
得到的结果是在SecondActivity中成功从文件里恢复了之前储存的User对象的内容。但反序列化得到的对象在本质上和之前的是不一样的,是两个对象。通过文件共享来实现共享数据对文件格式没有具体要求,只要读/写双方约定数据格式即可。但这样的弊端在于并行读/写的问题,所以我们尽可能避免这种情况发生或者用线程同步来限制多个线程的写操作(读操作不用管)。
- Messenger
这玩意可以在不同进程中传递Message对象,在Message中放入我们需要传递的数据,就能轻松实现数据的进程间传递了。Messenger的实现分为服务端和客户端,我们一一看过去吧
1:服务端进程 - 创建一个Handler,并通过它创建一个Messenger对象,然后再Service的onBind中返回Messenger的Binder。如下:
public class MyService extends Service {
private Handler handler =new Handler(){
@Override
public void handleMessage(Message msg){
Log.d("main","get msg");
}
};
Messenger messenger = new Messenger(handler);
@Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();
}
}
2:客户端进程
有限绑定服务端的Service,然后用服务端返回的IBinder创建一个Messenger,通过这个Messenger就能向服务端发送信息了,类型为Message对象。如果需要服务端回应客户端,就需要新建一个Handler并创建一个新Messenger,然后通过Message的replyTo参数把这个Messenger传给服务端,服务端再通过这个replyTo参数回应客户端。如下:
/***MainActivity***/
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
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 2:
Log.d("main_reply",msg.getData().getString("reply"));
break;
default:
super.handleMessage(msg);
}
}
}
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = new Messenger(service);
Message msg = Message.obtain(null,1);
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_main);
Intent intent = new Intent(this,MyService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy(){
unbindService(mConnection);
super.onDestroy();
}
}
/***MyService***/
public class MyService extends Service {
private static final String TAG = "MessengerService";
private static class MessengerHandler extends Handler{
@Override
public void handleMessage(Message msg){
switch (msg.what) {
case 1:
Log.d(TAG,"receive msg from Client:" + msg.getData().getString("msg"));
Messenger client = msg.replyTo;
//获取msg的replyTo参数,用于返还信息
Message replyMessage = Message.obtain(null,2);
Bundle bundle = new Bundle();
bundle.putString("reply","收到了的,等会叫你");
replyMessage.setData(bundle);
try {
client.send(replyMessage);//返还信息
}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();
}
}
总结:进程间通信,听起来很nb的概念,确实也nb,但只要抓住不同进程不同路这个概念就可以帮助理解了。