Android必知必会的四大组件 -- Broadcast Receiver篇

前言

广播,在咱们的应用中起着一个很是重要的角色。就好比说咱们常用的IntentIntentFilter,就有着广播的做用。java

在个人Android工具包项目中就集成了网络广播的动态注册。android

思惟导图

生命周期

由于没有直接的图示能够上,并且Broadcast中并无onCreateonDestroy这样方法,只能经过官方文档验证。 git

图中的圈红框的加粗文字大概意思就是,使用静态广播进行注册,那么每接受到一次信息,他就不复存在了,也就是须要重建。其它方式构建的生命周期,与关联的 Activity中的具体操做相关。

在Android 8.0之后已经不在支持静态广播了github

两种广播

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);
复制代码

应用内广播

  1. 优势:
    • 发送的广播只会在本身的App内传播,不会泄漏给其余App,保障了数据的安全性。
    • 没法接受到其余App的广播,也就省去各类麻烦事。
    • 相较于全局广播效率更高。
  2. 使用方法
//注册
networkReceiver = new NetworkReceiver();
localBroadcastManager = LocalBroadcastManager.getInstance(this); // --> 以单例模式进行建立
localBroadcastManager.registerReceiver(networkReceiver, new IntentFilter("须要去过滤的信息"));

// 发送消息
localBroadcastManager.sendBroadcast(Intent);

// 注销
localBroadcastManager.unregisterReceiver(networkReceiver);
复制代码

LocalBroadcastManager源码导读

为何要导读LocalBroadcastManager源码呢?ide

实际上是想让读者们知道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,这就是和应用间广播最大的不一样之处了。

总结

  1. 动态广播和静态广播的区别?
    • 静态广播:广播一直存在,消耗资源较大,耗电量大。
    • 动态广播:广播的生命周期较为灵活,资源消耗少。响应速度快于静态广播。
  2. 广播一样会引起ANR的惨状,广播的耗时操做时长不容许超过10s。并且广播内通常也不会像ServiceActivity同样会使用Thread来完成咱们的耗时操做。
  3. 全局和应用内的广播二者的注册方式其实类似,可是针对的场景不一样。若是须要网络、电池等服务,你就须要全局广播;若是你只须要应用内通讯,那么你只须要应用内广播。
  4. 应用内广播(LocalBroadcast)使用的Handler的消息传输机制;应用间广播或者说是进程间广播(Broadcast)使用的则是Binder的机制。

以上就是个人学习成果,若是有什么我没有思考到的地方或是文章内存在错误,欢迎与我分享。


相关文章推荐:

Android必知必会的四大组件 -- Service篇

Glide都在用的LruCache,你会几分?

Android事件分发机制,你了解过吗?

相关文章
相关标签/搜索