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

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

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

1.核心还是利用广播实现监听网络变化,注册广播那些基本操作我们不介绍,我们讲一下这个网络变化事件分发,实现的原理有点像EventBus,就是利用收集的页面类内部包含我们需要处理的注解@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","网络发生了变化....");
            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<MethodManager> methodManagerList = map
                .get(object);
        if (methodManagerList == null) {
            methodManagerList = findAnnotationMethod(object);
            map.put(object, methodManagerList);
        }
    }

这里其实就是去遍历类里面所有包含Network注解的方法,实现方法 是这个 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();

            //获取方法的参数
            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<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反射去调用,这样就实现了类似通知的效果

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

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,039评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,223评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,916评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,009评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,030评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,011评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,934评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,754评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,202评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,433评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,590评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,321评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,917评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,568评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,738评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,583评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,482评论 2 352

推荐阅读更多精彩内容

  • 背景 如果遇到问题请在:https://www.jianshu.com/p/301edd6a2e61讨论Event...
    yjy239阅读 816评论 0 1
  • EventBus的设计理念是基于观察者模式的,可以参考设计模式(1)—观察者模式先来了解该设计模式。 1、程序示例...
    开发者如是说阅读 868评论 0 5
  • EventBus是Guava的事件处理机制,是设计模式中的观察者模式(生产/消费者编程模型)的优雅实现。对于事件监...
    tracy_668阅读 5,865评论 0 5
  • 每个家庭都有可能出现一些冲突特别严重的场面,冲突出现中的家庭成员往往怒气很大,处理这类事情需要一套特别的技...
    刘灿丽阅读 695评论 0 3
  • 花了两个晚上细看完秋叶和秦阳的《如何打造超级IP》,书对现在的一些IP现象解释的非常透彻,其中最让我觉得物超所值的...
    曾小梧阅读 15,780评论 3 56