Android Service更新UI的方法之Messenger

       上一篇文章我们讲解了怎样通过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
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值