你们好,我系苍王。
如下是我这个系列的相关文章,有兴趣能够参考一下,能够给个喜欢或者关注个人文章。java
[Android]如何作一个崩溃率少于千分之三噶应用app--章节列表编程
宣传一波新书,里面介绍了众多组件化编程技术,以及让你对工程架构认识和理解有新的提高。安全
组件化群1已经满员,能够加群2 763094035
服务器
上一节,介绍了使用AIDL的进程通讯框架。
这一节给你们介绍Messenger的通讯框架,而Messenger其意思是“信使”的意思
使用Messenger的优点在于
1.实际传递的是Message,能够复用信息池
2.支持信息回调
3.不须要编写aidl架构
Messenger继承了Parcelable接口,能够做为序列化对象用于传输。
这里能够传入Handler,Handler里面有包含IMessenger对象并发
/** * Create a new Messenger pointing to the given Handler. Any Message * objects sent through this Messenger will appear in the Handler as if * {@link Handler#sendMessage(Message) Handler.sendMessage(Message)} had * been called directly. * * @param target The Handler that will receive sent messages. */
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
复制代码
或者传入IBinder对象,Stub当中存在IMessenger对象app
/** * Create a Messenger from a raw IBinder, which had previously been * retrieved with {@link #getBinder}. * * @param target The IBinder this Messenger should communicate with. */
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
复制代码
实际上Handler中IMessager实现对象是MessengerImpl框架
final IMessenger getIMessenger() {
synchronized (mQueue) {
if (mMessenger != null) {
return mMessenger;
}
mMessenger = new MessengerImpl();
return mMessenger;
}
}
复制代码
这里IMessenger是调用Handler的send方法来发送消息的。异步
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
msg.sendingUid = Binder.getCallingUid();
Handler.this.sendMessage(msg);
}
}
复制代码
每一个Message当中也包含了一个replyTo的变量用户回调ide
/** * Optional Messenger where replies to this message can be sent. The * semantics of exactly how this is used are up to the sender and * receiver. */
public Messenger replyTo;
复制代码
就这几个步骤Messenger独立的实现了Parcelable和使用aidl的通讯方式
接下来咱们介绍一下Modular框架是用Messenger通讯设计。
不一样于上一节介绍的ModularArchitecture的aidl中通讯是1对1的通讯,Modular提供的通讯框架是经过1对多的发送方式来传递的。
如下是Messenger的注册流程图
1.每一个模块初始化时启动一个消息队列来监听消息。
@Override
public void init() {
mBaseModule = this;
//启动线程接收消息
mWorkThread = new WorkThread();
mWorkThread.start();
//注册跳转路由
OkBus.getInstance().register(Constants.ROUTER_OPEN_URL, new Event() {
@Override
public void call(Message msg) {
String url = (String) msg.obj;
//实际跳转使用的Router
Router.openLocalUrl(BaseAppModuleApp.getBaseApplication(), url);
}
}, Bus.UI); //线程参数
}
public class WorkThread extends Thread {
Handler mHandler;
public Messenger clientHandler;
@Override
public void run() {
Looper.prepare();
//每一个module都有接收消息处理ClientHandler
mHandler = new ClientHandler();
clientHandler = new Messenger(mHandler);
if(resultRef!=null){
try {
resultRef.set(clientHandler);
} catch (Exception e) {
e.printStackTrace();
} finally {
//使用CountDownLatch唤醒机制保证线程安全
latch.countDown();
}
}
Looper.loop();
}
public void quit() {
mHandler.getLooper().quit();
}
}
复制代码
2.绑定MessengerService做为进程间管理,而且绑定每一个模块的ServiceConnection
/** * 链接服务器 */
public void connectService() {
Intent intent = new Intent(MessengerService.class.getCanonicalName());// 5.0+ need explicit intent
intent.setPackage(Constants.SERVICE_PACKAGE_NAME); // the package name of Remote Service
//绑定MessengerService做为进程间管理,而且绑定每一个模块的ServiceConnection
boolean mIsBound = bindService(intent, mBaseModule.mConnection, BIND_AUTO_CREATE);
LogUtils.i(Constants.TAG + " connectService", " ServiceConnection-->bindService mIsBound: " + mIsBound);
}
复制代码
3.启动MessengerService,启动消息循环
@Override
public void onCreate() {
super.onCreate();
LogUtils.i(Constants.TAG + " essengerService", "MessengerService -->onCreate");
mWorkThread = new WorkThread();
mWorkThread.start();
}
public class WorkThread extends Thread {
public ServiceHandler mHandler;
@Override
public void run() {
Looper.prepare();
LogUtils.i(Constants.TAG + " essengerService", "MessengerService -->new ServiceHandler");
//经过ServiceHandler来处理收到的消息
mHandler = new ServiceHandler();
Messenger mMessenger = new Messenger(mHandler);
// OkBus.getInstance().mServiceMessenger = mMessenger;
try {
resultRef.set(mMessenger);
} catch (Exception e) {
e.printStackTrace();
} finally {
latch.countDown();
}
Looper.loop();
}
public void quit() {
mHandler.getLooper().quit();
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
try {
latch.await(10, TimeUnit.SECONDS); //最多等待10秒
} catch (Exception e) { //等待中断
e.printStackTrace();
}
Messenger mMessenger = resultRef.get();
return mMessenger.getBinder();
}
复制代码
4.初始化OkBus并发送消息注册
public void initModule(BaseModule mBaseModule, Messenger mServiceMessenger, int mModuleId, Messenger mClientMessenger) {
this.mServiceMessenger = mServiceMessenger;
this.mModuleId = mModuleId;
this.mBaseModule = mBaseModule;
isModule.set(true);
mBaseModule.isConnected.set(true);
//线程池获取信息
Message msg = Message.obtain();
Bundle data = new Bundle();
data.putInt(Constants.REGISTER_ID, mModuleId);//注册模块信息
msg.setData(data);
msg.replyTo = mClientMessenger; //将处理消息的Messenger绑定到消息上带到服务端
try {
//发送到MessengerService中处理
mServiceMessenger.send(msg);
} catch (Exception e) {
e.printStackTrace();
}
}
复制代码
5.ServiceHandler中维护一个对Service Messenger到多个Client Messenger的关系
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
try {
Bundle bundle = msg.getData();
int registerId = bundle.getInt(Constants.REGISTER_ID, -1);
if (registerId > 0) {//注册模块类型的消息
LogUtils.logOnUI(Constants.TAG, "handleMessage: msg = [收到注册模块类型的消息]: registerId: " + Integer.toHexString(registerId));
//每一个模块对应的ClientHandler
Messenger client = msg.replyTo;
mClientMessengers.put(registerId, client);//存储Client端接受处理消息的Messenger来发送Message到Client
Message data = Message.obtain();
Bundle mBundle = new Bundle();
mBundle.putInt(Constants.REGISTER_RES, Constants.REGISTER_SEC); //通知Client模块注册成功
data.setData(mBundle);
try {
client.send(data); //回调注册状态给模块
} catch (Exception e) {
e.printStackTrace();
}
}
复制代码
6.介绍的模块注册结果
public class ClientHandler extends Handler {
@Override
public void handleMessage(Message msg) {
……
int resCode = bundle.getInt(Constants.REGISTER_RES, -1);
if (resCode < 0) {//收到普通消息
……
} else {//收到模块注册结果消息
boolean isRegisterSec = resCode == Constants.REGISTER_SEC;
if (isRegisterSec) {
LogUtils.logOnUI(Constants.TAG, "handleMessage() : reply = [注册成功]");
}
}
}
}
复制代码
7.其绑定完毕以后,将module信息注册到OkBus,以后会使用afterConneted()来初始化想要接收的消息
public ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
LogUtils.logOnUI(Constants.TAG, "ServiceConnection-->onServiceConnected 已自动唤醒服务器");
Messenger mServiceMessenger = new Messenger(service);
OkBus.getInstance().initModule(mBaseModule, mServiceMessenger, getModuleId(), mWorkThread.clientHandler);
afterConnected();
}
复制代码
8.经过ServiceBus来注册其余module会跨module调用过来的消息。
@Override public void afterConnected() {
ServiceBus.getInstance().registerService(Constants.SERVICE_A_UID, msg -> {
LogUtils.logOnUI(Constants.TAG, "afterConnected a 进程收到[服务请求]消息:ServiceMessage-->hello: " + Integer.toHexString(Math.abs(msg.what)));
return "10086";
});
}
复制代码
9.服务注册后,能够看到其会经过onEvent返回回调的msg对象(CallBack接口)
/** * 注册服务 * * @param serviceId 服务id * @param callback 服务调用的回调 * @param <T> 服务返回的数据范型 */
public <T> void registerService(final int serviceId, final CallBack<T> callback) {
LogUtils.logOnUI(Constants.TAG, "注册服务 " + Integer.toHexString(Math.abs(serviceId)));
okBus.unRegister(serviceId);//服务提供者只能有一个
okBus.register(serviceId, msg -> {
//TODO 优化到子线程
okBus.onEvent(serviceId - 1, callback.onCall(msg));
});
}
复制代码
到这里就介绍完初始化和注册流程了。
接下来介绍一下消息发送的架构,注意一下的模块服务规则
//==================模块间的服务定义============//
/** * 服务定义规则: * 一、服务的请求ID必须是负值(正值表示事件) * 二、服务的请求ID必须是奇数,偶数表示该服务的返回事件, * 即: requestID-1 = returnID * 例如 -0xa001表示服务请求 -0xa002表示-0xa001的服务返回 */
public static final int SERVICE_A_UID = -0xa001;
/** * 异步调用远端服务 */
findViewById(R.id.bt_1).setOnClickListener(v -> {
//异步调用,
ServiceBus.getInstance().fetchService(Constants.SERVICE_A_UID, msg -> {
LogUtils.logOnUI(Constants.TAG, "b 进程收到[异步服务返回]消息: 获取到的UID-->" + msg.obj);
Toast.makeText(BModuleActivity.this,
"b 进程收到[异步服务返回]消息: 获取到的UID-->" + msg.obj,
Toast.LENGTH_SHORT).show();
});
});
复制代码
具体步骤
1.对ID的请求限制
2.module链接的判断,没有链接就尝试链接
3.唤醒目标进程
4.注册回调
5.通知目标模块
/** * 异步调用服务 * * @param serviceId 服务id * @param callback 回调 */
public void fetchService(final int serviceId, final Event callback) {
if (serviceId > 0 || serviceId % 2 == 0) {
assert false : "请求ID必须是负奇值!";
return;
}
if (okBus.isModule() && !okBus.isModuleConnected()) {
LogUtils.logOnUI(Constants.TAG, "请求失败,服务已经断开连接,尝试从新打开服务,进行请求");
BaseAppModuleApp.getBaseApplication().connectService();
return;
}
//自动唤醒目标进程
if (okBus.isModule()) {
String module_name = Integer.toHexString(Math.abs(serviceId)).substring(0, 1);
noticeModule(module_name, serviceId, null);
}
//一、先注册回调
okBus.register(serviceId - 1, msg -> {
callback.call(msg);
okBus.unRegister(serviceId - 1);//服务是单次调用,触发后即取消注册
});
//二、通知目标模块
okBus.onEvent(serviceId);
}
复制代码
唤醒目标进程
/** * 唤醒目标进程 * * @param module_name 模块名 * @param serviceId 服务ID * @param url 要打开的url */
public void noticeModule(String module_name, int serviceId, String url) {
Intent ait = new Intent(NoticeService.class.getCanonicalName());// 5.0+ need explicit intent //唤醒目标进程的服务Action名
ait.setPackage(Constants.MODULE_PACKAGE_PRE + module_name); //唤醒目标进程的包名
//绑定包名
BaseAppModuleApp.getBaseApplication().bindService(ait, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (service != null) {
LogUtils.logOnUI(Constants.TAG, "已经自动唤醒" + module_name);
Messenger moduleNameMessenger = new Messenger(service);
Message _msg = Message.obtain();
Bundle _data = new Bundle();
_data.putBoolean(Constants.NOTICE_MSG, true);
_msg.setData(_data);
_msg.replyTo = okBus.mServiceMessenger;//把服务器的信使给目标组件的信使,让他俩本身联系,这里仅仅是通知
try {
moduleNameMessenger.send(_msg);
} catch (Exception e) {
e.printStackTrace();
}
try {
Thread.sleep(200);//给服务器和目标组件500ms联系的时间
} catch (Exception e) {
e.printStackTrace();
}
} else {
LogUtils.logOnUI(Constants.TAG, module_name + "进程,原本就是醒的");
}
if (serviceId < 0) { //唤醒成功,继续发送异步请求,通知目标模块
okBus.onEvent(serviceId);
}
if (!TextUtils.isEmpty(url)) { //目标url不为空,继续打开目标
OkBus.getInstance().onEvent(Constants.ROUTER_OPEN_URL, url);
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
LogUtils.logOnUI(Constants.TAG, "自动唤醒目标进程失败 module_name:" + module_name);
}
}, BIND_AUTO_CREATE);
}
复制代码
启动模块,并传递绑定对象
/** * 收到唤醒通知以后,初始化模块,并自动去服务器注册 * * @param intent * @return */
@Nullable
@Override
public IBinder onBind(Intent intent) {
LogUtils.logOnUI(Constants.TAG, getPackageName() + " 收到唤醒通知");
//获取模块的module
BaseModule mBaseModule = BaseAppModuleApp.getBaseApplication().mBaseModule;
if (!mBaseModule.isConnected.get()) {
LogUtils.logOnUI(Constants.TAG, getPackageName() + " 我被唤醒啦");
//初始化module,启动module的ClientHandler(Messenger)
mBaseModule.init(latch, resultRef);
mBaseModule.afterConnected();
try {
//超时限制
latch.await(2000, TimeUnit.SECONDS);
} catch (Exception e) { //等待中断
e.printStackTrace();
}
}
//返回ClientHandler的Binder对象
return mBaseModule.mWorkThread.clientHandler.getBinder();
}
复制代码
发送消息,其最终是经过ServiceBus转发到每一个模块OkBus,而后Binder传递的Messenger关联来完成信息传递。
/** * @param tag 发送消息的事件ID * @param data 发送消息的数据 * @return */
public OkBus onEvent(int tag, Object data) {
//发送时间,因此tag小于0
String hex = Integer.toHexString(Math.abs(tag));
LogUtils.i("Message OkBus", "onEvent " + (tag > 0 ? "[普通]" : "[服务]") + " tag: " + hex);
//一、本地先处理非服务消息
if (tag >= 0) onLocalEvent(tag, data);
//二、若是是组建化,向服务器发消息
if (isModule.get()) {
//保证发送时服务启动
if (!isModuleConnected()) {
LogUtils.i("Message OkBus", "发消息失败,服务已经断开连接,尝试从新打开服务,进行发消息");
BaseAppModuleApp.getBaseApplication().connectService();
return this;
}
//数据为空,即为事件
if (data == null || data instanceof Serializable) {
Message newMsg = new Message();
if (data != null) {
Bundle bundle = new Bundle();
bundle.putSerializable(Constants.MESSAGE_DATA, (Serializable) data);
newMsg.setData(bundle);
}
newMsg.arg1 = mModuleId;
newMsg.what = tag;
try {
//发送信息到目标Service
mServiceMessenger.send(newMsg);
} catch (Exception e) {
e.printStackTrace();
}
} else {
assert false : "跨进程时,你传递的对象没有序列化!";
}
} else if (tag < 0) {//非组件化时本地处理服务消息
onLocalEvent(tag, data);
}
return this;
}
复制代码
使用Messenger通讯框架设计就介绍到这里。1.Modular框架,模块内传输使用了OkBus的路由传输,而在跨模块则使用Messenger的方式来完成2.Messenger实际是一个封装好的IBinder对象3.Modular经过合理设置跨模块的传输的协议逻辑来完成信息传输