Android监听网络状态

突然觉得这是一个非常常用的一个功能,监听手机的网络状态,实时弹出一个弹窗,点击跳转到设置页面,网络正常了就自动隐藏弹窗,嗯,非常合理的一个需求,做!
那么首先就是写一个广播咯,毕竟是监听网络情况的:

	public class NetReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
            boolean isConnected = NetUtils.isNetworkConnected(context);
            System.out.println("网络状态:" + isConnected);
            System.out.println("wifi状态:" + NetUtils.isWifiConnected(context));
            System.out.println("移动网络状态:" + NetUtils.isMobileConnected(context));
            System.out.println("网络连接类型:" + NetUtils.getConnectedType(context));
            if (isConnected) {
                EventBus.getDefault().postSticky(new NetEvent(true));
                if (onNetConnect != null) {
                    onNetConnect.onNetConnect();
                }
            } else {
                EventBus.getDefault().postSticky(new NetEvent(false));
                if (onNetConnect != null) {
                    onNetConnect.onNetDisConnect();
                }
            }
        }
    }


    public interface OnNetConnect {
        void onNetConnect();

        void onNetDisConnect();
    }

    private OnNetConnect onNetConnect;

    public void setOnNetConnect(OnNetConnect onNetConnect) {
        this.onNetConnect = onNetConnect;
    }

}

在类中声明接口是为了设置广播事件的回调代码,后来想了一下,用Eventbus来发送时间就好了,外面设置广播的时候也就不需要实现接口了,接口可以自行删掉。有一点要声明一下,因为广播事件是要所有的页面都响应的,但是Eventbus的普通事件是只有在创建之后才能接收到,所以使用的是黏性事件,就酱紫。
然后就是注册广播咯,放哪里呢,application里比较合适。

 private NetReceiver mReceiver;

    private void initReceive() {
        mReceiver = new NetReceiver();
        IntentFilter mFilter = new IntentFilter();
        mFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        registerReceiver(mReceiver, mFilter);
    }

使用动态注册,在Application的onCreate方法里面实现初始化,记得在销毁的时候注销监听。

	@Override
    public void onTerminate() {
        unregisterReceiver(mReceiver);
        super.onTerminate();
    }

广播的注册和注销实现了,如果在Application中实现了接口,大概已经能看到效果了,但是这不是我想要的。
接着就是activity中弹出那个常驻的弹窗然后跳转了。

private PopupWindow mWindowNet;
private void showNetTip(final Activity activity, View parent) {
        View view = View.inflate(activity, R.layout.layout_netbar, null);
        mWindowNet = new PopupWindow(view, ViewGroup.LayoutParams.MATCH_PARENT, SinMinUtils.dp2px(activity, 40));
        view.findViewById(R.id.net_view_rl).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                startToSettings(activity);
            }
        });
        mWindowNet.setOutsideTouchable(false);
        mWindowNet.setTouchable(true);
        mWindowNet.showAtLocation(parent, Gravity.TOP, 0, SinMinUtils.dp2px(activity, 45));
    }
  
    public void hideNetTip(PopupWindow windowNet) {
        if (windowNet != null) {
            windowNet.dismiss();
            windowNet = null;
        }
    }
     /**
	 * 设置网络
	 * @param paramContext
	 */
	public void startToSettings(Context paramContext) {
		if (paramContext == null)
			return;
		try {
			if (Build.VERSION.SDK_INT > 10) {
				paramContext.startActivity(new Intent(
						"android.settings.SETTINGS"));
				return;
			}
		} catch (Exception localException) {
			localException.printStackTrace();
			return;
		}
		paramContext.startActivity(new Intent(
				"android.settings.WIRELESS_SETTINGS"));
	}

弹窗的高度和显示的位置我都限制死了,是为了让每个页面显示的一样,使用PopupWindow是因为我不愿在activity的layout中设置这个弹窗的,不仅layout会莫名其妙多了一层relativelayout,万一有个地方错漏了没加上不是要崩了?才不是偷懒!写着写着突然想到,我这个要是在activity中实现,那我不还是要写到崩溃,得,直接弄到BaseActivity中。

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        if (!EventBus.getDefault().isRegistered(mActivity)) {
            EventBus.getDefault().register(mActivity);
        }
    }
     @Override
    protected void onDestroy() {
        hideNetTip(mWindowNet);
        if (EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().unregister(this);
        }
    }

其他代码我都删了,看个大概就成了,在BaseActivity中初始化EventBus。

    @Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
    public void getStickyEvent(BaseStickyEvent event) {
        setStickyEvent(event);
        if (event instanceof NetEvent) {
            NetEvent netEvent = (NetEvent) event;
            if (netEvent.isNet()) {
                mBaseHandler.sendEmptyMessageDelayed(AppFields.HIDE_NET_TIP, 300);
                if (!isFirst) {
                    ToastUtil.showShort(mActivity, "已经连接网络");
                    setNetEvent();
                } else {
                    isFirst = false;
                }
            } else {
                mBaseHandler.sendEmptyMessageDelayed(AppFields.SHOW_NET_TIP, 300);
            }
        }

    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void getCommonEvent(BaseCommonEvent event) {
        setCommonEvent(event);
    }

常规的EventBus的使用方法,不同的是我只写了两个,一个是给普通事件用的,一个是写粘性事件用的,里面再通过判断是哪个子类实现的BaseEvent然后写业务代码。setNetEvent()和setCommonEvent(event)是我再BaseActivity中声明的抽象方法。

 private boolean isFirst = true;
    /**
     * base类的handler
     */
    protected Handler mBaseHandler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            switch (msg.what) {
                case AppFields.SHOW_NET_TIP:
                    showNetTip(mActivity, getWindow().getDecorView());
                    break;
                case AppFields.HIDE_NET_TIP:
                    PopWindowUtils.hideNetTip(mWindowNet);
                    break;
                default:
                    break;
            }
            return false;
        }
    });

isFirst 的作用是什么?因为使用的是粘性事件,有时候打开页面就会弹出一个toast极其不合理,那我就加了一个flag去判断一下咯。然后比较神奇的是我事件都是通过Handler 发送延迟事件来显示和隐藏弹窗,老实说,其实我不想的,事先我是直接在Handler调用的地方直接显示弹窗的,但是实际过程中出现了一个bug,大概就是说,那啥大兄弟,你这个页面还没初始化完毕,弹窗弹不出来,给你报个错,你改一下。当时想的是那我判断一下页面初始化的进度,完成了再去显示。然后发现挺麻烦的,干脆我延迟一下,就好了。
完成!这就是完整的一个实现过程,可能有一些不合理的地方,请各位大佬不吝赐教,谢谢啦!

你可能感兴趣的:(Android监听网络状态)