zoukankan      html  css  js  c++  java
  • AOP编程

    现象描述

    当我们打开京东 app 进入首页,如果当前是没有网络的状态,里面的按钮点击是没有反应的。只有当我们打开网络的情况下,点击按钮才能跳转页面,按照我们一般人写代码的逻辑应该是这个样子:

    /**
     * 跳转到待收货页面
     */
    public void jumpWaitReceiving() {
        // 判断当前有没有网络
        if(CheckNetUtil.isNetworkAvailable(this)) {
            // 当前有网络我才跳转,进入待收货页面
            Intent intent = new Intent(this, WaitReceivingActivity.class);
            startActivity(intent);
        }
    }
    
    /**
    * 跳转到我的钱包页面
    */
    public void jumpMineWallet() {
        if(CheckNetUtil.isNetworkAvailable(this)) {
            Intent intent = new Intent(this, MineWalletActivity.class);
            startActivity(intent);
        }
    }

    上面这段代码看似没有任何问题,完全满足京东的网络处理需求,就写一个 if(有网) 跳转到下一个页面,没网就不做任何处理。但是真的没有问题吗? 按照京东的页面,这些 if() 代码估计要写上几十次,而且有些在 Activity,有些甚至在 Fragment 中,很难管理。如果有一天需求变动,我们估计要改动多处。我们到底有没有更好的方式,且接着往下看。

    面向切面

    我们现在想做的其实就是,我根本不想写那么多的 if() 代码,而且写得越多越不好管理,比如有一天没网络要弹 Toast ,那么岂不是很多地方要去改动。所以接下来,我们打算采用面向切面的编程思想,把网络检测切出来统一管理。第一,保证代码的简洁性,第二,需求有变动时我们只需要统一改动那一部分代码,第三,有很多这里不一一列出来了。

    那么什么是 AOP ? 好处又有什么?

    面向切面(AOP)其实就是把众多方法中的所有共有代码全部抽取出来,放置到某个地方集中管理,然后在具体运行时,再由容器动态织入这些共有代码的话,最起码可以解决两个问题:

    1.1 Android程序员在编写具体的业务逻辑处理方法时,只需关心核心的业务逻辑处理,既提高了工作效率,又使代码变更简洁优雅。
    1.2 在日后的维护中由于业务逻辑代码与共有代码分开存放,而且共有代码是集中存放的,因此使维护工作变得简单轻松。

    那到底应该怎么写呢? 请看我最终的代码,代码如下:

    /**
     * 跳转到待收货页面
     */
    @CheckNet
    public void jumpWaitReceiving() {
        Intent intent = new Intent(this, WaitReceivingActivity.class);
        startActivity(intent);
    }
    
    /**
     * 跳转到我的钱包页面
     */
    @CheckNet
    public void jumpMineWallet() {
        Intent intent = new Intent(this, MineWalletActivity.class);
        startActivity(intent);
    }
    上面这段代码,也没看到你省了多少代码。但其实在我们真正的开发过程中,远不止检测网络这么个功能,比如还需要检测登录,需要上传日志,统计用户行为等等。这样,我们方法越多省的代码就会越多,而且所有的代码都统一进行了管理,后面维护起来也方便,况且跟最开始比起来,代码的确也变得更加简洁了。那好吧,我们就只看到加了一个 CheckNet ,也没看到你判断网络的代码啊?别急,且接着往下看。最主要的其实还是下面这段代码:
     1 /**
     2  * 处理网络检测切面
     3  */
     4 @Aspect
     5 public class SectionAspect {
     6 
     7     /**
     8      * 找到处理的切点
     9      * * *(..)  可以处理所有的方法
    10      */
    11     @Pointcut("execution(@com.darren.architect_day02.CheckNet * *(..))")
    12     public void checkNetBehavior() {
    13 
    14     }
    15 
    16     /**
    17      * 处理切面
    18      */
    19     @Around("checkNetBehavior()")
    20     public Object checkNet(ProceedingJoinPoint joinPoint) throws Throwable {
    21         Log.e("TAG", "checkNet");
    22         // 做埋点  日志上传  权限检测(我写的,RxPermission , easyPermission) 网络检测
    23         // 网络检测
    24         // 1.获取 CheckNet 注解  NDK  图片压缩  C++ 调用Java 方法
    25         MethodSignature signature = (MethodSignature) joinPoint.getSignature();
    26         CheckNet checkNet = signature.getMethod().getAnnotation(CheckNet.class);
    27         if (checkNet != null) {
    28             // 2.判断有没有网络  怎么样获取 context?
    29             Object object = joinPoint.getThis();// View Activity Fragment ; getThis() 当前切点方法所在的类
    30             Context context = getContext(object);
    31             if (context != null) {
    32                 if (!isNetworkAvailable(context)) {
    33                     // 3.没有网络不要往下执行
    34                     Toast.makeText(context,"请检查您的网络",Toast.LENGTH_LONG).show();
    35                     return null;
    36                 }
    37             }
    38         }
    39         return joinPoint.proceed();
    40     }
    41 
    42     /**
    43      * 通过对象获取上下文
    44      *
    45      * @param object
    46      * @return
    47      */
    48     private Context getContext(Object object) {
    49         if (object instanceof Activity) {
    50             return (Activity) object;
    51         } else if (object instanceof Fragment) {
    52             Fragment fragment = (Fragment) object;
    53             return fragment.getActivity();
    54         } else if (object instanceof View) {
    55             View view = (View) object;
    56             return view.getContext();
    57         }
    58         return null;
    59     }
    60 
    61     /**
    62      * 检查当前网络是否可用
    63      *
    64      * @return
    65      */
    66     private static boolean isNetworkAvailable(Context context) {
    67         // 获取手机所有连接管理对象(包括对wi-fi,net等连接的管理)
    68         ConnectivityManager connectivityManager = (ConnectivityManager)
    69                 context.getSystemService(Context.CONNECTIVITY_SERVICE);
    70         if (connectivityManager != null) {
    71             // 获取NetworkInfo对象
    72             NetworkInfo[] networkInfo = connectivityManager.getAllNetworkInfo();
    73 
    74             if (networkInfo != null && networkInfo.length > 0) {
    75                 for (int i = 0; i < networkInfo.length; i++) {
    76                     // 判断当前网络状态是否为连接状态
    77                     if (networkInfo[i].getState() == NetworkInfo.State.CONNECTED) {
    78                         return true;
    79                     }
    80                 }
    81             }
    82         }
    83         return false;
    84     }
    85 }
  • 相关阅读:
    Electron+Vue开发跨平台桌面应用
    vue-cli3.0 脚手架搭建项目的过程详解
    dart-sass与node-sass介绍
    创建vue-cli4项目,报错 ERROR command failed: yarn
    CSS Grid 网格布局教程
    总结5种自适应方式
    前端实战:electron+vue3+ts开发桌面端便签应用
    SDK 和 API 的区别是什么?
    Pinia 快速入门
    返回数组中最大的三个数
  • 原文地址:https://www.cnblogs.com/ganchuanpu/p/8351008.html
Copyright © 2011-2022 走看看