Android进程间通信(一):Messenger

Messeger适用于跨进程通信时不需多线程交互的情况。如若需要跨进程多线程交互,可以使用AIDL(请看《Android进程间通信(二):AIDL》)。

一、可运行代码类(Runnable)

public interface Runnable 
{
    /**
     * 把需要运行的代码放在这个方法中
     */
    public void run();
}

二、线程类(Thread类)

public class Thread implements Runnable 
{
    /**
     * 用来保存构造时传入的Runnable对象
     */
    Runnable target;

    /**
     * 常用的构造方法。另外还有其他构造方法
     */
    public Thread(Runnable runnable) 
    {
        // 最终会使得target = runnable;

        ...
    }

    /**
     * 如果直接调用此方法,是不会创建新线程的,而是在当前线程中执行这段代码
     */
    public void run() 
    {
        if (target != null) 
        {
            target.run();
        }
    }

    /**
     * 这个方法会真正创建一个新线程,并调用run()
     */
    public synchronized void start() { ... }

    ...   
}

三、消息(Message)

public final class Message implements Parcelable 
{
    /**
     * 自定义的消息内容。
     */
    public int what;

    public int arg1;

    public int arg2;

    public Object obj;

    Bundle data;

    public void setData(Bundle data) {
        this.data = data;
    }

    public Bundle getData() {
        if (data == null) {
            data = new Bundle();
        }
        return data;
    }

    /**
     * 若这个成员不为null,默认的Handler实现是
     * 只调用它的run方法处理本消息
     */
    Runnable callback;

    public Runnable getCallback() {
        return callback;
    }

    /**
     * 这个成员可以不设置:
     * 在本消息被Handler对象加入消息队列之前,
     * 或者在调用Handler对象的obtainMessage方法之后,
     * 它都会被设置为该Handler对象。
     */
    Handler target;

    /**
     * 从系统维护的全局消息池中获取一个新的消息对象。比直接构造一个新消息更节省资源
     */
    public static Message obtain(/* 本方法有多种重载版本 */) { ... }

    /**
     * 若本消息是调用Handler对象的obtainMessage方法来获取的,
     * 或者手动地设置了target成员,则可调用此方法
     */
    public void sendToTarget() 
    {
        target.sendMessage(this);
    }

    // ====================  进程间通信的分割线  ==================== // 

    /**
     * 本消息应该回复给哪个信使(Messenger)。
     * 如果希望对方回复,则需在发信前,设置好这个成员
     */
    public Messenger replyTo;

    /**
     * 发信者的用户ID。当本消息通过信使发送时,这个值会被自动设置
     */
    public int sendingUid = -1;

    ...    
}

四、消息队列(MessageQueue)

public final class MessageQueue
{
    /**
     * 把一个消息加入队列
     */
    boolean enqueueMessage(Message msg, long when) { ... }

    /**
     * 获取消息队列中的下一个消息
     */
    Message next() 
    {
        /**
         * 本方法的策略:
         * 1.当调用了quit()之后,返回null;
         * 2.当有队列中有非延时或者已到期的消息时,返回首个该类型的消息;
         * 3.阻塞。
         */

        ...
    }

    /**
     * 参数为false时,不管当前消息队列是否有消息,删除所有消息;
     * 参数为true时,删除未到期的消息
     */
    void quit(boolean safe) { ... }

    ... 
}

五、消息泵(Looper)

public final class Looper
{
    /**
     * 系统会为每个应用的主线程创建一个主Looper对象——sMainLooper。
     * 另外还有一个静态成员变量保存着各个线程中的Looper对象(一个线程只能拥有一个Looper),
     * sMainLooper是其中之一。
     */
    private static Looper sMainLooper;

    /**
     * 每个Looper对象中都维护着一个消息队列
     */
    final MessageQueue mQueue;

    /**
     * 如果要在非主线程中创建Looper对象,需先调用这个方法,
     * 再创建处理消息的Handler对象,最后调用loop()
     */
    public static void prepare() 
    {
        // 最终会创建一个消息队列作为内部成员

        ...
    }

    /** 
     * 获取主Looper对象
     */
    public static Looper getMainLooper() 
    {
        synchronized (Looper.class) 
        {
            return sMainLooper;
        }
    }

    /**
     * 获取当前线程的Looper
     */
    public static Looper myLooper() { ... }

