欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Android AspectJ 重复织入的问题

程序员文章站 2022-03-26 10:30:11
AspectJ是Android AOP三剑客之一,对于一些面向切面的需求,能提供很好的解决方案。但最近,在使用过程中,发现一个问题,对于切点的织入,不仅仅是...

AspectJ是Android AOP三剑客之一,对于一些面向切面的需求,能提供很好的解决方案。
但最近,在使用过程中,发现一个问题,对于切点的织入,不仅仅是当前类,当前类的子类也会被织入,从而导致重复织入的问题。

比如我们有一个基类BaseActivity

public class BaseActivity extends AppCompatActivity {

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        return super.onOptionsItemSelected(item);
    }
}

有一个主页Activity,继承自BaseActivity

public class MainActivity extends BaseActivity {
	@Override
    protected void onCreate(@androidx.annotation.Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_home, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.option_normal_1) {
            Toast.makeText(MainActivity.this, "Normal1", Toast.LENGTH_SHORT).show();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

接着,我们新建一个BaseActivity的切面

@Aspect
public class CheckBackAspect {
    @Pointcut("execution(boolean com.heiko.myaspecttest2.BaseActivity.onOptionsItemSelected(..))")
    public void methodMyOnOptionsItemSelected() {

    }

    @Around("methodMyOnOptionsItemSelected()")
    public boolean aroundMyOnOptionsItemSelected(ProceedingJoinPoint joinPoint) throws Throwable {
        Log.i("CheckBackAspect", "----- methodMyOnOptionsItemSelected -----");
        return (boolean) joinPoint.proceed();
    }
}

运行程序,点击菜单的时候,会发现日志会被调用两遍。

----- methodMyOnOptionsItemSelected -----
----- methodMyOnOptionsItemSelected -----

这和我们想要的效果是有偏差的,为此,我们打印下joinPoint有哪些参数

@Aspect
public class CheckBackAspect {
    @Pointcut("execution(boolean com.heiko.myaspecttest2.BaseActivity.onOptionsItemSelected(..))")
    public void methodMyOnOptionsItemSelected() {

    }

    @Around("methodMyOnOptionsItemSelected()")
    public boolean aroundMyOnOptionsItemSelected(ProceedingJoinPoint joinPoint) throws Throwable {
        String kind = joinPoint.getKind();
        String declaringTypeName = joinPoint.getSignature().getDeclaringTypeName();
        String signatureName = joinPoint.getSignature().getName();
        String srouceFileName = joinPoint.getSourceLocation().getFileName();
        String sourceWithinType = joinPoint.getSourceLocation().getWithinType().getName();
        Object target = joinPoint.getTarget();
        Log.i("CheckBackAspect", "----- methodMyOnOptionsItemSelected -----");
        Log.i("CheckBackAspect", "kind:" + kind);
        Log.i("CheckBackAspect", "declaringTypeName:" + declaringTypeName);
        Log.i("CheckBackAspect", "signatureName:" + signatureName);
        Log.i("CheckBackAspect", "srouceFileName:" + srouceFileName);
        Log.i("CheckBackAspect", "sourceWithinType:" + sourceWithinType);
        Log.i("CheckBackAspect", "target:" + target);
        return (boolean) joinPoint.proceed();
    }
}

点击菜单的时候,可以看到

----- methodMyOnOptionsItemSelected -----
kind:method-execution
declaringTypeName:com.heiko.myaspecttest2.MainActivity
signatureName:onOptionsItemSelected
srouceFileName:MainActivity.java
sourceWithinType:com.heiko.myaspecttest2.MainActivity
target:com.heiko.myaspecttest2.MainActivity@8f6cec4
----- methodMyOnOptionsItemSelected -----
kind:method-execution
declaringTypeName:com.heiko.myaspecttest2.BaseActivity
signatureName:onOptionsItemSelected
srouceFileName:BaseActivity.java
sourceWithinType:com.heiko.myaspecttest2.BaseActivity
target:com.heiko.myaspecttest2.MainActivity@8f6cec4

可以看到,我们可以通过declaringTypeNamesourceWithinType来判断一下,拦截掉不需要的切面执行。

@Aspect
public class CheckBackAspect {
    @Pointcut("execution(boolean com.heiko.myaspecttest2.BaseActivity.onOptionsItemSelected(..))")
    public void methodMyOnOptionsItemSelected() {

    }

    @Around("methodMyOnOptionsItemSelected()")
    public boolean aroundMyOnOptionsItemSelected(ProceedingJoinPoint joinPoint) throws Throwable {
        String declaringTypeName = joinPoint.getSignature().getDeclaringTypeName();
        if ("com.heiko.myaspecttest2.BaseActivity".equals(declaringTypeName)) {
            Log.i("CheckBackAspect", "执行onOptionsItemSelected切面");
            //执行了BaseActivity的onOptionsItemSelected切面
            //这里可以进行相关业务逻辑...
            return (boolean) joinPoint.proceed();
        }else{
            //对其他子类的切面,不进行操作
            return (boolean) joinPoint.proceed();
        }
    }
}

我们再来运行下程序,点击菜单,可以看到,只打印了如下日志

执行onOptionsItemSelected切面

至此,我们就解决了切面重复织入的问题了。

本文地址:https://blog.csdn.net/EthanCo/article/details/109583110