在实际开发中在我们的 app 中几乎都会用到网络,有时我们需要在网络改变时给用户一些体验上的友好提示,比如:我们在视频播放时,由wifi切换到4G网络时,要给用户提示,当前为 4G 网络状态,注意流量的使用等.

网络变化的监听

实现方法,我们通过添加广播的方式,监听网络变化.
1. 添加网络状态权限:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
  1. 创建网络变化监听广播
public class NetStatusBroadcast extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
    //当网络变化时,该广播中该方法会被回调.
    }
}
  1. 在 AndroidManifest.xml 中添加广播的配置信息,如下:
<receiver android:name=".NetStatusBroadcast">
    <intent-filter>
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
    </intent-filter>
</receiver>

实现这个功能很简单,就上面这个几行代码就可以实现.

在注册网络变化监听时,建议是使用动态注册方式.不要忘记当程序退出时记得你,取消注册.

IntentFilter filter = new IntentFilter();
        filter.addAction(NetStatusBroadcast.NET_CHANGE_ACTION);
        mBroadcast = new NetStatusBroadcast();
        this.registerReceiver(mBroadcast,filter);
下面是我也的一个网络变化相应的工具,如果有什么地方些的不好或有错误请指出来,一起交流,进步.

工具下载地址:https://github.com/CNCFOX/NetStatus

思路:

先介绍几个类:
  1. NetType 是一个枚举,在这里存放这网络状态:
public enum NetType {
    NO_NET,             //没有网络
    NET_WIFI,           //wifi 网络
    NET_3G_4G           //移动网络  3G 4G
}
  1. NetTools 类,在该类中可以判断网络是否可用,获取当前网络状态.
    先看一下代码(代码中有注释,不过多解释):要说明一下,在使用前,一定要在使用前调用init()方法设置Context.
public class NetTools {
    /**
     * 获取连接服务
     * @param context :
     * @return
     */
    private static ConnectivityManager getConnectivityMannager(Context context){
        return (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    }

    private static Context sCtx;

    /**
     * 初始化 Context ,一般建议在 Application 中进行设置
     * @param context
     */
    public static void init(Context context){

        if (sCtx != null) return;

        if (context instanceof Activity){
            sCtx = ((Activity) context).getApplication();
            return;
        }

        if (context instanceof Service){
            sCtx = ((Service) context).getApplication();
            return;
        }
        sCtx = context.getApplicationContext();
    }

    /**
     * 判断网络是否连接
     * <br/> 在使用这个方法时,一定要先通过#NetTools init() 方法中进行Context 设置
     * @return
     */
    public static boolean isConnected(){
        return isConnected(sCtx);
    }

    /**
     * 判断网络是否连接
     * @param context
     * @return
     */
    public static boolean isConnected(Context context){
        if (context == null){
            throw new RuntimeException(NetTools.class.getSimpleName() + " # Content  is null");
        }
        init(context);
        ConnectivityManager connectivityManager = getConnectivityMannager(sCtx);
        NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
        return networkInfo != null && networkInfo.isConnected();
    }


    /**
     * 获取网络状态
     * <br/> 在使用这个方法时,一定要先通过#NetTools init() 方法中进行 Context 设置
     * @return
     * <br/> enum NetType
     * <br/> #NO_NET : 没有网络
     * <br/> NET_WIFI : wifi 网络
     * <br/> NET_3G_4G : 移动网络  3G 4G
     */
    public static NetType netType(){
        return netType(sCtx);
    }

    /**
     * 获取网络状态
     * @return
     * <br/> enum NetType
     * <br/> #NO_NET : 没有网络
     * <br/> NET_WIFI : wifi 网络
     * <br/> NET_3G_4G : 移动网络  3G 4G
     */
    public static NetType netType(Context context){

        if (context == null){
            throw new RuntimeException(NetTools.class.getSimpleName() + " # Content  is null");
        }

        init(context);
        ConnectivityManager connectivityManager = getConnectivityMannager(sCtx);

        NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();

        if (networkInfo == null) return NetType.NO_NET;

        int type = networkInfo.getType();
        if (type == ConnectivityManager.TYPE_MOBILE) return NetType.NET_3G_4G;

        if (type == ConnectivityManager.TYPE_WIFI) return NetType.NET_WIFI;

        return NetType.NO_NET;
    }
}
  1. NetObserver 类,管理注册监听类.
public class NetObserver {

