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的源码