android 自定義網路變化時全域性提醒
前言:今天在鴻洋大神的公眾號中看到一篇文章,叫10分鐘讓你實現在APP中對網路狀態變化進行全域性提醒。這在APP開發中是一個硬性需求,雖然我開發的app並沒有要求,但我覺得這個功能有必要親手實現一下。當然我也借鑑了作者的一些思路
參考文章:https://mp.weixin.qq.com/s/W9U7uzXRYcqCmgbX3gbbKg
實現思路:1、定時獲取當前網路狀態
2、利用廣播發送當前網路狀態,並且觸發網路狀態改變的監聽
3、在baseActivity中實現網路狀態改變的監聽,並作出相應的響應(例如顯示沒有網路的佈局)
程式碼實現:
.定義接收網路變化的廣播,廣播我這邊用的的動態廣播,本來也打算用靜態廣播的但是看別人的評論說,android P下面有問題,所以就沒用了
public class CheckNetworkStatusChangeReceiver extends BroadcastReceiver { public static final String EVENT = "event"; public static final String ACTION="action"; private CheckNetworkStatusChangeListener mCheckNetworkStatusChangeListener; public CheckNetworkStatusChangeReceiver() { } public void setCheckNetworkStatusChangeListener(CheckNetworkStatusChangeListener mCheckNetworkStatusChangeListener) { this.mCheckNetworkStatusChangeListener = mCheckNetworkStatusChangeListener; } @Override public void onReceive(Context context, Intent intent) { CheckNetworkStatusChangeListener.Status mStatus = (CheckNetworkStatusChangeListener.Status) intent.getSerializableExtra(EVENT); mCheckNetworkStatusChangeListener.onEvent(mStatus); } }
網路狀態監聽類
public interface CheckNetworkStatusChangeListener { void onEvent(Status status); /** * 網路狀態 * TYPE_UN_NETWORK 沒有網路 * TYPE_WIFI WiFi連線 * TYPE_MOBILE 移動資料 */ enum Status { TYPE_UN_NETWORK, TYPE_WIFI, TYPE_MOBILE, } }
監聽事件,檢查到網路狀態時會呼叫
void onEvent(Status status);
檢測當前網路狀態
public class NetworkUtil {
/**
* 獲取當前網路型別 CheckNetworkStatusChangeListener.Status
*
* @return 返回網路型別 CheckNetworkStatusChangeListener.Status
*/
public static CheckNetworkStatusChangeListener.Status getNetworkConnectionType(Context context) {
//獲取連線管理器
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager == null)
return CheckNetworkStatusChangeListener.Status.TYPE_UN_NETWORK;
//獲取網路連線資訊
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isAvailable()) {
if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
return CheckNetworkStatusChangeListener.Status.TYPE_WIFI;
}
if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
return CheckNetworkStatusChangeListener.Status.TYPE_MOBILE;
}
}
return CheckNetworkStatusChangeListener.Status.TYPE_UN_NETWORK;
}
}
實現每秒檢測1次網路狀態,因為是耗時操作所有在子執行緒中去獲取當前網路狀態
@Override
protected void onResume() {
super.onResume();
new Thread(mRunnable).start();
}
Runnable mRunnable = new Runnable() {
@Override
public void run() {
//實現每隔一秒檢測一次網路
while (true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
CheckNetworkStatusChangeListener.Status status = NetworkUtil.getNetworkConnectionType(BaseActivity.this);
Message message = new Message();
message.obj = status;
simpleHandler.sendMessage(message);
}
}
};
檢測網路狀態後傳送Message到handle,handle去傳送廣播,這注意handle記憶體洩漏
/**
* @ Author yemao
* @ Email [email protected]
* @ Date 2018/7/31
* @ Des自定義Handler,使用弱引用防止記憶體溢位
*/
public class SimpleHandler<T extends Activity> extends Handler {
WeakReference<T> weakReference;
public SimpleHandler(T t) {
this.weakReference = new WeakReference<>(t);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (weakReference.get() != null) {
//傳送廣播
Intent mCheckNetworkIntent = new Intent();
mCheckNetworkIntent.setAction(CheckNetworkStatusChangeReceiver.ACTION);
CheckNetworkStatusChangeListener.Status status= (CheckNetworkStatusChangeListener.Status) msg.obj;
mCheckNetworkIntent.putExtra(CheckNetworkStatusChangeReceiver.EVENT,status);
weakReference.get().sendBroadcast(mCheckNetworkIntent);
}
}
}
到這基本上就竄起來了,看下baseActivity完整程式碼
/**
* @ Author YeMao
* @ Email [email protected]
* @ Date 2018/7/31
* @ Des Activity 基類
*/
public class BaseActivity extends AppCompatActivity implements CheckNetworkStatusChangeListener {
private CheckNetworkStatusChangeReceiver mCheckNetworkStatusChangeReceiver;
private String LOG = BaseActivity.class.getSimpleName();
SimpleHandler<BaseActivity> simpleHandler;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mCheckNetworkStatusChangeReceiver = new CheckNetworkStatusChangeReceiver();
mCheckNetworkStatusChangeReceiver.setCheckNetworkStatusChangeListener(this);
IntentFilter mIntentFilter = new IntentFilter();
mIntentFilter.addAction(CheckNetworkStatusChangeReceiver.ACTION);
registerReceiver(mCheckNetworkStatusChangeReceiver, mIntentFilter);
simpleHandler = new SimpleHandler<BaseActivity>(this);
}
@Override
protected void onResume() {
super.onResume();
new Thread(mRunnable).start();
}
Runnable mRunnable = new Runnable() {
@Override
public void run() {
//實現每隔一秒檢測一次網路
while (true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
CheckNetworkStatusChangeListener.Status status = NetworkUtil.getNetworkConnectionType(BaseActivity.this);
Message message = new Message();
message.obj = status;
simpleHandler.sendMessage(message);
}
}
};
@Override
public void onEvent(Status status) {
Log.w(LOG, "status: " + status.name());
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mCheckNetworkStatusChangeReceiver);
simpleHandler.removeCallbacks(mRunnable);
}
}
我們執行一下,看下結果
07-31 19:12:14.069 13865-13865/com.yr.simple W/BaseActivity: status: TYPE_WIFI
07-31 19:12:14.172 13865-13865/com.yr.simple W/BaseActivity: status: TYPE_WIFI
07-31 19:12:14.429 13865-13865/com.yr.simple W/BaseActivity: status: TYPE_WIFI
07-31 19:12:14.975 13865-13865/com.yr.simple W/BaseActivity: status: TYPE_WIFI
07-31 19:12:15.071 13865-13865/com.yr.simple W/BaseActivity: status: TYPE_UN_NETWORK
07-31 19:12:15.193 13865-13865/com.yr.simple W/BaseActivity: status: TYPE_UN_NETWORK
07-31 19:12:15.446 13865-13865/com.yr.simple W/BaseActivity: status: TYPE_UN_NETWORK
07-31 19:12:15.959 13865-13865/com.yr.simple W/BaseActivity: status: TYPE_UN_NETWORK
當網路變化時,呼叫onEvent()的列印資訊
那麼下一步就是在onEvent()判斷網路狀態,沒有網路時的頁面提示,當然你也可以做其他操作我這隻提供思路
1.自定義layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:background="@color/gray"
android:layout_height="50dp">
<TextView
android:id="@+id/tv_network_status"
android:layout_centerInParent="true"
android:text="@string/not_network"
android:textColor="@color/red"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
2.BaseActivity關鍵程式碼
@Override
public void setContentView(int layoutResID) {
LinearLayout mRootLayout = findViewById(R.id.root_linear_layout);
//將網路狀態view新增到根檢視
mNetworkStatusLayout = new NetworkStatusLayout(this);
//預設隱藏狀態
mNetworkStatusLayout.setVisibility(View.GONE);
mRootLayout.addView(mNetworkStatusLayout, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
//將子類的layout,新增到根目錄
View mContentView = LayoutInflater.from(this).inflate(layoutResID, null);
mRootLayout.addView(mContentView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
}
動態顯示隱藏NetworkStatusLayout
@Override
public void onEvent(Status status) {
Log.w(LOG, "status: " + status.name());
if (status == Status.TYPE_UN_NETWORK) {
if (mNetworkStatusLayout.getVisibility() == View.GONE)
mNetworkStatusLayout.setVisibility(View.VISIBLE);
} else {
if (mNetworkStatusLayout.getVisibility() == View.VISIBLE)
mNetworkStatusLayout.setVisibility(View.GONE);
}
}
執行一下看下效果
然後進入優化工作
可能有些頁面不需要顯示,新增變數checkNetworkStatusChangeListenerEnable判斷是否要顯示
private boolean checkNetworkStatusChangeListenerEnable=true;
public void setCheckNetworkStatusChangeListenerEnable(boolean checkNetworkStatusChangeListener) {
this.checkNetworkStatusChangeListenerEnable = checkNetworkStatusChangeListener;
}
@Override
public void onEvent(Status status) {
Log.w(LOG, "status: " + status.name());
if (checkNetworkStatusChangeListenerEnable)
return;
if (status == Status.TYPE_UN_NETWORK) {
if (mNetworkStatusLayout.getVisibility() == View.GONE)
mNetworkStatusLayout.setVisibility(View.VISIBLE);
} else {
if (mNetworkStatusLayout.getVisibility() == View.VISIBLE)
mNetworkStatusLayout.setVisibility(View.GONE);
}
}
到這基本上大功告成了,BaseActivity完整程式碼
public class BaseActivity extends AppCompatActivity implements CheckNetworkStatusChangeListener {
private CheckNetworkStatusChangeReceiver mCheckNetworkStatusChangeReceiver;
private String LOG = BaseActivity.class.getSimpleName();
private SimpleHandler<BaseActivity> simpleHandler;
private NetworkStatusLayout mNetworkStatusLayout;
private boolean checkNetworkStatusChangeListenerEnable=true;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setContentView(R.layout.activity_base);
init();
}
@Override
public void setContentView(int layoutResID) {
LinearLayout mRootLayout = findViewById(R.id.root_linear_layout);
//將網路狀態view新增到根檢視
mNetworkStatusLayout = new NetworkStatusLayout(this);
//預設隱藏狀態
mNetworkStatusLayout.setVisibility(View.GONE);
mRootLayout.addView(mNetworkStatusLayout, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
//將子類的layout,新增到根目錄
View mContentView = LayoutInflater.from(this).inflate(layoutResID, null);
mRootLayout.addView(mContentView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
}
private void init() {
mCheckNetworkStatusChangeReceiver = new CheckNetworkStatusChangeReceiver();
mCheckNetworkStatusChangeReceiver.setCheckNetworkStatusChangeListener(this);
IntentFilter mIntentFilter = new IntentFilter();
mIntentFilter.addAction(CheckNetworkStatusChangeReceiver.ACTION);
registerReceiver(mCheckNetworkStatusChangeReceiver, mIntentFilter);
simpleHandler = new SimpleHandler<BaseActivity>(this);
}
public void setCheckNetworkStatusChangeListenerEnable(boolean checkNetworkStatusChangeListener) {
this.checkNetworkStatusChangeListenerEnable = checkNetworkStatusChangeListener;
}
@Override
protected void onResume() {
super.onResume();
new Thread(mRunnable).start();
}
Runnable mRunnable = new Runnable() {
@Override
public void run() {
//實現每隔一秒檢測一次網路
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
CheckNetworkStatusChangeListener.Status status = NetworkUtil.getNetworkConnectionType(BaseActivity.this);
Message message = new Message();
message.obj = status;
simpleHandler.sendMessage(message);
}
}
};
@Override
public void onEvent(Status status) {
Log.w(LOG, "status: " + status.name());
if (checkNetworkStatusChangeListenerEnable)
return;
if (status == Status.TYPE_UN_NETWORK) {
if (mNetworkStatusLayout.getVisibility() == View.GONE)
mNetworkStatusLayout.setVisibility(View.VISIBLE);
} else {
if (mNetworkStatusLayout.getVisibility() == View.VISIBLE)
mNetworkStatusLayout.setVisibility(View.GONE);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mCheckNetworkStatusChangeReceiver);
simpleHandler.removeCallbacks(mRunnable);
}
}
如何使用,activity繼承自BaseActivity
public class MainActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setTitle("我是首頁");
}
}
好了,謝謝大家閱讀,如有問題請戳我哦!