新闻资讯
Android必知必会的四大组件 -- Broadcast Receiver篇
前言
广播,在我们的应用中起着一个非常重要的角色。就比如说我们经常使用的Intent、IntentFilter,就有着广播的作用。
在我的Android工具包项目中就集成了网络广播的动态注册。
思维导图
生命周期
因为没有直接的图示可以上,而且Broadcast中并没有onCreate、onDestroy这样方法,只能通过官方文档验证。
图中的圈红框的加粗文字大概意思就是,使用静态广播进行注册,那么每接受到一次信息,他就不复存在了,也就是需要重建。其它方式构建的生命周期,与关联的Activity中的具体操作相关。在Android 8.0以后已经不在支持静态广播了
两种广播
public class NetworkReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION) && App.getInstance() != null) {
App.getInstance().notifyObservers(isNetConnected(context));
}
}
}
虽然是两种广播形式,但是他们同样要干一件事情,就是继承BroadcastReceiver,并重写onReceive()方法。
全局广播
这个广播同样可以使用在应用内,但是这种广播的安全性有待质疑。
// 消息传递 sendBroadcast(Intent); 复制代码
- 静态广播注册
<receiver android:name="com.clericyi.basehelper.network.NetworkReceiver"> <intent-filter> <action android:name="android.intent.action.BATTERY_LOW"/> </intent-filter> </receiver> 复制代码
- 动态广播注册
和静态广播不同的地方,动态广播注册完以后需要进行注销操作。
// 注册 networkReceiver = new NetworkReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
registerReceiver(networkReceiver, intentFilter); // 注销(如果没有注销,将会发生内存泄漏) unregisterReceiver(networkReceiver);
应用内广播
-
优点:
- 发送的广播只会在自己的App内传播,不会泄漏给其他App,保障了数据的安全性。
- 无法接受到其他App的广播,也就省去各种麻烦事。
- 相较于全局广播效率更高。
- 使用方法
//注册 networkReceiver = new NetworkReceiver();
localBroadcastManager = LocalBroadcastManager.getInstance(this); // --> 以单例模式进行创建 localBroadcastManager.registerReceiver(networkReceiver, new IntentFilter("需要去过滤的信息")); // 发送消息 localBroadcastManager.sendBroadcast(Intent); // 注销 localBroadcastManager.unregisterReceiver(networkReceiver);
LocalBroadcastManager源码导读
为什么要导读LocalBroadcastManager源码呢?
其实是想让读者们知道LocalBroadcastManager使用并不是Binder机制来完成通信的。
getInstance()
public static LocalBroadcastManager getInstance(@NonNull Context context) { synchronized (mLock) { if (mInstance == null) {
mInstance = new LocalBroadcastManager(context.getApplicationContext()); // 1 --> } return mInstance;
}
} // 由注释1直接调用的方法 private LocalBroadcastManager(Context context) {
mAppContext = context;
mHandler = new Handler(context.getMainLooper()) { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_EXEC_PENDING_BROADCASTS:
executePendingBroadcasts(); break; default: super.handleMessage(msg);
}
}
};
}
那这里就是很清楚的知道,这是一个以DCL的方式,来直接完成对单例的创建,而在构造函数中,定义了一个Handler。
那我们就来做一个猜测,我们在应用内的广播本质其实是基于一个Handler的一异步传输机制。为了验证!!我们就需要去了解他的sendBroadcast(Intent)方法。
sendBroadcast(Intent)
public boolean sendBroadcast(@NonNull Intent intent) { synchronized (mReceivers) { // 拿到传递过来的Intent中保存的数据 final String action = intent.getAction(); final String type = intent.resolveTypeIfNeeded(
mAppContext.getContentResolver()); final Uri data = intent.getData(); final String scheme = intent.getScheme(); final Set<String> categories = intent.getCategories(); // 。。。。。 // 获取配置的Action ArrayList<ReceiverRecord> entries = mActions.get(intent.getAction()); if (entries != null) { if (debug) Log.v(TAG, "Action list: " + entries);
ArrayList<ReceiverRecord> receivers = null; // 。。。。。 对变量receivers的一些列操作。 // 存在接受对象时,将数据通过Handler的方式传递出去。 if (receivers != null) { for (int i=0; i<receivers.size(); i++) {
receivers.get(i).broadcasting = false;
}
mPendingBroadcasts.add(new BroadcastRecord(intent, receivers)); if (!mHandler.hasMessages(MSG_EXEC_PENDING_BROADCASTS)) {
mHandler.sendEmptyMessage(MSG_EXEC_PENDING_BROADCASTS);
} return true;
}
}
} return false;
}
通过代码已经成功验证了,其实LocalBroadcast最终基于的数据传输机制就是我们的Handler,这就是和应用间广播最大的不同之处了。
总结
-
动态广播和静态广播的区别?
- 静态广播:广播一直存在,消耗资源较大,耗电量大。
- 动态广播:广播的生命周期较为灵活,资源消耗少。响应速度快于静态广播。
- 广播同样会引发ANR的惨状,广播的耗时操作时长不允许超过10s。而且广播内一般也不会像Service和Activity一样会使用Thread来完成我们的耗时操作。
- 全局和应用内的广播两者的注册方式其实相似,但是针对的场景不同。如果需要网络、电池等服务,你就需要全局广播;如果你只需要应用内通信,那么你只需要应用内广播。
- 应用内广播(LocalBroadcast)使用的Handler的消息传输机制;应用间广播或者说是进程间广播(Broadcast)使用的则是Binder的机制。
原文链接:https://juejin.im/post/5e53da99518825490d12571f
回复列表