突然觉得这是一个非常常用的一个功能,监听手机的网络状态,实时弹出一个弹窗,点击跳转到设置页面,网络正常了就自动隐藏弹窗,嗯,非常合理的一个需求,做!
那么首先就是写一个广播咯,毕竟是监听网络情况的:
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,大概就是说,那啥大兄弟,你这个页面还没初始化完毕,弹窗弹不出来,给你报个错,你改一下。当时想的是那我判断一下页面初始化的进度,完成了再去显示。然后发现挺麻烦的,干脆我延迟一下,就好了。
完成!这就是完整的一个实现过程,可能有一些不合理的地方,请各位大佬不吝赐教,谢谢啦!