Messenger案例解析及其源码分析

Messenger简介及其作用

Messenger是一种轻量级的IPC方案,通过它可以在不同进程中传递Message对象,在Message中放入我们需要传递的数据,就可以实现数据的进程间传递了。其中本质还是Handler和AIDL的封装和结合。

  1. 按键截屏使用的就是Messenger的方式进行IPC通信
    我们都知道原生android中截屏触发是同时按住电源键和音量下键,然后就能够截取屏幕了。
    这个事件的处理流程在PhoneWindowManager.java中进行处理。
    经过多步骤的跳转(后续补充完整),跳到了方法takeScreenshot,代码如下:
    private static final String SYSUI_PACKAGE = "com.android.systemui";
    private static final String SYSUI_SCREENSHOT_SERVICE =
            "com.android.systemui.screenshot.TakeScreenshotService";
private void takeScreenshot(final int screenshotType) {
    synchronized (mScreenshotLock) {
        if (mScreenshotConnection != null) {
            return;
        }
        final ComponentName serviceComponent = new ComponentName(SYSUI_PACKAGE,
                SYSUI_SCREENSHOT_SERVICE);
        final Intent serviceIntent = new Intent();
        serviceIntent.setComponent(serviceComponent);
        ServiceConnection conn = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                synchronized (mScreenshotLock) {
                    if (mScreenshotConnection != this) {
                        return;
                    }
                    Messenger messenger = new Messenger(service);
                    Message msg = Message.obtain(null, screenshotType);
                    final ServiceConnection myConn = this;
                    Handler h = new Handler(mHandler.getLooper()) {
                        @Override
                        public void handleMessage(Message msg) {
                            synchronized (mScreenshotLock) {
                                if (mScreenshotConnection == myConn) {
                                   //绑定成功之后,就通知客户端进行解绑操作(我也不知道为什么立刻解绑,可能是启动之后会自动截图,不再需要绑定)
                                    mContext.unbindService(mScreenshotConnection);
                                    mScreenshotConnection = null;
                                    mHandler.removeCallbacks(mScreenshotTimeout);
                                }
                            }
                        }
                    };
                    msg.replyTo = new Messenger(h);
                    msg.arg1 = msg.arg2 = 0;
                    if (mStatusBar != null && mStatusBar.isVisibleLw())
                        msg.arg1 = 1;
                    if (mNavigationBar != null && mNavigationBar.isVisibleLw())
                        msg.arg2 = 1;
                    try {
                        messenger.send(msg);
                    } catch (RemoteException e) {
                    }
                }
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {
                notifyScreenshotError();
            }
        };
        if (mContext.bindServiceAsUser(serviceIntent, conn,
                Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
                UserHandle.CURRENT)) {
            mScreenshotConnection = conn;
            mHandler.postDelayed(mScreenshotTimeout, 10000);
        }
    }
}

主要步骤就是bindServiceAsUser,绑定SystemUI模块中的TakeScreenshotService服务。
ServiceConnection中onServiceConnected方法,

                    synchronized (mScreenshotLock) {
                        if (mScreenshotConnection != this) {
                            return;
                        }
                        Messenger messenger = new Messenger(service);
                        Message msg = Message.obtain(null, screenshotType);
                        final ServiceConnection myConn = this;
                        Handler h = new Handler(mHandler.getLooper()) {
                            @Override
                            public void handleMessage(Message msg) {
                                synchronized (mScreenshotLock) {
                                    if (mScreenshotConnection == myConn) {
                                        mContext.unbindService(mScreenshotConnection);
                                        mScreenshotConnection = null;
                                        mHandler.removeCallbacks(mScreenshotTimeout);
                                    }
                                }
                            }
                        };
                        msg.replyTo = new Messenger(h);
                        msg.arg1 = msg.arg2 = 0;
                        if (mStatusBar != null && mStatusBar.isVisibleLw())
                            msg.arg1 = 1;
                        if (mNavigationBar != null && mNavigationBar.isVisibleLw())
                            msg.arg2 = 1;
                        try {
                            messenger.send(msg);
                        } catch (RemoteException e) {
                        }
                    }

