深入分析Android监听网络变化的坑

本文深入探讨了Android中监听网络变化时遇到的问题,即为何在注册ConnectivityManager.CONNECTIVITY_ACTION广播时会收到网络变化的广播。通过分析Android广播注册机制的源码,揭示了这其实是粘性广播机制导致的。在Android 5.0之后,粘性广播已不推荐使用,开发者可以通过BroadcastReceiver.isInitialStickyBroadcast()来判断是否为缓存的粘性广播。
摘要由CSDN通过智能技术生成

Android开发的同学都知道,在很多场景下我们需要监听网络变化,从而做一些业务逻辑比如刷新数据。于是我们会找到这样一个广播:ConnectivityManager.CONNECTIVITY_ACTION,注册一个BroadcastReceiver,添加一个ConnectivityManager.CONNECTIVITY_ACTION,就可以监听网络变化了。再看看这个action的注释:

public static final String CONNECTIVITY_ACTION
Added in API level 1
A change in network connectivity has occurred. A default connection has either been established or lost. The NetworkInfo for the affected network is 
sent as an extra; it should be consulted to see what kind of connectivity event occurred.
If this is a connection that was the result of failing over from a disconnected network, then the FAILOVER_CONNECTION boolean extra is set to true.
For a loss of connectivity, if the connectivity manager is attempting to connect (or has already connected) to another network, the NetworkInfo for
 the new network is also passed as an extra. This lets any receivers of the broadcast know that they should not necessarily tell the user that no data
 traffic will be possible. Instead, the receiver should expect another broadcast soon, indicating either that the failover attempt succeeded 
(and so there is still overall data connectivity), or that the failover attempt failed, meaning that all connectivity has been lost.
For a disconnect event, the boolean extra EXTRA_NO_CONNECTIVITY is set to true if there are no connected networks at all.
Constant Value: "android.net.conn.CONNECTIVITY_CHANGE"


注释很明确的说明了它的作用——在网络变化的时候触发!加上工程里很多地方都在用。于是觉得万无一失,需求轻松搞定。但是,悲剧就此上演!

线上反馈在网络稳定的时候也会触发该广播,排查发现是在注册广播的时候发送的。直觉告诉我这个广播的作用是只会在网络变化的时候才发送,于是怀疑是某个手机厂商修改rom导致的问题,但是试了包括nexus在内的几乎所有手机都会出现这个问题,就茫然了。注释上明明写的是网络变化的时候才会触发该广播,怎么会在注册的时候也会触发呢?

带着这个问题开始研究android广播机制的源码,重点是注册的过程。

广播注册机制本质上是订阅-发布模式。Android里用到这种机制的地方很多,比如按钮click。在Android框架中,Activity和Service都继承了ContextWrapper类,因此,我们可以在Activity或者Service的子类中调用registerReceiver函数来注册广播接收器。这里我们从Activity里发起注册。

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        IntentFilter filter = new IntentFilter();
        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        registerReceiver(netReceiver, filter);
    }
......

在MainActivity里注册了一个ConnectivityManager.CONNECTIVITY_ACTION的广播,当网络变化的时候,系统就会给对应的netReceiver发起一个网络变化的广播。

接下来,分析ContextWrapper.registerReceiver函数:

public class ContextWrapper extends Context {
    Context mBase;
    ...
    public ContextWrapper(Context base) {
        mBase = base;
    }
    @Override
    public Intent registerReceiver(
        BroadcastReceiver receiver, IntentFilter filter) {
        return mBase.registerReceiver(receiver, filter);
    }
    ...
}

ContextWrapper. registerReceiver比较简单,调用的是mBase的registerReceiver方法。mBase是一个ContextImpl的实例。

然后分析ContextImpl.registerReceiver:

class ContextImpl extends Context {
    @Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
        return registerReceiver(receiver, filter, null, null);
    }

    @Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
            String broadcastPermission, Handler scheduler) {
        return registerReceiverInternal(receiver, getUserId(),
                filter, broadcastPermission, scheduler, getOuterContext());
    }
   ....
}

可以发现最终是调到registerReceiverInternal方法


                
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值