10分鐘讓你實現(xiàn)在APP中對網(wǎng)絡(luò)狀態(tài)變化進行全局提示
- 永遠不要期望用戶按照你預(yù)設(shè)的步驟操作 APP
一個新項目剛剛開始推廣工作,市場人員向我抱怨用戶使用時總會出現(xiàn)各種各樣的問題,大部分問題都是因為用戶操作不當導(dǎo)致的,但是在用戶眼中的結(jié)論就是“你們的 APP 不好用”。
舉一個例子,有的用戶在使用時禁用了 APP 訪問移動網(wǎng)絡(luò),或者有的用戶干脆都沒有打開移動數(shù)據(jù)開關(guān)或者 WIFI 開關(guān)。但是作為開發(fā)人員,我們應(yīng)該避免用戶思考,當用戶使用出現(xiàn)問題時,APP 應(yīng)該能夠引導(dǎo)用戶前往設(shè)置,故有此文。
我們希望當用戶網(wǎng)絡(luò)連接不可用時,及時提醒用戶當前的網(wǎng)絡(luò)狀態(tài)。當連接恢復(fù)時,將提示用的視圖隱藏,并且我們希望這個提示視圖可以工作在所有需要網(wǎng)絡(luò)的頁面中。
思路如下:使用 BaseActivity ,所有頁面繼承該文件,在該文件中實現(xiàn)根據(jù)網(wǎng)絡(luò)狀態(tài)顯示提示、隱藏提示。
好了,廢話少說,show u the code。
1. 實現(xiàn)監(jiān)聽網(wǎng)絡(luò)狀態(tài)變更的廣播接收器
我們使用廣播接收器接收網(wǎng)絡(luò)變化的 Intent,這里直接使用靜態(tài)注冊的方法,因為我們不需要在每個頁面單獨注冊這個 Receiver,那太重量級了。
NetworkConnectChangedReceiver.java
- public class NetworkConnectChangedReceiver extends BroadcastReceiver {
- private static final String TAG = "NetworkConnectChanged";
- @Override
- public void onReceive(Context context, Intent intent) {
- //**判斷當前的網(wǎng)絡(luò)連接狀態(tài)是否可用*/
- boolean isConnected = NetUtils.isConnected(context);
- Log.d(TAG, "onReceive: 當前網(wǎng)絡(luò) " + isConnected);
- EventBus.getDefault().post(new NetworkChangeEvent(isConnected));
- }
- }
事件Event:
- public class NetworkChangeEvent {
- public boolean isConnected; //是否存在網(wǎng)絡(luò)
- public NetworkChangeEvent(boolean isConnected) {
- this.isConnected = isConnected;
- }
- }
判斷網(wǎng)絡(luò)連接是否可用:
- /**
- * 判斷網(wǎng)絡(luò)是否連接
- * @param context
- * @return
- */
- public static boolean isConnected(Context context) {
- ConnectivityManager connectivity = (ConnectivityManager) context
- .getSystemService(Context.CONNECTIVITY_SERVICE);
- if (null != connectivity) {
- NetworkInfo info = connectivity.getActiveNetworkInfo();
- if (null != info && info.isConnected()) {
- if (info.getState() == NetworkInfo.State.CONNECTED) {
- return true;
- }
- }
- }
- return false;
- }
靜態(tài)注冊Receiver:
- <receiver android:name=".receiver.NetworkConnectChangedReceiver">
- <intent-filter>
- <action android:name="android.NET.conn.CONNECTIVITY_CHANGE" />
- <action android:name="android.Net.wifi.WIFI_STATE_CHANGED" />
- <action android:name="android.net.wifi.STATE_CHANGE" />
- </intent-filter>
- </receiver>
2. 在 BaseActivity中監(jiān)聽事件并處理提示視圖
看到 EventBus 的時候你是不是已經(jīng)知道我的實現(xiàn)方式了(笑 XD),是的就是那個已經(jīng)很久沒人提了的 EventBus。當然還可以使用觀察者模式來實現(xiàn),這樣就不用依賴第三方庫了,但是我們需要的是快速實現(xiàn),且對原有代碼盡可能少的改動,引入觀察者模式顯然不如直接拿 EventBus來的方便。
BaseActivity.java
- public class BaseActivity extends Activity {
- protected Context mContext;
- protected ACache mACache;
- protected boolean mCheckNetWork = true; //默認檢查網(wǎng)絡(luò)狀態(tài)
- View mTipView;
- WindowManager mWindowManager;
- WindowManager.LayoutParams mLayoutParams;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- mContext = this;
- this.mACache = ACache.get(mContext);
- MyApp.addActivity(this);
- initTipView();//初始化提示View
- EventBus.getDefault().register(this);
- }
- @Override
- protected void onResume() {
- super.onResume();
- MobclickAgent.onResume(this);
- //在無網(wǎng)絡(luò)情況下打開APP時,系統(tǒng)不會發(fā)送網(wǎng)絡(luò)狀況變更的Intent,需要自己手動檢查
- hasNetWork(NetUtils.isConnected(mContext));
- }
- @Override
- protected void onPause() {
- super.onPause();
- MobclickAgent.onPause(this);
- }
- @Override
- protected void onDestroy() {
- super.onDestroy();
- MyApp.removeActivity(this);
- EventBus.getDefault().unregister(this);
- }
- @Override
- public void finish() {
- super.finish();
- //當提示View被動態(tài)添加后直接關(guān)閉頁面會導(dǎo)致該View內(nèi)存溢出,所以需要在finish時移除
- if (mTipView != null && mTipView.getParent() != null) {
- mWindowManager.removeView(mTipView);
- }
- }
- @Subscribe(threadMode = ThreadMode.MAIN)
- public void onNetworkChangeEvent(NetworkChangeEvent event) {
- hasNetWork(event.isConnected);
- }
- private void hasNetWork(boolean has) {
- if (isCheckNetWork()) {
- if (has) {
- if (mTipView != null && mTipView.getParent() != null) {
- mWindowManager.removeView(mTipView);
- }
- } else {
- if (mTipView.getParent() == null) {
- mWindowManager.addView(mTipView, mLayoutParams);
- }
- }
- }
- }
- public void setCheckNetWork(boolean checkNetWork) {
- mCheckNetWork = checkNetWork;
- }
- public boolean isCheckNetWork() {
- return mCheckNetWork;
- }
- private void initTipView() {
- LayoutInflater inflater = getLayoutInflater();
- mTipView = inflater.inflate(R.layout.layout_network_tip, null); //提示View布局
- mWindowManager = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
- mLayoutParams = new WindowManager.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT,
- WindowManager.LayoutParams.TYPE_APPLICATION,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
- PixelFormat.TRANSLUCENT);
- //使用非CENTER時,可以通過設(shè)置XY的值來改變View的位置
- mLayoutParams.gravity = Gravity.TOP;
- mLayoutParams.x = 0;
- mLayoutParams.y = 0;
- }
- }
默認所有繼承 BaseActivity 的頁面當網(wǎng)絡(luò)狀況變化活無網(wǎng)絡(luò)時都會顯示提示,如果某個頁面不需要網(wǎng)絡(luò)狀態(tài)提示,可以在該頁面 onCreate 方法中調(diào)用 setCheckNetWork(false) 即可。
由于我全部頁面都有一個50dp高度的 toolbar,所以我直接在 R.layout.layout_network_tip 文件中設(shè)置了上邊距。你也可以在 BaseActivity 中通過方法來設(shè)置 mLayoutParams.x = 0;mLayoutParams.y = 0; 來使每個頁面動態(tài)設(shè)置提示的位置。
最終效果如下圖:
ToDo
所有頁面在網(wǎng)絡(luò)鏈接恢復(fù)后應(yīng)該可以自動重新發(fā)起網(wǎng)絡(luò)請求,實現(xiàn)原理其實也很簡單,在BaseActivity中增加一個reConnect()的方法,在網(wǎng)絡(luò)恢復(fù)去除提示View的時候調(diào)用。在各個頁面中重寫該方法即可。