背景
Activity在加载显示之前一般会有一个Loading界面,给用户一个比较好的视觉体验,一般来说就是加载一个动画。动画则是一个animation-list,循环播放这个动画列表的图片即可
问题:
一般来说,如果只是一个ImageView没有什么太大问题,但是如果资源过多,或者将要显示的界面很复杂。Loading界面需要根据相应的回调方法改变不同的显示状态用来提升用户体验。那么这时候进入一个Activity或者一个Fragment首先进入的是你的Animation界面,但是想象一下,此时你的Loading界面布局复杂,动画图片又比较大的时候。在低端机上显示的话很有可能先黑那么一瞬间,这样的话苦心经营的用户体验大打折扣了。
TipView优化
一般来说显示一个动画,有一个很简单的方法,比如:
android:id="@+id/tip_loading_img" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@anim/tip_loading" />
或者直接在代码里实现:
loadingAnimation = (AnimationDrawable) tipLoadingImg.getBackground(); if (loadingAnimation != null) { loadingAnimation.start(); }
- 在这里遇到了一件很有意思的事情,我发现loadingAnimation.start()以及loadingAnimation = (AnimationDrawable) tipLoadingImg.getBackground();可以不用在UI线程里执行。想想也对,因为官方文档明确指出Animation Drawable必须在渲染之后执行。这也就意味着Animation在绘制的是在ImageView本身的空间,但是不会引起界面重绘,因此我觉的是可以在非UI线程操作的。如果你的TipView动画值播放的时候出现卡帧,可以试试这么做:
@Override public void run() { super.run(); Looper.prepare(); new Handler().post(new Runnable() { @Override public void run() { tipLoadingImg.setBackgroundResource(R.drawable.tip_loading); loadingAnimation = (AnimationDrawable) tipLoadingImg.getBackground(); if (loadingAnimation != null) { loadingAnimation.start(); } } }); } }.start();
那么这段代码是怎么操作的呢?
首先创建一个线程出来,然后在线程中创建一个Lopper,与一个handler.同时伴随着一个Message队列。lopper会从message队列取出数据扔给创建的handler执行,在这里执行的内容则是创建的匿名Runnable对象。
很不幸的是这么做在我们现在这个优化方案并不起作用,甚至初始化的时间还会延长,因为创建一个Thread,Looper,Handler,MessageQueue所花的时间要比收益要大。当然如果你维护一个全局的Thread,类似守护进程一样的守护线程就另当别论了。但是没必要真的做到这种地步吧。。感觉与收益有点不成正比了。说下我的实现思路。将状态分为几个模块,基础的,常用的作为基础模块。有点类似分段的意思,需要的就去加载,切换到另一个状态,发现还缺UI控件,那么接着去加载。这种策略比较适合我的这个工程。因为有一个状态90%都是它,只有在不太常用的情况才会切换到其他的状态。因此在new instance的时候初始化最基本的布局模板,这种状态在我的工程中90%的都会出现。如果在加载中出现要切换到其他状态则通过addView()的方式进行加载。
- ps:每个项目的工程都不一样,因此优化策略肯定也是因人而异
转载请注明出处:
http://blog.csdn.net/sanyinchen/article/details/50901579