Android Service更新UI的方法之Messenger

来源:互联网 发布:淘宝ued团队博客 编辑:程序博客网 时间:2024/06/06 08:52

       上一篇文章我们讲解了怎样通过AIDL实现Service更新UI的功能,今天要讲的是另外一种方式:Messenger。它可以通过与Handler配合实现不同进程之间的通信,可以跨进程使用Handler发送消息。它的使用不像直接使用AIDL那么复杂,它只需要实现一个Handler对象来处理消息,其他的和使用普通的Service差不多。两个进程间可以通过Messenger来发送Message进行通信,在服务端使用Handler创建一个Messenger,客户端持有这个Messenger就可以与服务端通信了。

       我们之前使用Handler和Message都是在同一个进程,子线程持有一个主线程的Handler对象,并向主线程发送消息。Android可以使用Binder机制进行跨进程通信,所以我们当然可以将Handler与Binder结合起来进行跨进程发送消息,Messenger就是基于这个原理。

       使用方法:

1、创建一个Handler对象,以它为参数再创建一个Messenger对象

mMessenger = new Messenger(mHandler)  

2、客户端使用bindService绑定远程服务

3、远程服务的onBind()方法返回一个Binder对象

return mMessenger.getBinder();  

 4、客户端使用远程返回的Binder对象得到Messenger对象

 public void onServiceConnected(ComponentName name, IBinder service) {    

              rMessenger = new Messenger(service);      

 }  

5、客户端使用这个Messenger对象向远程发送消息

rMessenger.send(msg);

       这样远程服务端的Handler对象就能收到消息,然后在其handleMessage(Message msg)方法中处理消息。

       我们已经实现了消息的单向传递,即从客户端向服务端的传递,那么如何实现双向传递呢?

       在第5步中,在send(msg)前通过msm.replyTo = mMessenger将自己的Messenger对象设置到消息中,这样服务端接收到消息时同时也得到了客户端的Messenger对象了,然后服务端可以通过客户端的Messenger对象向它发送消息。通过Messenger实现的双向通信就完成了。

       下面来看全部的实现代码,首先是Service端:

public class MessengerService extends Service {    private Messenger activityMessenger;    private MessengerHandler messengerHandler;    private int count = 0;    private static volatile boolean isRunning;    public MessengerService() {        messengerHandler = new MessengerHandler();    }    @Override    public IBinder onBind(Intent intent) {        return new Messenger(messengerHandler).getBinder();    }    @Override    public boolean onUnbind(Intent intent) {        isRunning = false;        return super.onUnbind(intent);    }    private class MessengerHandler extends Handler {        @Override        public void handleMessage(Message msg) {            if (msg.replyTo != null) {                activityMessenger = msg.replyTo;                notifyActivity();            }            super.handleMessage(msg);        }    }    private void notifyActivity(){        isRunning = true;        new Thread(new Runnable() {            @Override            public void run() {                while(isRunning) {                    try {                        Thread.sleep(1000);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    count++;                    Message message = Message.obtain();                    message.arg1 = count;                    try {                        activityMessenger.send(message);                    } catch (RemoteException e) {                        e.printStackTrace();                    }                }            }        }).start();    }}
       然后是Activity端:
public class ServiceUpdateActivity extends Activity implements View.OnClickListener {    private Button btn, btnStop;    private TextSwitcher switcher;    private int mCount = 0;    Intent intent;    Messenger mServiceMessenger;    Messenger mActivityMessenger;    private boolean isMessengerServiceConnected = false;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_service_update_main);        btn = (Button) findViewById(R.id.btn);        btnStop = (Button) findViewById(R.id.method_stop);        btn.setOnClickListener(this);        btnStop.setOnClickListener(this);        switcher = (TextSwitcher) findViewById(R.id.number_switcher);        switcher.setFactory(new ViewSwitcher.ViewFactory() {            @Override            public View makeView() {                TextView textView = new TextView(ServiceUpdateActivity.this);                textView.setGravity(Gravity.CENTER);                textView.setTextSize(30);                return textView;            }        });        switcher.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.switcher_text_in));        switcher.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.switcher_text_out));        updateCount();        mActivityMessenger = new Messenger(mMessengerHandler);        intent = new Intent(this, MessengerService.class);    }    @Override    protected void onDestroy() {        stopAll();        super.onDestroy();    }    private void startMessengerMethod() {        bindService(intent, messengerServiceConnection, Service.BIND_AUTO_CREATE);    }    /**     * 刷新数字     */    private void updateCount() {        //由于从binder调用回来是在子线程里,需要post到主线程调用        new Handler(Looper.getMainLooper()).post(new Runnable() {            @Override            public void run() {                switcher.setText(Integer.toString(mCount));            }        });    }    private void stopAll() {        if (isMessengerServiceConnected) {            unbindService(messengerServiceConnection);            isMessengerServiceConnected = false;        }    }    @Override    public void onClick(View v) {        switch (v.getId()) {            case R.id.btn:                startMessengerMethod();                break;            case R.id.method_stop:                stopAll();                break;        }    }    //messenger使用    private ServiceConnection messengerServiceConnection = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            isMessengerServiceConnected = true;            mServiceMessenger = new Messenger(service);            Message message = Message.obtain();            message.replyTo = mActivityMessenger;            try {                mServiceMessenger.send(message);            } catch (RemoteException e) {                e.printStackTrace();            }        }        @Override        public void onServiceDisconnected(ComponentName name) {        }    };    private Handler mMessengerHandler = new Handler() {        @Override        public void handleMessage(Message msg) {            mCount = msg.arg1;            updateCount();            super.handleMessage(msg);        }    };}

