????Android網(wǎng)絡(luò)監(jiān)控可以說是一個(gè)老生長談的話題了。但隨著Android API的更新,總有新東西可以聊。我們知道在Android N上移除了部分隱式廣播來達(dá)到防止應(yīng)用被頻繁啟動(dòng)而提升設(shè)備性能的問題。其中就包括:
<receiver android:name=".NetStateReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
因此,為了兼容Android N,只能使用動(dòng)態(tài)注冊(cè)的方式來注冊(cè)BroadCastReceiver:
IntentFilter filter = new IntentFilter();
filter.addAction(Constants.ACTION_CONNECTIVITY_CHANGE);
application.registerReceiver(receiver, filter);
????但是巫橄,這不是今天的重點(diǎn),今天主要說的是NetworkCallback,這是Android API 21以后推出的api茵典。有人可能會(huì)說單單使用動(dòng)態(tài)注冊(cè)BroadCastReceiver的方式就可以解決的問題湘换,為什么還要使用這個(gè)不兼容低版本的api?我們要相信android 5.0及以下的手機(jī)逐漸會(huì)退出歷史舞臺(tái)的,新版api總歸是要用起來的统阿。況且NetworkCallback有著更佳的表現(xiàn)彩倚,我們沒有拒絕的理由。
????第一步:實(shí)現(xiàn)一個(gè)NetworkCallback方法:
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class NetworkCallbackImpl extends ConnectivityManager.NetworkCallback {
private static final String TAG = "NetworkCallbackImpl";
private Map<Object, List<MethodManager>> networkList = new HashMap<>();
@Override
public void onAvailable(Network network) {
super.onAvailable(network);
Log.e(TAG,"網(wǎng)絡(luò)連接了");
}
@Override
public void onLost(Network network) {
super.onLost(network);
Log.e(TAG,"網(wǎng)絡(luò)斷開了");
}
@Override
public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
super.onCapabilitiesChanged(network, networkCapabilities);
if(networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)){
if(networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)){
Log.e(TAG,"wifi網(wǎng)絡(luò)已連接");
}else {
Log.e(TAG,"移動(dòng)網(wǎng)絡(luò)已連接");
}
}
}
}
????通過復(fù)寫以上三個(gè)方法基本就可以滿足我們監(jiān)控網(wǎng)絡(luò)的連接與斷開扶平,wifi網(wǎng)絡(luò)與移動(dòng)網(wǎng)絡(luò)切換的需求了帆离。
????第二步:注冊(cè)NetworkCallbackImpl
NetworkCallbackImpl networkCallback = new NetworkCallbackImpl();
NetworkRequest request = new NetworkRequest.Builder().build();
ConnectivityManager cmgr = (ConnectivityManager) application
.getSystemService(Context.CONNECTIVITY_SERVICE);
if (cmgr != null) {
cmgr.registerNetworkCallback(request,networkCallback);
}
????通過以上兩步我們就可以run一把代碼,不出意外结澄,網(wǎng)絡(luò)連接狀態(tài)已經(jīng)可以愉快的打印出來了哥谷。那么問題來了岸夯,我們?nèi)绾卧贏ctivity或者是Fragment中實(shí)時(shí)獲取網(wǎng)絡(luò)狀態(tài)了呢?很簡單们妥,使用接口回調(diào)就可以搞定了囱修。當(dāng)然也可以使用EventBus或者RxBus來進(jìn)行事件傳遞。對(duì)于沒有在項(xiàng)目中使用事件總線的情況王悍,我們不妨來實(shí)現(xiàn)自己的"EventBus"。
- 先定義一個(gè)枚舉類型餐曼,用來表示網(wǎng)絡(luò)狀態(tài)
public enum NetType {
AUTO,//全部狀態(tài)
NONE,//無網(wǎng)絡(luò)
WIFI,
MOBILE
}
- 為需要回調(diào)網(wǎng)絡(luò)狀態(tài)的方法定義一個(gè)運(yùn)行時(shí)注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Network {
NetType netType() default NetType.AUTO;
}
- 為Activity中的監(jiān)控方法添加注解
@Network(netType = NetType.AUTO)
public void onNetChanged(NetType netType) {
switch (netType) {
case WIFI:
Log.e(TAG,"AUTO監(jiān)控:WIFI CONNECT");
break;
case MOBILE:
Log.e(TAG,"AUTO監(jiān)控:MOBILE CONNECT");
break;
case AUTO:
Log.e(TAG,"AUTO監(jiān)控:AUTO CONNECT");
break;
case NONE:
Log.e(TAG,"AUTO監(jiān)控:NONE CONNECT");
break;
default:
break;
}
}
@Network(netType = NetType.WIFI)
public void onWifiChanged(NetType netType){
switch (netType){
case WIFI:
Log.e(TAG,"wifi監(jiān)控:WIFI CONNECT");
break;
case NONE:
Log.e(TAG,"wifi監(jiān)控:NONE CONNECT");
break;
}
}
@Network(netType = NetType.MOBILE)
public void onMobileChanged(NetType netType){
switch (netType){
case MOBILE:
Log.e(TAG,"Mobile監(jiān)控:MOBILE CONNECT");
break;
case NONE:
Log.e(TAG,"Mobile監(jiān)控:NONE CONNECT");
break;
}
}
????注解和監(jiān)控方法都定義好了压储,我們需要將二者關(guān)聯(lián)起來,也就是我們要在NetworkCallback中為Activity提供注冊(cè)方法源譬。在此之前我們創(chuàng)建一個(gè)注解方法的管理類
4.注解方法管理類
public class MethodManager {
//被注解方法的參數(shù)類型 NetType netType
private Class<?> type;
//需要監(jiān)聽的網(wǎng)絡(luò)類型
private NetType netType;
//需要執(zhí)行的方法
private Method method;
public MethodManager(Class<?> type, NetType netType, Method method) {
this.type = type;
this.netType = netType;
this.method = method;
}
public Class<?> getType() {
return type;
}
public void setType(Class<?> type) {
this.type = type;
}
public NetType getNetType() {
return netType;
}
public void setNetType(NetType netType) {
this.netType = netType;
}
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
}
5.通過對(duì)注解的解析集惋,在NetworkCallback中為Actvitiy提供注冊(cè)與解除注冊(cè)
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class NetworkCallbackImpl extends ConnectivityManager.NetworkCallback {
private static final String TAG = "NetworkCallbackImpl";
private Map<Object, List<MethodManager>> networkList = new HashMap<>();
@Override
public void onAvailable(Network network) {
super.onAvailable(network);
Log.e(TAG,"網(wǎng)絡(luò)連接了");
}
@Override
public void onLost(Network network) {
super.onLost(network);
post(NetType.NONE);
}
@Override
public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
super.onCapabilitiesChanged(network, networkCapabilities);
if(networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)){
if(networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)){
post(NetType.WIFI);
}else {
post(NetType.MOBILE);
}
}
}
/**
* 通知所有注冊(cè)的方法,網(wǎng)絡(luò)發(fā)生了改變
* @param netType
*/
private void post(NetType netType) {
Set<Object> sets = networkList.keySet();
for (Object observer : sets) {
List<MethodManager> methodList = networkList.get(observer);
for (MethodManager method : methodList) {
if (method.getType().isAssignableFrom(netType.getClass())) {
if (method.getNetType() == netType ||
netType == NetType.NONE ||
method.getNetType() == NetType.AUTO) {
invoke(method, observer, netType);
}
}
}
}
}
private void invoke(MethodManager methodManager, Object observer, NetType netType) {
try {
Method execute = methodManager.getMethod();
execute.invoke(observer, netType);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
/**
* 注冊(cè)監(jiān)聽
* @param observer
*/
public void registerObserver(Object observer) {
List<MethodManager> methodList = networkList.get(observer);
if (methodList == null) {
methodList = getAnnotationMethod(observer);
networkList.put(observer, methodList);
}
}
/**
* 遍歷注冊(cè)類中的所有方法踩娘,收集被注解方法的信息
* @param observer
* @return
*/
private List<MethodManager> getAnnotationMethod(Object observer) {
List<MethodManager> methodList = new ArrayList<>();
Method[] methods = observer.getClass().getMethods();
for (Method method : methods) {
com.px.network.Network network = method.getAnnotation(com.px.network.Network.class);
if (network == null) {
continue;
}
Log.e(TAG, "NETWORK.....");
//校驗(yàn)返回值
Type returnType = method.getGenericReturnType();
if (!"void".equals(returnType.toString())) {
throw new RuntimeException(method.getName() + "return type should be null");
}
//校驗(yàn)參數(shù)
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length != 1) {
throw new RuntimeException(method.getName() + "arguments should be one");
}
MethodManager methodManager = new MethodManager(parameterTypes[0],
network.netType(), method);
methodList.add(methodManager);
}
return methodList;
}
public void unRegisterObserver(Object observer) {
if (!networkList.isEmpty()) {
networkList.remove(observer);
}
}
public void unRegisterAllObserver() {
if (!networkList.isEmpty()) {
networkList.clear();
}
NetworkManager.getInstance().getConnectivityManager().unregisterNetworkCallback(this);
networkList = null;
}
}
????這樣刮刑,整個(gè)網(wǎng)絡(luò)監(jiān)控框架基本完成,這個(gè)框架中使用了注解养渴,通過反射的方式完成了事件了分發(fā)雷绢,如果你介意使用反射,可以使用接口回調(diào)的方式注冊(cè)事件理卑。完整代碼請(qǐng)查看Demo翘紊。