    /**
     * 如果要在非主线程中创建Looper对象,需先调用prepare(),
     * 再创建处理消息的Handler对象,最后调用此方法。
     * 这个方法会一直循环地去当前线程的Looper对象的消息队列中取消息
     */
    public static void loop() 
    {
        final Looper me = myLooper();
        if (me == null) 
        {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;

        ...

        for (;;) 
        {
            // 获取下一个消息。可能会阻塞
            Message msg = queue.next();
            if (msg == null) 
            {
                // 若没有消息,则表明已调用了quit(),所以退出循环
                return;
            }

            ...

            // 派发消息。实际上是交回给发送消息的Handler对象处理消息
            msg.target.dispatchMessage(msg);

            ...

            // 回收消息,放回全局消息池中
            msg.recycleUnchecked();
        }
    }

    /**
     * 不管当前消息队列是否有消息,舍弃所有消息,直接退出循环
     */
    public void quit() 
    { 
        mQueue.quit(false); 
    }

    /**
     * 派发非延时及已到期的消息给Handler,而未到期的消息将会被舍弃
     */
    public void quitSafely() 
    {
        mQueue.quit(true);
    }

    ...
}

六、消息处理者(Handler)

public class Handler 
{
    /**
     * 指定为某个线程的Looper或者设置为当前线程的Looper
     */
    final Looper mLooper;

    /**
     * 设置为mLooper中的MessageQueue 
     */
    final MessageQueue mQueue;

    public Handler(/* 本方法有多种重载版本 */)
    {  
        /** 
         * 若不指定Looper则默认与当前线程的Looper绑定:mLooper = Looper.myLooper();
         * 而消息队列成员则与Looper对象的等同:mQueue = mLooper.mQueue;
         */ 

        ...
    }

    /**
     * 从系统维护的全局消息池中获取一个新的消息对象。比直接构造一个新消息更节省资源
     */
    public final Message obtainMessage(/* 本方法有多种重载版本 */) 
    {
        return Message.obtain(/* 本方法有多种重载版本 */);
    }

    /**
     * 以下7个send系列方法最终都会调用enqueueMessage()来发送消息
     */
    public final boolean sendMessage(Message msg) { ... }

    public final boolean sendEmptyMessage(int what) { ... }

    public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { ... }

    public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) { ... }

    public final boolean sendMessageDelayed(Message msg, long delayMillis) { ... }

    public boolean sendMessageAtTime(Message msg, long uptimeMillis) { ... }

    public final boolean sendMessageAtFrontOfQueue(Message msg) { ... }

    /**
     * 以下5个post系列方法,都会把参数封装到一个Message对象中,
     * 并且最终调用enqueueMessage()来发送消息
     */
    public final boolean post(Runnable r) { ... }

    public final boolean postAtTime(Runnable r, long uptimeMillis) { ... }

    public final boolean postAtTime(Runnable r, Object token, long uptimeMillis) { ... }

    public final boolean postDelayed(Runnable r, long delayMillis) { ... }

    public final boolean postAtFrontOfQueue(Runnable r) { ... }

