美文网首页android知识点
AspectJ在Android中的使用

AspectJ在Android中的使用

作者: EvilsoulM | 来源:发表于2015-12-11 11:44 被阅读1805次

    学习自:http://blog.csdn.net/innost/article/details/49387395

    关于AOP和AspectJ详细使用就不多做介绍了,上面的文章都已经介绍的比较清楚了,这里就简单具几个在android中的例子~

    AOP思想:

    • 第一,我们要认识到OOP世界中,有些功能是横跨并嵌入众多模块里的,比如打印日志,比如统计某个模块中某些函数的执行时间等。这些功能在各个模块里分散得很厉害,可能到处都能见到。
    • 第二,AOP的目标是把这些功能集中起来,放到一个统一的地方来控制和管理。如果说,OOP如果是把问题划分到单个模块的话,那么AOP就是把涉及到众多模块的某一类问题进行统一管理。比如我们可以设计两个Aspects,一个是管理某个软件中所有模块的日志输出的功能,另外一个是管理该软件中一些特殊函数调用的权限检查。

    利用aspectJ我们也可以在方法执行前后 或者执行期进行一些hook~后续慢慢加使用方法。

    在项目开发中我们会经常遇到在很多地方校验url是否合法的问题:
    eg

    public class ImageLoader {
        private static final String TAG = "EvilsoulM";
        public static void loadImage(String url) {
            if(TextUtils.isEmpty(url)){
                return;
            }
        }
        public static void loadImage(String url, int placeholder) {
            if(TextUtils.isEmpty(url)){
                return;
            }
        }
        public static void loadImage(String url, int placeholder, int errorHolder) {
            if(TextUtils.isEmpty(url)){
                return;
            }
        }
        public static void loadImage(String url, int errorHolder, boolean isFade) {
            if(TextUtils.isEmpty(url)){
                return;
            }
        }
        public static void loadImage(String url, boolean isFade) {
            if(TextUtils.isEmpty(url)){
                return;
            }
        }
        public static void loadImage(String url, boolean isFade, int placeHolder) {
            if(TextUtils.isEmpty(url)){
                return;
            }
        }
    }
    

    如果方法数量较少还好,我们一个个加就好了,但是如果有很多种重载的方法,或者需要统一修改下判断条件就恶心了,你就得挨个去改。如果使用了aop我们就可以统一去管理url校验:

    ImageLoader

    public class ImageLoader {
        private static final String TAG = "EvilsoulM";
    
        public static void loadImage(String url) {
            Log.d(TAG, "loadImage() called with: " + "url = [" + url + "]");
        }
    
        public static void loadImage(String url, int placeholder) {
            Log.d(TAG, "loadImage() called with: " + "url = [" + url + "], placeholder = [" + placeholder + "]");
        }
    
        public static void loadImage(String url, int placeholder, int errorHolder) {
            Log.d(TAG, "loadImage() called with: " + "url = [" + url + "], placeholder = [" + placeholder + "], errorHolder = [" + errorHolder + "]");
        }
    
        public static void loadImage(String url, int errorHolder, boolean isFade) {
            Log.d(TAG, "loadImage() called with: " + "url = [" + url + "], errorHolder = [" + errorHolder + "], isFade = [" + isFade + "]");
    
        }
    
        public static void loadImage(String url, boolean isFade) {
            Log.d(TAG, "loadImage() called with: " + "url = [" + url + "], isFade = [" + isFade + "]");
        }
    
        public static void loadImage(String url, boolean isFade, int placeHolder) {
            Log.d(TAG, "loadImage() called with: " + "url = [" + url + "], isFade = [" + isFade + "], placeHolder = [" + placeHolder + "]");
        }
    }
    

    拦截url的aspect

    @Aspect
    public class CheckUrlAspect {
    
        @Pointcut("execution(* com.evilsoulm.common.Utils.ImageLoader.loadImage(String,..))")
        public void loadImageEntryPoint(String imageUri) {
        }
    
        @Around(value = "loadImageEntryPoint(imageUri)")
        public Object loadImageMethod(ProceedingJoinPoint joinPoint, String imageUri) throws Throwable {
            LogUtils.log("call -> loadImageMethod");
            if (TextUtils.isEmpty(((String) joinPoint.getArgs()[0]))) {//统一处理url是不是为空这里用的是一个比较简单的方式,默认第一个参数就是url但是url放在第2个参数就不使用了 一些高级用法后续再加
                return null;//如果为空就不执行我们拦截到的方法
            }
            return joinPoint.proceed();//相当于执行你拦截的方法 
        }
    }
    

    调用

    public class MainActivity extends AppCompatActivity {
        private static final String URL = "api.maoyan.com";
        private static final int ERROR_ID = 0x11;
        private static final int PLACE_HOLDER_ID = 0x12;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
            setSupportActionBar(toolbar);
    
            FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
            fab.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                            .setAction("Action", null).show();
                }
            });
            init("name->EvilsoulM");
    
            ImageLoader.loadImage("");//传空
            ImageLoader.loadImage("", ERROR_ID);//传空
            ImageLoader.loadImage("", ERROR_ID, PLACE_HOLDER_ID);//传空
            ImageLoader.loadImage("", ERROR_ID, true);//传空
            ImageLoader.loadImage(URL, false);
            ImageLoader.loadImage(URL, false, PLACE_HOLDER_ID);
        }
    
        @MethodTime
        private void init(String args) {
            LogUtils.log("init() called with: " + args);
        }
    }
    

    日志

    12-11 11:39:25.358 15900-15900/? D/EvilsoulM: init() called with: name->EvilsoulM
    12-11 11:39:25.361 15900-15900/? D/EvilsoulM: call -> loadImageMethod
    12-11 11:39:25.361 15900-15900/? D/EvilsoulM: call -> loadImageMethod
    12-11 11:39:25.361 15900-15900/? D/EvilsoulM: call -> loadImageMethod
    12-11 11:39:25.361 15900-15900/? D/EvilsoulM: call -> loadImageMethod
    12-11 11:39:25.361 15900-15900/? D/EvilsoulM: call -> loadImageMethod
    12-11 11:39:25.361 15900-15900/? D/EvilsoulM: loadImage() called with: url = [api.maoyan.com], isFade = [false]
    12-11 11:39:25.361 15900-15900/? D/EvilsoulM: call -> loadImageMethod
    12-11 11:39:25.361 15900-15900/? D/EvilsoulM: loadImage() called with: url = [api.maoyan.com], isFade = [false], placeHolder = [18]
    

    从上面日志就能看到 我们拦截到了6次调用,但是只执行了两次url不为空的情况

    当然我们也可以使用注解来判断我们方法是否需要拦截,这种方式后续再补充。

    自从有了AOP,我们就可以去掉业务逻辑中显示调用安全检查的内容,使得代码归于干净,各个模块又能各司其职。而这之中千丝万缕的联系,都由AOP来连接和管理。

    还有一个使用annotation 计算方法运行时间的demo~
    代码:github

    相关文章

      网友评论

      • 51b6eb550d85:如果使用asjectJ拦截用户权限怎么用呢?主页点击修改密码图标,然后如果没登录就不进入activty,登陆的话才能进入,asjectJ可以拦截activity启动吗?cutpoint是oncreate方法吗?
        求楼主回复
        51b6eb550d85:@EvilsoulM 谢谢楼主,我试试看:kissing_heart:
        EvilsoulM:@东澈 可以尝试替换 activitythread里的Instrumentation 拦截execStartActivity 方法,这是startActivity的入口在这判断等没登陆~
      • walker113:为什么没有aspectj-1.8.9.jar库
      • zpscott:咋不好使呢?楼主亲自测试过吗?
        zpscott: @EvilsoulM 嗯嗯 已经搞好了 多谢啦
        EvilsoulM:@zpscott 可能是你的gradle配置不对哈 肯定是亲子试用过的

      本文标题:AspectJ在Android中的使用

      本文链接:https://www.haomeiwen.com/subject/fzeyhttx.html