工作生活

Android-Lottie与线程池结合产生的问题

2019-07-04  本文已影响0人  RookieRun

1.背景:项目中底部的tab动画使用的Lottie实现的,最近发现如下问题:

问题:1.动画未显示
    问题:2.动画显示之前,切换tab 在动画文件加载之后会导致多个选中的情况
    问题:3.断网的情况下,动画可以正常显示

2.问题分析:

项目中,首页新增一个LottieAnimationView,网速较慢的情况下,也不能显示
项目中,二级页面新增一个LottieAnimationView,网速较慢的情况下,也不能显示

当前的首页启动时,异步任务过多,UI线程被worker线程抢占,那为什么网速好的情况下,不会出现这种情况呢?
由此可见,LottieAnimationView的渲染,也是异步的,或者说,至少json文件的读取是异步的,在网速不好的情况下,多个异步任务无法及时返回,而线程池中的异步任务排队无法被及时执行,导致LottieAnimationView对应的json文件无法及时被读取,从而导致界面空白
那解决措施,就是,1.优化项目中异步任务的执行2.提高LottieAnimationView的线程优先级

3.代码分析:

项目中,引用的lottie是2.3.0,而该版本的LottieComposition类中的JsonCompositionLoader(用来执行json的加载和解析的)在执行异步任务的时候,使用的是AsyncTask默认的线程池(AsyncTask.THREAD_POOL_EXECUTOT)

 /**
     * Loads a composition from a raw json object. This is useful for animations loaded from the
     * network.
     */
    public static Cancellable fromJson(Resources res, JSONObject json,
        OnCompositionLoadedListener loadedListener) {
      JsonCompositionLoader loader = new JsonCompositionLoader(res, loadedListener);
      loader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, json);
      return loader;
    }
项目中的网络请求等耗时操作,也是使用的AsyncTask默认的线程池,
该线程池的CorePoolSize(核心线程数)是4个,最大线程数量17个,
工作队列是128个(数量因手机不同而有差异,公式不变)。
而打印的日志也发现,的确在初始化异步请求的时候,该方法的调用次数达到了40+,
而17个最大线程数量,显然会导致,部分异步任务会被放置到队列中。
image.png
AsyncTask
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    private static final int KEEP_ALIVE_SECONDS = 30;

    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);

        public Thread newThread(Runnable r) {
            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
        }
    };

    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);

    /**
     * An {@link Executor} that can be used to execute tasks in parallel.
     */
    public static final Executor THREAD_POOL_EXECUTOR;

    static {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                sPoolWorkQueue, sThreadFactory);
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
    }

以上就导致了当并行的任务过多,网速较慢的时候,队列中的异步任务排队过久的情况,进而导致了上述问题

解决:

方案1,修改项目中异步任务使用的线程池,可行
方案2,修改LottieAnimationView,可行,但是有局限性, 虽然可以解决这个lottie的问题,
但是,从整个项目层面上来考虑,不够完美,而且,需要修改lottie的源码
上一篇 下一篇

猜你喜欢

热点阅读