    /**
     * 以上的post系列和send系列方法最终会调用到这个方法
     */
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)
    { 
        /**
         * 无论用哪个Handler对象来发消息,最终都会派发回给该Handler处理。
         * 由此可见,若要发消息给某个线程的Handler对象,需要获取到该对象,
         * 用它来发消息,并且消息的target成员不必设置
         */
        msg.target = this;

        ...

        /**
         * 把消息放入消息队列中。
         * 参数queue实际上就是mLooper
         */
        return queue.enqueueMessage(msg, uptimeMillis);
    }

    /**
     * 派发消息
     */
    public void dispatchMessage(Message msg) 
    {
        if (msg.callback != null) 
        {
            /**
             * 1.当消息中的Runnable类型的callback成员不为null时,调用该成员的run方法。
             *   这行代码相当于msg.callback.run();
             */
            handleCallback(msg);
        } 
        else 
        {
            if (mCallback != null) 
            {
                // 2.如果成员mCallback不为空时
                if (mCallback.handleMessage(msg)) 
                {
                    // 如果没有进一步处理的需要,直接返回
                    return;
                }
            }
            // 3.常用的处理消息方法,需要我们实现其代码
            handleMessage(msg);
        }
    }

    /**
     * 当消息中的Runnable类型的callback成员不为null时,调用此方法
     */
    private static void handleCallback(Message message) 
    {
        message.callback.run();
    }

    /**
     * 通常在这里实现处理消息的代码
     */
    public void handleMessage(Message msg) 
    {
        /**
         * 需要我们实现的处理消息代码。例如:
         * switch(msg.what)
         * {
         * case CONDITION_ONE:
         *     // do something here
         *     break;
         * case CONDITION_TWO:
         *     // do something here
         *     break;
         * 
         * ...
         * }
         */
    }

    /**
     * 自定义处理消息的回调接口
     */
    public interface Callback 
    {
        // 如果没有进一步处理(即handleMessage())的需要,返回true,否则返回false
        public boolean handleMessage(Message msg);
    }

    /**
     * 可以在调用构造方法时,传入一个实现Callback接口的对象来设置这个成员
     */
    final Callback mCallback;

    // ====================  进程间通信的分割线  ==================== // 

    /**
     * 内部维护的信使接口对象
     */
    IMessenger mMessenger;

    /**
     * 获取自身维护的信使接口对象
     */
    final IMessenger getIMessenger() 
    {
        synchronized (mQueue) 
        {
            if (mMessenger != null) 
            {
                return mMessenger;
            }
            mMessenger = new MessengerImpl();
            return mMessenger;
        }
    }

    /**
     * mMessenger成员的类型实际上是这个MessengerImpl类
     */
    private final class MessengerImpl extends IMessenger.Stub 
    {
        /**
         * 信使正是通过这个方法来发消息的
         */
        public void send(Message msg) 
        {
            // 保存调用者的用户ID
            msg.sendingUid = Binder.getCallingUid();
            Handler.this.sendMessage(msg);
        }
    }

    ...
}

七、信使(Messenger)

public final class Messenger implements Parcelable 
{
    // ====================  进程间通信的分割线  ==================== // 

    /**
     * 这个信使接口成员,根据其指向的不同,有着不同的作用:
     * 1.保存对方Handler的内部信使接口,用来发信给对方;
     * 2.保存自己Handler的内部信使接口,供对方回信用。
     * 如果是双向通信,则需要有两个信使对象,分别对应以上两种类型;
     * 若只是单向通信,则只需前者
     */
    private final IMessenger mTarget;

    /**
     * 保存自己Handler的内部信使接口,供对方回信用
     */
    public Messenger(Handler target) 
    {
        mTarget = target.getIMessenger();
    }

    /**
     * 保存转为IBinder类型的对方Handler的内部信使接口,用来发信给对方
     */
    public Messenger(IBinder target) 
    {
        mTarget = IMessenger.Stub.asInterface(target);
    }

    /**
     * 获取转为IBinder类型的(自己的)Handler的内部信使接口。可供对方回信用。
     * 应用场景之一:
     * 客户端绑定服务器的服务(Service),后者在onBind方法的中调用此方法返回:
     * public IBinder onBind(Intent intent)
     * {
     *     return myMessenger.getBinder();
     * }
     */
    public IBinder getBinder() 
    {
        return mTarget.asBinder();
    }

    /**
     * 给对方发消息
     */
    public void send(Message message) throws RemoteException 
    {
        // 如果希望对方回复,则需在发信前,设置好Message的replyTo成员
        mTarget.send(message);
    }

    ...
}

样例

public class MessengerService extends Service {
    static final int MSG_DO_SOMETHING = 0x1;

    class MessageHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_DO_SOMETHING:
                    // Do something here
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }


    final Messenger mMessenger = new Messenger(new MessageHandler());


    @Override
    public IBinder onBind(Intent intent) {
        return mMessenger.getBinder();
    }

    ...
}
public class MessengerActivity extends Activity {

    Messenger mService = null;

    boolean mBound;

    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            mService = new Messenger(service);
            mBound = true;
        }

        public void onServiceDisconnected(ComponentName className) {
            mService = null;
            mBound = false;
        }
    };

    public void doSomething(View v) {
        if (!mBound) return;

        Message msg = Message.obtain(null, MessengerService.MSG_DO_SOMETHING);

        try {
            mService.send(msg);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.XXX);
    }

    @Override
    protected void onStart() {
        super.onStart();

        bindService(new Intent(this, MessengerService.class), 
        mConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();

        if (mBound) {
            unbindService(mConnection);
            mBound = false;
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值