根据服务端传过来的IBinder,构建对应的Messenger,相当于构建服务端的Messenger代理,然后封装各种数据到Message,然后通过Messenger代理传回给服务端,服务端根据封装的数据,进行截图。
其中还有一个包含重要的步骤:

msg.replyTo = new Messenger(h);

这一步将客户端的Messenger传送给服务端,服务端根据msg.replyTo,回调客户端。
那么这个takeScreenshot方法端就是所谓的客户端用来绑定SystemUI中的服务端
调用服务端的TakeScreenshotService进行实际的截屏操作。再来看看TakeScreenshotService源码:

public class TakeScreenshotService extends Service {
    private static final String TAG = "TakeScreenshotService";

    private static GlobalScreenshot mScreenshot;

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            final Messenger callback = msg.replyTo;
            Runnable finisher = new Runnable() {
                @Override
                public void run() {
                    Message reply = Message.obtain(null, 1);
                    try {
                        callback.send(reply);
                    } catch (RemoteException e) {
                    }
                }
            };
            if (mScreenshot == null) {
                mScreenshot = new GlobalScreenshot(TakeScreenshotService.this);
            }

            switch (msg.what) {
                case WindowManager.TAKE_SCREENSHOT_FULLSCREEN:
                    mScreenshot.takeScreenshot(finisher, msg.arg1 > 0, msg.arg2 > 0);
                    break;
                case WindowManager.TAKE_SCREENSHOT_SELECTED_REGION:
                    mScreenshot.takeScreenshotPartial(finisher, msg.arg1 > 0, msg.arg2 > 0);
                    break;
            }
        }
    };

    @Override
    public IBinder onBind(Intent intent) {
        return new Messenger(mHandler).getBinder();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        if (mScreenshot != null) mScreenshot.stopScreenshot();
        return true;
    }
}

就是一个标准的绑定服务的写法 返回new Messenger(mHandler).getBinder(),其实就是将服务端Messenger的地址发送给客户端。回调onServiceConnected方法,告诉客户端绑定成功。服务端自己绑定成功之后就根据screenshotType,进行全部
截图还是部分截图。

  1. Messenger源码分析 先看一下Messenger的源码:
//实现了Parcelable,可以再进程之间传递的数据
public final class Messenger implements Parcelable {
    private final IMessenger mTarget;

    //通过Handler创建mTarget,一般先在服务端建立Messenger,传给客户端,然后在客户端获取对应的IBinder,然后建立一个Messenger(相当于服务端Messenger的代理)
    public Messenger(Handler target) {
        mTarget = target.getIMessenger();
    }

    通过IBinder创建mTarget,一般在客户端建立(相当于服务端Messenger的代理)
    public Messenger(IBinder target) {
        mTarget = IMessenger.Stub.asInterface(target);
    }

    //跨进程发送消息
    public void send(Message message) throws RemoteException {
        mTarget.send(message);
    }

    //服务端返回Messenger对应的IBinder地址,给客户端进行处理
    public IBinder getBinder() {
        return mTarget.asBinder();
    }


    public boolean equals(Object otherObj) {
        if (otherObj == null) {
            return false;
        }
        try {
            return mTarget.asBinder().equals(((Messenger)otherObj)
                    .mTarget.asBinder());
        } catch (ClassCastException e) {
        }
        return false;
    }

}

其中就一个属性mTarget,看看这个具体是什么吧。就是MessengerImpl对象,继承IMessenger.Stub。 这个一看就是IMessenger这个AIDL的实现类

private final IMessenger mTarget; 
//通过Handler创建mTarget,一般先在服务端建立,传给客户端,然后再客户端建立一个Messenger,通过msg.reply传给服务端 
public Messenger(Handler target) { 
   mTarget = target.getIMessenger(); 
}

    final IMessenger getIMessenger() {
    //就是在Handler中建立一个MessengerImpl对象
        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();
             //实际mTarget的send方法,还是Handler发送消息。 
             //所以服务端send,实际就是服务端的Handler发送消息,然后在服务端处理。客户端的send发送消息,就是客户端的Handler进行处理 
            Handler.this.sendMessage(msg);
        }
    }

然后就是发送消息,然后通过Messenger的send发送,而这个send方法上面我们也分析过了,其实现就是通过Handler的sendMessage方法来发送的,所以不再多解释,又回归到了Handler与Message过程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值