网站优化排名分享隐迅推,wordpress微支付宝,挂别人公司做网站可以吗,医院网站建设的规划方案该系列文章总纲链接#xff1a;专题总纲目录 Android Framework 总纲 本章关键点总结 说明#xff1a; 说明#xff1a;本章节主要解读广播组件的广播发送过程。关注思维导图中左上侧部分即可。
有了前面普通广播组件 注册/注销程/广播组件的发送广播流程分析的基础专题总纲目录 Android Framework 总纲 本章关键点总结 说明 说明本章节主要解读广播组件的广播发送过程。关注思维导图中左上侧部分即可。
有了前面普通广播组件 注册/注销程/广播组件的发送广播流程分析的基础基于此接下来我们来分析LocalBroadcastManager也就是本地广播组件的 注册/注销程/广播组件的发送广播流程。
我们先对LocalBroadcastManager的引用有一个了解再详细分析其注册/注销/广播发送关键流程。
1 LocalBroadcastManager应用解读
LocalBroadcastManager是Android框架中一个非常有用的工具类它允许应用内的各个组件如Activities、Services、Fragments等之间通过广播机制进行通信而无需使用全局的Intent系统。这种通信方式被称为本地广播或应用内广播。它的主要特点和用途解读如下
作用域限制LocalBroadcastManager限制了广播的作用域在应用内部这意味着广播不会被发送到其他应用增强了数据的安全性。简化通信它提供了一种简化的通信方式使得应用内部的组件可以轻松地发送和接收消息而不需要处理复杂的Intent和Permission。解耦组件LocalBroadcastManager帮助解耦应用内的组件组件之间不需要直接引用或依赖只需注册感兴趣的广播即可。线程安全所有与LocalBroadcastManager交互的操作都是线程安全的这意味着它可以在任何线程中使用包括主线程和后台线程。异步和同步发送应用可以使用LocalBroadcastManager发送异步广播使用sendBroadcast或同步广播使用sendBroadcastSync。广播生命周期管理LocalBroadcastManager管理广播的生命周期包括注册接收器、发送广播和注销接收器。性能优化由于广播仅限于应用内部LocalBroadcastManager可以减少系统资源的消耗提高应用性能。使用场景适用于需要在应用的不同组件之间传递小量数据的场景如更新UI、同步数据。
以下是一个使用LocalBroadcastManager发送和接收本地广播的示例包含发送广播和接收广播两部分。
1.1 发送广播部分
首先我们需要一个方法来发送本地广播。这通常可以在某个事件发生时触发比如用户完成了某个操作。SendBroadcastActivity.java内如实现如下
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;public class SendBroadcastActivity extends AppCompatActivity {Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_send_broadcast);}public void sendLocalBroadcast(View view) {Intent intent new Intent(com.example.myapp.LOCAL_BROADCAST);intent.putExtra(key_message, Hello, this is a local broadcast!);// 使用LocalBroadcastManager发送本地广播LocalBroadcastManager localBroadcastManager LocalBroadcastManager.getInstance(this);localBroadcastManager.sendBroadcast(intent);}
}
1.2 接收广播部分
接下来我们需要一个组件来接收并处理这个本地广播。这里我们使用一个Service作为例子。ReceiveBroadcastService.java内容实现如下
import android.app.Service;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;public class ReceiveBroadcastService extends Service {Overridepublic void onCreate() {super.onCreate();// 创建IntentFilter并添加要接收的广播ActionIntentFilter filter new IntentFilter(com.example.myapp.LOCAL_BROADCAST);// 使用LocalBroadcastManager注册接收器LocalBroadcastManager localBroadcastManager LocalBroadcastManager.getInstance(this);localBroadcastManager.registerReceiver(broadcastReceiver, filter);}Overridepublic void onDestroy() {super.onDestroy();// 注销接收器LocalBroadcastManager localBroadcastManager LocalBroadcastManager.getInstance(this);localBroadcastManager.unregisterReceiver(broadcastReceiver);}Overridepublic IBinder onBind(Intent intent) {// 不提供绑定服务返回nullreturn null;}private BroadcastReceiver broadcastReceiver new BroadcastReceiver() {Overridepublic void onReceive(Context context, Intent intent) {String action intent.getAction();if (com.example.myapp.LOCAL_BROADCAST.equals(action)) {String message intent.getStringExtra(key_message);// 处理接收到的广播比如显示日志、更新UI等}}};
}
1.3 对应的AndroidManifest.xml配置文件部分
对应的AndroidManifest.xml配置文件参考如下:
manifest xmlns:androidhttp://schemas.android.com/apk/res/androidpackagecom.example.myappapplicationandroid:allowBackuptrueandroid:iconmipmap/ic_launcherandroid:labelstring/app_nameandroid:roundIconmipmap/ic_launcher_roundandroid:supportsRtltrueandroid:themestyle/AppTheme!-- 发送广播的Activity --activity android:name.SendBroadcastActivityintent-filteraction android:nameandroid.intent.action.MAIN /category android:nameandroid.intent.category.LAUNCHER //intent-filter/activity!-- 接收广播的Service --service android:name.ReceiveBroadcastService //application
/manifest
2 LocalBroadcastManager解读
基于上面的案例demo我们主要分析几个关键代码及对应流程
localBroadcastManager LocalBroadcastManager.getInstance(this); 获取LocalBroadcastManager的单例对象流程localBroadcastManager.registerReceiver(broadcastReceiver, filter);注册流程localBroadcastManager.unregisterReceiver(broadcastReceiver);注销流程localBroadcastManager.sendBroadcast(intent);广播发送流程
2.1 获取LocalBroadcastManager的单例对象流程解读
LocalBroadcastManager的单例模式设计和构造器实现代码如下
//LocalBroadcastManager// 单例模式public static LocalBroadcastManager getInstance(Context context) {synchronized (mLock) {if (mInstance null) {mInstance new LocalBroadcastManager(context.getApplicationContext());}return mInstance;}}// 构造函数private LocalBroadcastManager(Context context) {mAppContext context;mHandler new Handler(context.getMainLooper()) {Overridepublic void handleMessage(Message msg) {switch (msg.what) {case MSG_EXEC_PENDING_BROADCASTS:// 调用executePendingBroadcasts方法来执行挂起的广播executePendingBroadcasts(); break;default:super.handleMessage(msg);}}};}
这里在构造期中初始化了一个Handler用于消息处理。
2.2 LocalBroadcastManager注册接收器流程解读
注册receiver流程为registerReceiver方法代码实现如下
//LocalBroadcastManagerpublic void registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {synchronized (mReceivers) {// 创建一个新的ReceiverRecord对象它包含了IntentFilter和BroadcastReceiver的引用ReceiverRecord entry new ReceiverRecord(filter, receiver);// 获取与该BroadcastReceiver关联的IntentFilter列表ArrayListIntentFilter filters mReceivers.get(receiver);if (filters null) {// 如果列表不存在则创建一个新的列表并将其与BroadcastReceiver关联filters new ArrayListIntentFilter(1);mReceivers.put(receiver, filters);}// 将新的IntentFilter添加到列表中filters.add(filter);// 遍历IntentFilter中的所有动作for (int i 0; i filter.countActions(); i) {String action filter.getAction(i);// 获取与该动作关联的ReceiverRecord列表ArrayListReceiverRecord entries mActions.get(action);if (entries null) {// 如果列表不存在则创建一个新的列表并将其与动作关联entries new ArrayListReceiverRecord(1);mActions.put(action, entries);}// 将ReceiverRecord添加到与动作关联的列表中entries.add(entry);}}}registerReceiver方法通过维护两个映射mReceivers和mActions来管理BroadcastReceiver的注册信息。这种方法允许LocalBroadcastManager高效地处理本地广播的注册和分发确保只有匹配特定IntentFilter的广播被发送到对应的BroadcastReceiver。
2.3 LocalBroadcastManager注销接收器流程解读
注销receiver流程为unregisterReceiver方法代码实现如下
//LocalBroadcastManagerpublic void unregisterReceiver(BroadcastReceiver receiver) {synchronized (mReceivers) {// 从mReceivers映射中移除与BroadcastReceiver关联的IntentFilter列表ArrayListIntentFilter filters mReceivers.remove(receiver);if (filters null) {// 如果没有找到对应的IntentFilter列表直接返回return;}for (int i 0; i filters.size(); i) {// 遍历每个IntentFilterIntentFilter filter filters.get(i);for (int j 0; j filter.countActions(); j) {// 遍历IntentFilter中的每个动作String action filter.getAction(j);ArrayListReceiverRecord receivers mActions.get(action);if (receivers ! null) {// 在与动作关联的ReceiverRecord列表中查找对应的BroadcastReceiverfor (int k 0; k receivers.size(); k) {if (receivers.get(k).receiver receiver) {// 如果找到从列表中移除对应的ReceiverRecordreceivers.remove(k);k--; // 调整索引因为列表大小变了}}// 如果某个动作的所有ReceiverRecord都被移除了那么也移除这个动作if (receivers.size() 0) {mActions.remove(action);}}}}}}
unregisterReceiver方法通过遍历mReceivers映射和mActions映射来注销BroadcastReceiver。它确保了所有与BroadcastReceiver关联的IntentFilter和动作都被正确地移除保持了LocalBroadcastManager内部状态的一致性。这个过程对于维护LocalBroadcastManager的注册表非常重要确保了广播能够准确地发送给正确的接收器。
2.4 LocalBroadcastManager发送广播流程解读
2.4.1 sendBroadcast方法解读
发送广播流程为sendBroadcast方法代码实现如下
//LocalBroadcastManager//关键流程step1public boolean sendBroadcast(Intent intent) {synchronized (mReceivers) {// 获取Intent中的动作final String action intent.getAction();// 根据ContentResolver解析Intent的数据类型final String type intent.resolveTypeIfNeeded(mAppContext.getContentResolver());// 获取Intent中的数据Urifinal Uri data intent.getData();// 获取Intent中的schemefinal String scheme intent.getScheme();// 获取Intent中的categoriesfinal SetString categories intent.getCategories();// 根据动作从mActions映射中获取对应的ReceiverRecord列表ArrayListReceiverRecord entries mActions.get(intent.getAction());if (entries ! null) {// 如果有记录准备发送广播ArrayListReceiverRecord receivers null;for (int i 0; i entries.size(); i) {ReceiverRecord receiver entries.get(i);// 如果ReceiverRecord正在广播中则跳过if (receiver.broadcasting) {continue;}// 匹配IntentFilter和Intentint match receiver.filter.match(action, type, scheme, data, categories, LocalBroadcastManager);// 如果匹配成功if (match 0) {if (receivers null) {receivers new ArrayListReceiverRecord();}receivers.add(receiver);receiver.broadcasting true; // 标记为正在广播}}// 如果有匹配的接收器if (receivers ! null) {for (int i 0; i receivers.size(); i) {receivers.get(i).broadcasting false; // 重置广播状态}// 将广播记录添加到待处理列表mPendingBroadcasts.add(new BroadcastRecord(intent, receivers));// 如果Handler没有正在处理的消息则发送一个消息以执行待处理的广播if (!mHandler.hasMessages(MSG_EXEC_PENDING_BROADCASTS)) {mHandler.sendEmptyMessage(MSG_EXEC_PENDING_BROADCASTS);}return true; // 返回true表示广播已发送}}}return false; // 返回false表示没有匹配的接收器}//消息处理流程private LocalBroadcastManager(Context context) {mAppContext context;mHandler new Handler(context.getMainLooper()) {Overridepublic void handleMessage(Message msg) {switch (msg.what) {case MSG_EXEC_PENDING_BROADCASTS:// 调用executePendingBroadcasts方法来执行挂起的广播executePendingBroadcasts(); break;default:super.handleMessage(msg);}}};}//关键流程step3private void executePendingBroadcasts() {while (true) {BroadcastRecord[] brs null;synchronized (mReceivers) {// 获取挂起广播的数量final int N mPendingBroadcasts.size();// 如果没有挂起的广播退出方法if (N 0) {return;}// 创建一个数组来存储挂起的广播记录brs new BroadcastRecord[N];// 将挂起的广播记录复制到数组中mPendingBroadcasts.toArray(brs);// 清空挂起的广播列表mPendingBroadcasts.clear();}// 遍历所有挂起的广播记录for (int i 0; i brs.length; i) {BroadcastRecord br brs[i];// 遍历广播记录中的所有接收器for (int j 0; j br.receivers.size(); j) {// 获取ReceiverRecordReceiverRecord receiverRecord br.receivers.get(j);// 调用BroadcastReceiver的onReceive方法receiverRecord.receiver.onReceive(mAppContext, br.intent);}}}}
sendBroadcast方法通过匹配Intent和IntentFilter来找到所有感兴趣的BroadcastReceiver并将它们添加到待处理列表中。然后它使用Handler来异步执行这些广播确保广播的发送不会阻塞当前线程。这种方法允许LocalBroadcastManager在应用内部高效地分发本地广播。
sendBroadcast最后是通过handler消息机制调用executePendingBroadcasts方法来完成处理的该方法负责执行所有挂起的本地广播。它通过遍历挂起的广播列表为每个广播调用相应的BroadcastReceiver的onReceive方法。这个方法确保了所有本地广播都能被正确处理即使在主线程繁忙时也能异步执行。
2.4.2 sendBroadcastSync方法解读
同步发送广播流程为sendBroadcastSync方法代码实现如下
//LocalBroadcastManagerpublic void sendBroadcastSync(Intent intent) {// 首先尝试异步发送广播if (sendBroadcast(intent)) {// 如果sendBroadcast方法返回true表示广播已经成功放入待处理队列// 然后调用executePendingBroadcasts方法来同步执行所有挂起的广播executePendingBroadcasts();}}
sendBroadcastSync方法提供了一个同步发送本地广播的机制。与sendBroadcast方法不同sendBroadcastSync会立即执行挂起的广播而不是将它们放入消息队列等待主线程处理。这确保了广播的接收器能够立即接收到广播这对于需要快速响应的场景非常有用。
这种方法的同步特性意味着它可能会阻塞当前线程直到所有挂起的广播都被处理完毕。因此在使用sendBroadcastSync时需要谨慎以避免在主线程中引起不必要的延迟。通常sendBroadcastSync用于测试或后台线程中以确保广播能够立即被处理。
2.4.3 sendBroadcastSync与sendBroadcast的区别
两者的区别主要有以下几点
同步执行sendBroadcastSync方法在发送广播后会立即调用executePendingBroadcasts方法来同步执行所有挂起的广播。这意味着BroadcastReceiver的onReceive方法会在当前方法调用栈中被执行而不是被放入消息队列等待。sendBroadcast方法则需要消息等待。立即响应使用sendBroadcastSync可以确保广播的接收器立即接收到广播这对于需要快速响应的事件处理非常重要。阻塞性sendBroadcastSync可能会导致当前线程阻塞直到所有挂起的广播都被处理完毕因为它是同步执行的。而sendBroadcast是异步的。适用场景sendBroadcastSync适用于那些需要立即处理广播的场景而sendBroadcast则适用于那些可以异步处理广播的场景。
总之sendBroadcastSync方法提供了一种机制允许应用在发送本地广播后立即同步处理这些广播而不是等待主线程的消息队列中的其他消息。这与sendBroadcast方法形成对比后者是异步的它将广播放入消息队列中等待主线程在适当的时候处理。选择使用哪种方法取决于应用的具体需求是否需要立即处理广播或者可以容忍一定的延迟。