Android AspectJ 重复织入的问题

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切面

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

氦客

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值