    private static NetStatusReceiver sGlobalReceiver;
    private static NetStatusReceiver sNetStatusReceiver;

    /**
     * 注册全局回调,全局网络状态改变时,每次都会回调,主要用于设置全局网络状态使用
     * @param netStatusReceiver
     */
    public static synchronized void registerlGlobalReceiver(NetStatusReceiver netStatusReceiver){
        sGlobalReceiver = netStatusReceiver;
    }

    /**
     * 获取全局回调
     * @return
     */
    public static NetStatusReceiver getGlobalReceiver(){
        return sGlobalReceiver;
    }

    /**
     * 取消注册的全局回调
     */
    public static void unGlobalRegister(){
        sGlobalReceiver = null;
    }

    /**
     * 注册回调
     * @param netStatusReceiver
     */
    public static synchronized void register(NetStatusReceiver netStatusReceiver){
        sNetStatusReceiver = netStatusReceiver;
    }

    /**
     * 取消
     */
    public static void unregister(){
        sNetStatusReceiver = null;
    }

    public static NetStatusReceiver  getNetStatusReceiver(){
        return sNetStatusReceiver;
    }
}

4.NetStatusReceiver 接口.

public interface NetStatusReceiver {

    void netStatusChanged(NetType netType);
}

看完这几个类,可能已经知道大概的思路了,下面介绍一下我的思路.

在 AndroidManifest.xml 中添加注册网络状态改变监听广播:这里推荐使用动态注册方式,如果使用动态注册,在程序退出时不要忘记取消注册

  • 静态注册
<receiver android:name=".netutils.NetStatusBroadcast">
    <intent-filter>
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
    </intent-filter>
</receiver>
  • 动态注册
IntentFilter filter = new IntentFilter();
        filter.addAction(NetStatusBroadcast.NET_CHANGE_ACTION);
        mBroadcast = new NetStatusBroadcast();
        this.registerReceiver(mBroadcast,filter);
注意: 不要忘记添加权限:<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
  1. ### 实现网络状态改变接收广播:
public class NetStatusBroadcast extends BroadcastReceiver {
    private static final String TAG = "NetStatusBroadcast";
    public  static  final String NET_CHANGE_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
    /** 有些时候网络改变时会调用两次,使用这个变了记录上一次改变时的网络状态,如果和上一次相同,则不向下通知 */
    private static NetType sNetTypeCache = null;
    @Override
    public void onReceive(Context context, Intent intent) {
        NetTools.init(context);
        Log.i(TAG,"Cache Net :" + sNetTypeCache );
        if (NetTools.netType() == sNetTypeCache) return;
        Log.i(TAG,"Changed net :" + NetTools.netType());
        if (intent.getAction().equals(NET_CHANGE_ACTION)){
            sNetTypeCache = NetTools.netType();

            NetStatusReceiver receiver = NetObserver.getGlobalReceiver();
            if (receiver != null) receiver.netStatusChanged(sNetTypeCache);

            receiver = NetObserver.getNetStatusReceiver();
            if (receiver != null) receiver.netStatusChanged(sNetTypeCache);
        }
    }
}
  1. ### 添加注册和取消注册:
    建议在 onResume 中添加注册,在 onDestroy 中添加取消注册.
ublic class OtherActivity extends Activity {

    private Button mBtnFinsh;

    private NetStatusReceiver receiver = new NetStatusReceiver() {
        @Override
        public void netStatusChanged(NetType netType) {
            Toast.makeText(OtherActivity.this,name + "OtherActivity page net type" + netType ,Toast.LENGTH_SHORT).show();

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_other);
        mBtnFinsh = (Button) findViewById(R.id.btn_finsh);
    }

    @Override
    protected void onResume() {
        super.onResume();
        NetObserver.register(receiver);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        NetObserver.unregister();
    }

    public void exitActivity(View view) {
        finish();
    }
}

详细内容请参考工程代码工具下载地址:https://github.com/CNCFOX/NetStatus