One time to optimize the list page lag experience

Source: Internet
Author: User
Tags transparent color

写下这篇文章的日期是2016年4月初。当时来到公司,项目之前是外包出去的,代码乱糟糟的,需要重构掉,摆在面前的问题不是重构项目,而是一些列表页的紧急的性能优化。
1. Optimize the level of item first
其实层级只要不是太深的话,比如5层,6层,对性能的差别在中等性能的机器上几乎看不出来的,但是想要做到 极致,我就得死扣细节,原来代码是有4层的,其实有一点点接近可优化的范围了,我把原来的4层降到1层。1层的话在item的话,在cpu进行计算测量的时候就速度很快了。
Here's how I use DDMS to see a setAnd my deskThe control-level comparison of the list.

A list of the item's levels, layer three : Grid>Linear>Frame>Rela

The level of item on the list page of my platform 优化后 , one layer :Grid>Rela


In fact, enemy Units List page is also serious, and the visual control, enemy units than my Taiwan a round head of the control, bitmap accounted for the big head, although enemy units has a few textview, but TextView itself there is almost nothing to optimize the performance of things. But I still have to do more fluent than enemy units.

2. Optimization OverdrawThe issue of transition drawing.

The old code, first look at the code of the ListView GetView method:

@Override public View getView (int position, view Convertview, ViewGroup parent) {if (Convertview = = null) { Convertview = Layoutinflater. from(context). Inflate(R. Layout. Item_live_adapter, parent, false);} linearlayout layout_item_live = Baseviewholder. Get(Convertview, R. ID. Layout_item_live);if (position%2==0) {//The focus is here layout_item_live. setpadding( -, -,Ten,0);} else if (position%2==1) {layout_item_live. setpadding(Ten, -, -,0);} ImageView iv_item_live_cover = Baseviewholder. Get(Convertview, R. ID. IV_item_live_cover);TextView Tv_live_hostname = Baseviewholder. Get(Convertview, R. ID. TV_live_hostname);TextView Tv_item_live_viewernum = Baseviewholder. Get(Convertview, R. ID. TV_item_live_viewernum);TextView Tv_item_live_title = Baseviewholder. Get(Convertview, R. ID. TV_item_live_title);Circleimageview Iv_item_recycle_host_head = Baseviewholder. Get(Convertview, R. ID. IV_item_recycle_host_head);Bitmaputils. Configdefaultloadfailedimage(R. Mipmap. Live_default);Bitmaputils. Configdefaultloadingimage(R. Mipmap. Live_default);Bitmaputils. Display(Iv_item_live_cover, List_info. Get(position). Get("Thumb"). toString());Bitmaputils. Display(Iv_item_recycle_host_head, List_info. Get(position). Get("Avatar"). toString());Tv_live_hostname. SetText(List_info. Get(position). Get("Nick."). toString());int view = Integer. parseint(List_info. Get(position). Get("View"). toString());if (View >10000) {BigDecimal B1 = new BigDecimal (view);BigDecimal b2 = new BigDecimal (10000);Tv_item_live_viewernum. SetText(B1. Divide(B2,1, BigDecimal. ROUND_HALF_UP). Doublevalue()+"W");}else{Tv_item_live_viewernum. SetText(View +"");} tv_item_live_title. SetText(List_info. Get(position). Get("title"). toString());Return Convertview;}

setPaddingIn theory, it would be childMeasure a way to start, then a bunch of UI threads that are constantly going to compute things. Then the sub-level and self-control is not particularly small, so the problem here is also very big AH!!

The process of tracking the lag with TraceView CPU time is much more

When the old code runs, scrolling the list, in order to be fair, after the ListView has scrolled up and down, ensure that the memory of the picture is cached, clean down the log, and then scroll to crawl the following

The UI thread loops loop only when it is idle. If my list scrolling performance is not good, the percentage of loop occupied is definitely low. At present, the proportion of Looper is only about 50%.

Turn down, please look carefully 30 that line, although I selected 25 lines!!!

30 This line points to our own com.maimiao ... A custom control that takes up 35% of the CPU time, so it's a bit serious here. If this 35% is removed, it is basically close to 90% Loope.

Some ways to post this custom control that TraceView points to

RoundImageViewByXfermodeThis class is a custom control that is used in the old code to make rounded corners. In fact, there are three ways to achieve the fillet, I sort by the level of performance down said,

  • First, draw a rectangular chart, do not fix the fillet, use and the background color consistent overcolor cover Four Corners
  • The second kind, bitmapshader.
  • The third Kind, xfermode. This is what the old code is used for.
    @SuppressLint("Drawallocation")@Override    protected void OnDraw(Canvas canvas) {//Remove the bitmap in the cacheBitmap Bitmap = Mweakbitmap = =NULL?NULL: Mweakbitmap.get ();if(NULL= = Bitmap | | Bitmap.isrecycled ()) {//Get drawabledrawable drawable = getdrawable ();if(Drawable! =NULL)            {//Get drawable width and height                intDwidth = Drawable.getintrinsicwidth ();intDheight = Drawable.getintrinsicheight ();//Create bitmapBitmap = Bitmap.createbitmap (GetWidth (), GetHeight (), config.argb_8888);floatScale =1.0F//Create canvasCanvas Drawcanvas =NewCanvas (bitmap);//According to the width of the bitmap and the width of the view, calculate the scaling ratio, because the src width and height ratio of the set may be different from the ImageView, we do not want the picture to be distorted;                if(type = = Type_round) {//If the width or height of the picture does not match the width and height of the view, the scale is calculated, and the width of the scaled image must be greater than the width of our view, so we take a large value here;Scale = Math.max (getwidth () *1.0F/dwidth, GetHeight () *1.0F/dheight); }Else{scale = GetWidth () *1.0F/math.min (Dwidth, dheight); }//According to the scale, set bounds, which is equivalent to zooming the picture.Drawable.setbounds (0,0, (int) (Scale * dwidth), (int) (scale * dheight)); Drawable.draw (Drawcanvas);if(Mmaskbitmap = =NULL||                Mmaskbitmap.isrecycled ()) {Mmaskbitmap = Getbitmap (); }//Draw Bitmap.Mpaint.reset (); Mpaint.setfilterbitmap (false); Mpaint.setxfermode (Mxfermode);//Draw ShapesDrawcanvas.drawbitmap (Mmaskbitmap,0,0, Mpaint); Mpaint.setxfermode (NULL);//Draw the prepared bitmapCanvas.drawbitmap (Bitmap,0,0,NULL);//bitmap Cache, avoid each call to OnDraw, allocate memoryMweakbitmap =NewWeakreference<bitmap> (BITMAP); }        }//If the bitmap is still present, draw directly        if(Bitmap! =NULL) {Mpaint.setxfermode (NULL); Canvas.drawbitmap (Bitmap,0.0F0.0F, Mpaint);return; }    }/** * Draw shape * @return  * *     PublicBitmapGetbitmap() {Bitmap Bitmap = Bitmap.createbitmaps (GetWidth (), GetHeight (), config.argb_8888); Canvas Canvas =NewCanvas (bitmap); Paint paint =NewPaint (Paint.anti_alias_flag); Paint.setcolor (Color.Black);if(type = = Type_round) {Canvas.drawroundrect (NewRECTF (0,0, GetWidth (), GetHeight ()), Mborderradius, Mborderradius, paint); }Else{canvas.drawcircle (getwidth ()/2, getwidth ()/2, getwidth ()/2, paint); }returnBitmap }
如上,代码明显性能很差,createBitmap,Bitmap的色彩用的也是ARGB_8888,内存消耗也很大,同时还频繁使用setXfermode模式,这些东西都在UI线程走,性能极差。

In order to prove that TraceView did not deceive me, I did not wronged him, I changed the custom control to imageview,padding also removed, the performance has indeed increased very high.

In order to solve these problems, I intend to use fresco to complete these work, Fresco's old club to optimize the performance of Android to achieve the ultimate, research for many years, but also contributed to a lot of literature and materials open source of things.

Fresco, there are two options for fillets and circles
  • The first kind, overlay_color, is the normal display of a square chart, the corner of the place with non-transparent color to draw the scheme of occlusion, this performance is very high. However, it is not available if the background of the control is opaque.

  • The second, bitmap_only, prototype he is using Bitmapshader to complete the performance is not how, but fresco only try to help you do not repeat the creation of BITMAP and other performance problems, to achieve round or rounded corners.

fresco绝对不用xfermode方案。
Use Systemclock to capture time-consuming GetView or Bindholder method lines

It is time-consuming to post the code snippet in the GetView before optimizing, and in order to be fair, do not record Layoutinflat this line of code in. Because after I hit refactoring the list, I used the Recyclerview,bind method and the Create method is separate, I want to ensure fairness.

Obviously, the old GetView code has obviously had a time-consuming jitter problem, and after refactoring the BindHolder code's CPU time-consuming standard is between 2-4ms and later posted. Old code He really can run to 7, in fact, some places did not cut, there are 10ms, a getview are 10ms, that some log can not see the place to be more serious, which is why this list so card reason.

android屏幕刷新频率是16ms,如果一旦UI线程繁忙超过16ms,那么就很容易被看出卡顿,当然页面静止的情况下页面卡顿的话也是很难看出来,因为卡是静止的,不卡也是静止的。但是到列表页上之后,就不同了,到了列表页,很多问题都容易被凸显出来,滚动不流畅,明显掉帧,这些都要去仔细找问题。

In order to find the GetView CPU time jitter problem, I first guess some third-party things, that is xutils, and then baseviewholder the code to find the view, his internal is sparsearray, theoretically speaking, the performance is quite high, So first start with xutils, I can't blame xutils without proof, so I hit log again in Xutils that three or four lines of code, do not crawl other code time consuming.

In order to ensure fairness, I scroll a few times up and down, and so xutils the pictures are cached in memory, I clear the log, start scrolling, see the data is like this.

It is clear, here only crawl xutils three or four lines of code, incredibly have two times his CPU time to 4, quiet time can also be 0, so, undoubtedly this place xutils.

Here is the refactoring scenario

After refactoring

After the reconstruction here the fillet and round are used fresco to complete these, the large figure of the fillet because the background color is white can be used Overlay_color, the circle head background needs to be transparent, so still have to bitmap_only mode.

Post-refactoring Bindholder code @Override public void Onbinditemviewholder (Livefragholder holder, final int position) { String url=getlist (). Get(position). Get("Avatar"). toString()+"";Frescoutils. Displayavatar(Holder. IV_item_recycle_host_head,url);Frescoutils. Displayurl(Holder. IV_item_live_cover, GetList (). Get(position). Get("Thumb"). toString());Holder. TV_live_hostname. SetText(GetList (). Get(position). Get("Nick."). toString());int view = Integer. parseint(GetList (). Get(position). Get("View"). toString());if (View >10000) {BigDecimal B1 = new BigDecimal (view);BigDecimal b2 = new BigDecimal (10000);Holder. TV_item_live_viewernum. SetText(B1. Divide(B2,1, BigDecimal. ROUND_HALF_UP). Doublevalue()+"W");}else{Holder. TV_item_live_viewernum. SetText(View +"");} Holder. TV_item_live_title. SetText(GetList (). Get(position). Get("title"). toString());Final Context Context=holder. IV_item_live_cover. GetContext();Holder. IV_item_live_cover. Setonclicklistener(New View. Onclicklistener() {@Override public void OnClick (view view) {hashmap<string,string> Mob_map = new Hashmap<> ();Because some circles are still using Hasmap Mob_map. Put("Position", Position +"");Mobclickagent. OnEvent(Context, Umengcollectconfig. ZB_FL,MOB_MAP);Bundle bundle = new Bundle ();Bundle. putstring("UID", GetList (). Get(position). Get("UID"). toString());Intent Intent = new Intent ();Intent. SetClass(Context, Theliveactivity. Class);Intent. Putextras(bundle);Context. StartActivity(Intent);}        });}

Take a look at the data that TraceView crawled after the optimization of the scrolling process.

Clearly see a point where 90.2% of the time is spent on Looper.loop. This means that the UI thread only goes through loop loops when it is idle. If my list scrolling performance is not good, the percentage of loop occupied is definitely low.

Make a millisecond timestamp at the beginning of my code, and BindHoder make a record at the end, and compare the difference between two timestamps to see how long My code is taking BindHoder .

CPU time-consuming standard between 2-4ms. Very stable, no phenomenon of wandering.

Absolutely perfect!!! Compared to the list page of enemy units, the enemy Units list page that is visible to the naked eye is worse than ours, and the other's item is more than we have a control of a round head. Finally can Pat ARM said we better than enemy units performance.
目前这个列表页,我台依旧要比敌台性能好,只是首页的第一个tab页面,我台也很卡,敌台也很卡,只是目前我还没有抽出时间去处理第一个tab页,后期会去优化,另外就是我台是哪里,我台是**全民TV**。

This is my public number, dare to sweep me, give you good-looking!

One time to optimize the list page lag experience

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.