AspectJ实现无侵入图片加载监控

657 阅读2分钟

使用沪江开源的aspectjx

github.com/HujiangTech…

监控ImageLoader

找到切入点:ImageLoader.displayImage方法

/**
 * ImageLoader的各个重载方法最终都会调用displayImage方法
 * 所以使用AdpectJ切入该方法,将ImageLoadingListener替换为我们自己的监听器
 */
@Aspect
public class ImageAspectj {
    public static final String TAG = "ImageAspectj";
    //总共的参数个数
    private static final int ARG_LEN = 5;

    //imageLoadingListener的序号
    private static final int REQ_LI_INDEX = 3;

    @Pointcut("execution(* com.vivo.imageloader.core.ImageLoader.displayImage(" +
            "java.lang.String," +
            "com.vivo.imageloader.core.imageaware.ImageAware," +
            "com.vivo.imageloader.core.DisplayImageOptions," +
            "com.vivo.imageloader.core.listener.ImageLoadingListener," +
            "com.vivo.imageloader.core.listener.ImageLoadingProgressListener))" +
            "&& args(uri, imageAware,displayImageOptions,imageLoadingListener,progressListener)")
    public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions displayImageOptions,
                             ImageLoadingListener imageLoadingListener, ImageLoadingProgressListener progressListener) {

    }

    @Around(value = "displayImage(uri, imageAware, displayImageOptions, imageLoadingListener, progressListener)",
            argNames = "uri, imageAware, displayImageOptions,imageLoadingListener,progressListener")
    public void imageLoaderDisplayImage(ProceedingJoinPoint point, String uri, ImageAware imageAware, DisplayImageOptions displayImageOptions,
                                        ImageLoadingListener imageLoadingListener, ImageLoadingProgressListener progressListener) {
        try {
            Object[] args = point.getArgs();
            //参数为空,或者长度非5-只是边界判断;非空间的activity加载图片时不替换ImageLoadingListener
            if (TextUtils.isEmpty(uri) || args == null || args.length != ARG_LEN || !GSConstant.inGsActivity) {
                point.proceed();
            } else {
                VLog.d(TAG, "imageLoaderDisplayImage : " + uri);
                //替换ImageLoadingListener
                //监控逻辑,自己完善
                args[REQ_LI_INDEX] = new ImageLoadingListener(){
                @Override
                void onLoadingStarted(String var1, View var2);
                @Override
    			void onLoadingFailed(String var1, View var2, FailReason var3);
                @Override
    			void onLoadingComplete(String var1, View var2, Bitmap var3);
                @Override
    			void onLoadingCancelled(String var1, View var2);
                };
                point.proceed(args);
            }
        } catch (Throwable throwable) {
            VLog.d(TAG, throwable.toString());
        }
    }
}

监控Glide

切入点:SingleRequest.obtain()

/**
 * Glide的SingleRequest负责包装请求,在obtain()方法中能同时获取到图片地址以及监听器列表
 * 所以使用AspectJ切入该方法,增加我们自己的监听器,用来监听图片加载过程
 */
@Aspect
public class GlideAspectj {
    private static final String TAG = "GlideAspectj";
    //总共的参数个数
    private static final int ARG_LEN = 15;

    //requestListeners是第11个参数,数组中的位置为10
    private static final int REQ_LI_INDEX = 10;

    @Pointcut("execution(* com.bumptech.glide.request.SingleRequest.obtain(" +
            "android.content.Context," +
            "com.bumptech.glide.GlideContext," +
            "Object," +
            "java.lang.Class<Object+>," +
            "com.bumptech.glide.request.BaseRequestOptions<?>," +
            "int," +
            "int," +
            "com.bumptech.glide.Priority," +
            "com.bumptech.glide.request.target.Target<Object+>," +
            "com.bumptech.glide.request.RequestListener<Object+>," +
            "java.util.List+," +
            "..))" +
            "&& args(context,glideContext,model,transcodeClass,requestOptions,overrideWidth,overrideHeight,priority,target,targetListener,requestListeners,..)")
    public void singleRequestObtain(Context context,
                                    GlideContext glideContext,
                                    Object model,
                                    Class transcodeClass,
                                    BaseRequestOptions<?> requestOptions,
                                    int overrideWidth,
                                    int overrideHeight,
                                    Priority priority,
                                    Target target,
                                    RequestListener targetListener,
                                    List<RequestListener> requestListeners) {

    }

    /**
     * PointCut的方法如果有返回值,则Around时也需要返回结果,只需要声明为Object即可
     */
    @Around(value = "singleRequestObtain(" +
            "context," +
            "glideContext," +
            "model," +
            "transcodeClass," +
            "requestOptions," +
            "overrideWidth," +
            "overrideHeight," +
            "priority," +
            "target," +
            "targetListener," +
            "requestListeners" +
            ")",
            argNames = "context," +
                    "glideContext," +
                    "model," +
                    "transcodeClass," +
                    "requestOptions," +
                    "overrideWidth," +
                    "overrideHeight," +
                    "priority," +
                    "target," +
                    "targetListener," +
                    "requestListeners")
    public Object obtainRequest(ProceedingJoinPoint point,
                                Context context,
                                GlideContext glideContext,
                                Object model,
                                Class transcodeClass,
                                BaseRequestOptions<?> requestOptions,
                                int overrideWidth,
                                int overrideHeight,
                                Priority priority,
                                Target target,
                                RequestListener targetListener,
                                List<RequestListener> requestListeners) {
        try {
            Object[] args = point.getArgs();
            if (model == null || args == null || args.length != ARG_LEN || !GSConstant.inGsActivity) {
                return point.proceed();
            } else {
                VLog.d(TAG, "obtainRequest :" + model);
                //model可能是Drawable,Bitmap,GifDecoder,WebpDecoder等,只处理网络url和uri这两种类型
                RequestListener li = null;
                if (model instanceof String || model instanceof Uri) {
                    //监控逻辑在此处添加
                    li = new RequestListener() {
                        @Override
                        public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) {
                            return false;
                        }

                        @Override
                        public boolean onResourceReady(Object resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) {
                            return false;
                        }
                    };
                }
                if (li != null) {
                    if (requestListeners == null) {
                        requestListeners = new ArrayList<>();
                    } else {
                        //避免重复添加
                        Iterator<RequestListener> it = requestListeners.iterator();
                        while (it.hasNext()) {
                            RequestListener tmp = it.next();
                            if (tmp instanceof GlideImageLoadListenerProxy) {
                                it.remove();
                            }
                        }
                    }
                    requestListeners.add(li);
                    //向requestListeners添加我们的监听器
                    args[REQ_LI_INDEX] = requestListeners;
                }
                return point.proceed(args);
            }
        } catch (Throwable throwable) {
            VLog.e(TAG, "obtainRequest err : " + throwable.getMessage());
        }
        return null;
    }
}