网易云微专业安卓-即时网络终结者,轻松驾驭Wifi与流量切换

文章纯属个人学习的代码实现

网易云微专业公开课这节课主要讲了监听网络框架,主要核心用的反射,好处是解耦,还有一个好处是"专一",这个专一就是比如你想在不同网络情况下做不同的动作,比如wifi的时候你选择加载高清图等,但是你在弱网或者3g,4g只加载文本显示这样是不是挺好。

1.核心还是利用广播实现监听网络变化,注册广播那些基本操作我们不介绍,我们讲一下这个网络变化事件分发,实现的原理有点像EventBus,就是利用收集的页面类内部包含我们需要处理的注解@Network的方法,然后把它存在一个HashMap上面
先看看代码

public class NetStateReceiver extends BroadcastReceiver {
    private NetType netType;
    private Map> 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","网络发生了变化....");
            Application application = NetWorkManager.getDefault().getApplication();
            netType=NetworkUtils.getNetworkType(application);
            if(NetworkUtils.netIsConnected(application)){
                Log.e("bigman","网络连接成功....");
            }else{
                Log.e("bigman","网络连接失败....");
            }
            post(netType);
        }
    }

这一段代码实现了网络变化的监听,而分发方法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);
    }
}

这一部分代码主要完成了动态注册广播,当然我们还静态注册了,同学们可以自己去配置文件找找,这里用动态注册的好处就是做到了很好的版本兼容,这里的核心方法是

    public void register(Object object) {
        receiver.register(object);
    }

这里调用了注册了一个对象,我们看看怎么调用的

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        NetWorkManager.getDefault().register(this);
    }
}

其实就是把当前MainActivity对象传给receiver(即NetStateReceiver)的register方法,这个register就完成了注解方法的收集,我们看代码

    public void register(Object object) {
        List methodManagerList = map
                .get(object);
        if (methodManagerList == null) {
            methodManagerList = findAnnotationMethod(object);
            map.put(object, methodManagerList);
        }
    }

这里其实就是去遍历类里面所有包含Network注解的方法,实现方法 是这个 findAnnotationMethod

 private List findAnnotationMethod(Object object) {
        List 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();

            //获取方法的参数
            Class[] parameterTypes = method.getParameterTypes();

            if (parameterTypes.length != 1) {
                throw new RuntimeException("参数只能有一个");
            }
            MethodManager methodManager = new MethodManager(parameterTypes[0],annotation.netType(),method);
            list.add(methodManager);

        }
        return list;
    }

这个方法是核心也是反射的基本操作,首先通过 Object对象找到对应的 Class对象,然后通过这个 Class对象获取所有的方法,然后遍历所有方法,再通过Method方法 对象的method.getAnnotation(Network.class)方法 找到指定包含Network注解的方法,找到之后把该方法参数类型,注解的值和方法都包装到这个MethodManager对象里面,然后再放进HashMap存起来

好了,回到开始的地方,我们没看的那个post事件分发,实现 代码如下

 public  void post(NetType netType){
       if (map.isEmpty())return;
        Set set = map.keySet();
        for (Object getter : set) {
            List 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反射去调用,这样就实现了类似通知的效果

分析完后,我们可以看到这个架构方式,比我们以前写接口监听,代码的解耦,职责的分配都简洁很多,当然见仁见智,这个方法不一定是最好的,很多人不能容忍反射带来的一丢丢性能。

大家想了解更多直接去我的github看代码实现

你可能感兴趣的:(网易云微专业安卓-即时网络终结者,轻松驾驭Wifi与流量切换)