文章純屬個人學(xué)習(xí)的代碼實現(xiàn)
網(wǎng)易云微專業(yè)公開課這節(jié)課主要講了監(jiān)聽網(wǎng)絡(luò)框架沃测,主要核心用的反射,好處是解耦食茎,還有一個好處是"專一",這個專一就是比如你想在不同網(wǎng)絡(luò)情況下做不同的動作蒂破,比如
wifi
的時候你選擇加載高清圖等,但是你在弱網(wǎng)
或者3g别渔,4g
只加載文本顯示這樣是不是挺好附迷。
1.核心還是利用廣播實現(xiàn)監(jiān)聽網(wǎng)絡(luò)變化,注冊廣播那些基本操作我們不介紹哎媚,我們講一下這個網(wǎng)絡(luò)變化事件分發(fā)喇伯,實現(xiàn)的原理有點像EventBus
,就是利用收集的頁面類內(nèi)部包含我們需要處理的注解@Network
的方法,然后把它存在一個HashMap
上面
先看看代碼
public class NetStateReceiver extends BroadcastReceiver {
private NetType netType;
private Map<Object, List<MethodManager>> map;
public NetStateReceiver() {
netType = NetType.NONE;
map = new HashMap<>();
}
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null||intent.getAction()==null) {
Log.e("bigman","異常....");
return;
}
if (intent.getAction().equalsIgnoreCase("android.net.conn.CONNECTIVITY_CHANGE")){
Log.e("bigman","網(wǎng)絡(luò)發(fā)生了變化....");
Application application = NetWorkManager.getDefault().getApplication();
netType=NetworkUtils.getNetworkType(application);
if(NetworkUtils.netIsConnected(application)){
Log.e("bigman","網(wǎng)絡(luò)連接成功....");
}else{
Log.e("bigman","網(wǎng)絡(luò)連接失敗....");
}
post(netType);
}
}
這一段代碼實現(xiàn)了網(wǎng)絡(luò)變化的監(jiān)聽拨与,而分發(fā)方法post(netType);
我們等一下再看
我們先看看稻据,這邊定一個了一個全局單例NetWorkManager
,為啥先看這個類,因為他 是我們對外的接口
public class NetWorkManager {
private static volatile NetWorkManager instance;
private NetStateReceiver receiver;
private Application application;
public static NetWorkManager getDefault() {
if(instance==null){
synchronized (NetWorkManager.class){
if (instance==null){
instance=new NetWorkManager();
}
}
}
return instance;
}
private NetWorkManager(){
receiver = new NetStateReceiver();
}
public Application getApplication(){
if (application==null){
throw new RuntimeException("....");
}
return application;
}
public void init(Application application){
this.application=application;
IntentFilter intentFilter=new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
application.registerReceiver(receiver,intentFilter);
}
public void register(Object object) {
receiver.register(object);
}
}
這一部分代碼主要完成了動態(tài)注冊廣播买喧,當(dāng)然我們還靜態(tài)注冊了捻悯,同學(xué)們可以自己去配置文件找找,這里用動態(tài)注冊的好處就是做到了很好的版本兼容淤毛,這里的核心方法是
public void register(Object object) {
receiver.register(object);
}
這里調(diào)用了注冊了一個對象今缚,我們看看怎么調(diào)用的
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
NetWorkManager.getDefault().register(this);
}
}
其實就是把當(dāng)前MainActivity
對象傳給receiver
(即NetStateReceiver
)的register
方法,這個register
就完成了注解方法的收集钱床,我們看代碼
public void register(Object object) {
List<MethodManager> methodManagerList = map
.get(object);
if (methodManagerList == null) {
methodManagerList = findAnnotationMethod(object);
map.put(object, methodManagerList);
}
}
這里其實就是去遍歷類里面所有包含Network
注解的方法荚斯,實現(xiàn)方法 是這個 findAnnotationMethod
private List<MethodManager> findAnnotationMethod(Object object) {
List<MethodManager> list = new ArrayList<>();
Class<?> aClass = object.getClass();
Method[] methods = aClass.getMethods();
for (Method method : methods) {
Network annotation = method.getAnnotation(Network.class);
if (annotation == null) {
continue;
}
//獲取方法返回類型
// method.getGenericReturnType();
//獲取方法的參數(shù)
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length != 1) {
throw new RuntimeException("參數(shù)只能有一個");
}
MethodManager methodManager = new MethodManager(parameterTypes[0],annotation.netType(),method);
list.add(methodManager);
}
return list;
}
這個方法是核心也是反射的基本操作,首先通過 Object
對象找到對應(yīng)的 Class
對象查牌,然后通過這個 Class
對象獲取所有的方法事期,然后遍歷所有方法,再通過Method
方法 對象的method.getAnnotation(Network.class)
方法 找到指定包含Network
注解的方法纸颜,找到之后把該方法參數(shù)類型兽泣,注解的值和方法都包裝到這個MethodManager
對象里面,然后再放進(jìn)HashMap
存起來
好了胁孙,回到開始的地方唠倦,我們沒看的那個post
事件分發(fā)称鳞,實現(xiàn) 代碼如下
public void post(NetType netType){
if (map.isEmpty())return;
Set<Object> set = map.keySet();
for (Object getter : set) {
List<MethodManager> methodManagerList = map.get(getter);
if (methodManagerList!=null){
for (MethodManager methodManager : methodManagerList) {
if (methodManager.getType().isAssignableFrom(netType.getClass())) {
switch (methodManager.getNetType()){
case AUTO:
invoke(methodManager,getter,netType);
break;
case WIFI:
if (netType==NetType.WIFI||netType==netType.NONE){
invoke(methodManager,getter,netType);
}
break;
case CMNET:
case CMWAP:
if (netType==NetType.CMNET||netType==NetType.CMWAP||netType==netType.NONE){
invoke(methodManager,getter,netType);
}
break;
}
}
}
}
}
}
這里其實原理就是通過key
就是比如MainActivity
對象找到上面register
收集的帶Network
注解的方法,然后通過invoke
反射去調(diào)用稠鼻,這樣就實現(xiàn)了類似通知的效果
分析完后冈止,我們可以看到這個架構(gòu)方式,比我們以前寫接口監(jiān)聽候齿,代碼的解耦熙暴,職責(zé)的分配都簡潔很多,當(dāng)然見仁見智慌盯,這個方法不一定是最好的周霉,很多人不能容忍反射帶來的一丟丟性能。
大家想了解更多直接去我的github看代碼實現(xiàn)