AOP面向切面编程-AspectJ-让相同逻辑代码更易维护管理的

2020-04-04  本文已影响0人  _风听雨声

现象:

打开京东/淘宝APP,断开网络连接,发现点击没有任何反应。我们简单猜想一下,他们是怎么做的呢?


一般实现方式:
    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.checkNet_tv:
                if (!NewWorkUtils.isNetworkConnected(this)) {
                    return;
                }
                Intent intent = new Intent(MainActivity.this, OtherActivity.class);
                startActivity(intent);
                break;
        }
    }

稍微看下上面的这一段代码,主要逻辑是通过判断网络是否可用,不可用就return,可用才继续往下走。这样显然是可以实现无网络状态时点击无反应这个需求的。但是在项目中,需要判断有网络状态才可以进入下一步的按钮,可能是几十个或者更多呢?每一个都需要写一段相同的逻辑判断一遍吗?如果有几十个都需要相同判断逻辑的按钮,项目中的相同代码会非常多,又或者这里的需求变更,需要改逻辑的位置会非常多,增加代码维护的成本。


那有没有更好的实现方式呢?
答案是有的
接下来插入剧情…
    @CheckNet
    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.checkNet_tv:
                Intent intent = new Intent(MainActivity.this, MainActivity.class);
                startActivity(intent);
                break;
        }
    }

相比原来的代码,多了一个注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckNet {
}

注解简单理解就是给程序看的一个标签,使用@interface来定义一个注解,注解里面也可以声明变量。声明注解必须声明这个注解的作用域和作用阶段,也就是Target和Retention。常用的Target有ElementType.TYPE,ElementType.FLELD,ElementType.METHOD,分别代表作用在类、成员变量、方法上。常用的Retention有RetentionPolicy.CLASS,Retention.RUNTIME,Retention.SOURCE,分别代表编译阶段,运行阶段,编码阶段。RetentionPolicy.CLASS,Retention.RUNTIME使用的频率会更高一点,Retention.SOURCE常见的注解有@Override。

@Aspect
public class CheckNetAspect {
    @Pointcut("execution(@com.demo.checknetdemo.CheckNet * * (..))")
    public void onCheckNet() {
    }

    @Around("onCheckNet()")
    public void handleCheckNet(ProceedingJoinPoint joinPoint) throws Throwable {
        Object object = joinPoint.getThis();
        Context context = getContext(object);
        if (context != null) {
            if (!isNetworkConnected(context)) {
                return;
            }
        }
        joinPoint.proceed();
    }

    private Context getContext(Object object) {
        if (object instanceof Activity) {
            return (Activity) object;
        } else if (object instanceof Fragment) {
            return ((Fragment) object).getContext();
        } else if (object instanceof View) {
            return ((View) object).getContext();
        }
        return null;
    }

    private boolean isNetworkConnected(Context context) {
        if (context != null) {
            ConnectivityManager mConnectivityManager = (ConnectivityManager) context
                    .getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
            if (mNetworkInfo != null) {
                return mNetworkInfo.isAvailable();
            }
        }
        return false;
    }
}

@Aspect代表这是一个切面的处理类

    @Pointcut("execution(@com.demo.checknetdemo.CheckNet * * (..))")
    public void onCheckNet() {
    }

@Pointcut代表一个切点,("execution(@com.demo.checknetdemo.CheckNet * * (..))")代表的是切点的完整的路径,后面的* *(..)是一种固定格式,相当于导包时路径后面跟的 *一样。

    @Around("onCheckNet()")
    public void handleCheckNet(ProceedingJoinPoint joinPoint) throws Throwable {
        Object object = joinPoint.getThis();
        Context context = getContext(object);
        if (context != null) {
            if (!isNetworkConnected(context)) {
                return;
            }
        }
        joinPoint.proceed();
    }

@Around("onCheckNet()")表示这里是针对切面的处理函数,使用@Around注解可以决定函数是否可以往下执行。joinPoint.proceed()表示让函数继续往下执行。这里常用的注解还有@Before,@After,分别代表要把这段代码插入到原方法的前面还是后面。


总结:

AOP面向切面编程是一种编程思想,这种编程方式的存在能使我们的代码更易维护管理。可以使用的场景有很多,如防多次点击、上传埋点、网络判断、权限申请..等等。AspectJ是AOP的一种实现方式。还有APT,Javassist..等等。

上一篇下一篇

猜你喜欢

热点阅读