       上面的代码实现了Activity和Service的双向通信,也就实现了Service更新Activity的UI的功能。可能有的同学会觉得奇怪,Messenger是怎么做到跨进程发送消息的。

       首先来看一个问题 ,在Service中的onBind()方法中,返回了一个Messenger对象,

    @Override    public IBinder onBind(Intent intent) {        return new Messenger(messengerHandler).getBinder();    }
       而在Activity中的onServiceConnected方法中,却new了一个新的Messenger对象,那就奇怪了,两个不同的对象怎么做到通信的?

<span style="white-space:pre"></span>@Override        public void onServiceConnected(ComponentName name, IBinder service) {            mServiceMessenger = new Messenger(service);            Message message = Message.obtain();            message.replyTo = mActivityMessenger;            try {                mServiceMessenger.send(message);            } catch (RemoteException e) {                e.printStackTrace();            }        }
       我们看一下Messenger的构造函数,还是首先看看Service端,

    public Messenger(Handler target) {        mTarget = target.getIMessenger();    }
       其中mTarget是一个IMessenger的aidl接口,getIMessenger()做了什么呢
    final IMessenger getIMessenger() {        synchronized (mQueue) {            if (mMessenger != null) {                return mMessenger;            }            mMessenger = new MessengerImpl();            return mMessenger;        }    }    private final class MessengerImpl extends IMessenger.Stub {        public void send(Message msg) {            msg.sendingUid = Binder.getCallingUid();            Handler.this.sendMessage(msg);        }    }
       可以看到getIMessenger()返回了一个IMessenger类型的Binder对象,Messenger本身也是通过AIDL实现的。而且我们在调用send(msg)方法的时候,其实是调用了与这个Binder关联的Handler的sendMessage()方法,继而会触发这个Handler的handleMessage()的调用。

       通过上面的分析,大概能猜出来,Activity端就是拿到这个IMessenger类型的Binder的代理对象,通过代理对象的send()方法来发送消息到Service中。

    public Messenger(IBinder target) {        mTarget = IMessenger.Stub.asInterface(target);    }
       至此,关于跨进程的Service通知Activity更新UI的分析就讲完了,可以发现无论是哪种实现,最终都是通过AIDL的方式,只是做了不同的封装和处理罢了。也说明实现一个问题的方式有很多,但也许表面上看起来不同的实现,底层的原理都是相似的。


点我下载Demo源代码





1 0