Android-----takes you step by step to optimize the ListView (i)

Source: Internet
Author: User

The ListView is the most commonly used control in Android, can display a large amount of data as an entry, is often used to display a list of recent contacts, and for each Item, adapter's GetView method is required to return a view, So the implementation of the ListView is inseparable from the adapter, if the idea of MVC to see the ListView, the ListView is equivalent to the v,adapter portion of C, and the data portion is the equivalent of M, The next few blog plans for the ListView self-understanding of some of the optimization measures to summarize, hoping to help everyone;

Let's take a look at the ListView method if we don't use any optimization measures:

Here are three ways to get Layoutinflater first:

(1) If you are in activity, you can call

Layoutinflater inflater = Getlayoutinflater ();

(2) If not in activity, you can use context context as an argument by

Context.getsystemservice (Context.layout_inflater_service);

(3) if it is not in the activity, you can use the context as a parameter, by

Layoutinflater Inflater = layoutinflater.from (context);

First define the Activity interface layout listview.xml, very simple, there is only one ListView

<linearlayout xmlns:android= "http://schemas.android.com/apk/res/android"    xmlns:tools= "http// Schemas.android.com/tools "    android:layout_width=" match_parent "    android:layout_height=" Match_parent "    tools:context= ". Mainactivity ">    <listview        android:id=" @+id/listview "        android:layout_width=" Match_parent        " android:layout_height= "Match_parent"/></linearlayout>
It is also simple to define the layout of each item of the ListView Item.xml, and only one TextView

<?xml version= "1.0" encoding= "Utf-8"? ><linearlayout xmlns:android= "http://schemas.android.com/apk/res/ Android "    android:layout_width=" match_parent "    android:layout_height=" match_parent "    android:o rientation= "vertical" >     <textview        android:id= "@+id/textview" android:layout_width= "Wrap_        Content "        android:layout_height=" 50DP "/></linearlayout>

Next, define a adapter, inherited from Baseadapter, to populate the ListView with data

public Class Listviewadapter extends baseadapter{list<string> List = new arraylist<string> (); Layoutinflater inflater = Null;public listviewadapter (list<string> list,context Context) {this.list = List; Inflater = Layoutinflater.from (context);} @Overridepublic int GetCount () {return list.size ();} @Overridepublic Object getItem (int position) {return list.get (position);} @Overridepublic long Getitemid (int position) {return position;} @Overridepublic view GetView (int position, view Convertview, ViewGroup parent) {view view = null; System.out.println ("Before:" +list.get (position) + "-------" +convertview); view = Inflater.inflate (R.layout.item,    NULL); System.out.println ("After:" +list.get (position) + "-------" +view); TextView TextView = (TextView) View.findviewbyid (R.id.textview); Textview.settext (List.get (position)); return view;}} 

It can be found that we did not do any optimization in the GetView, we will see what the problem is in this way;

Define activity, bind adapter to the ListView

public class Mainactivity extends Activity {list<string> List = new arraylist<string> (); ListView listview = null; @Overrideprotected void OnCreate (Bundle savedinstancestate) {super.oncreate ( Savedinstancestate); Setcontentview (R.layout.listview); listview = (ListView) Findviewbyid (R.id.listview); for (int i = 1;i < 50;i++) {List.add ("item" +i);} Listviewadapter adapter = new Listviewadapter (list, this); Listview.setadapter (adapter);}}
quite simply, we simulated a ListView with 50 entries and passed it to adapter using the Listviewadapter constructor to present the data in the interface;

Run:


The corresponding Logcat output:


You can see that the initial state has 10 item displayed on the interface, and their before view is null, and the new view is generated after calling the inflate method, so after view is not empty;

Then we drag the screen up and we can see the following output in Logcat:

You can see that item 19 and item 20 at this time Convertview the address is @4181a590 before before, this view is the item 9 that has been drawn off the screen, this can be seen from the output of the first screen, because item 9 has been added to the RecycleBin cache , so when calling the GetView method Convertview gets a random view,item 19 and item in the cache 20 is completely possible to get to the same view, but their after view is unlikely to appear the same, which means that the address value of the after view in our example is not the same, because we have simulated 50 item, So there will be 50 view is put into the RecycleBin cache , perhaps now for our display is nothing, then if there is a lot of information need to display, directly will report memory;

By the above we will find that when calling the GetView method, his second argument may not be null, because the RecycleBin cache helps us to temporarily save the view of the screen. So we have no need to re-call the inflate method to load the layout when the Convertview is not empty, because this method is also to parse the XML file, at least take the time, directly using the view removed from the cache, Let's take a look at the RecycleBin cache plot provided by the ListView:

Photo from: https://hit-alibaba.github.io/interview/Android/basic/ListView-Optimize.html

As you can see from the above figure, when item 1 is scratched, it is placed in the recycle cache, and when item 8 is to be drawn into the screen, if he is the same type as item 1, it is obtained directly from the recycle, i.e. Convertview is no longer null at this time If he does not match the item 1 type, a new view is created, i.e. Convertview equals null at this time;

Well, then we should make full use of the RecycleBin mechanism that Android provides to us to optimize the ListView;

You only need to modify the GetView method of the Listviewadapter class:

@Overridepublic view GetView (int position, view Convertview, ViewGroup parent) {view view = null; System.out.println ("Before:" +list.get (position) + "-------  " +convertview); if (Convertview = = null) {view = Inflater.inflate (R.layout.item, null);} Elseview = Convertview; TextView TextView = (TextView) View.findviewbyid (R.id.textview); Textview.settext (List.get (position)); return view;}
when you do not swipe the screen, the program outputs:

Then we swipe the screen to see the output:

Note The Red section, found that no 11 item, will be reused before the view, which means that our RecycleBin cache will only have 11 view, not as before there are 50 view, which saves memory to a large extent, think if there is thousands data need to display, Each data entry has a view in the recyclebin is how terrible thing, after the convertview is null judgment, will only cache a screen view, of course, there may be a few more it;

Above we have determined whether the convertview is empty to optimize the ListView, and then we look at the GetView method, which in the acquisition of TextView, we used the Findviewbyid method, which is related to the IO operation, must also affect performance bar, he only want to get a certain view of the layout, if we have a view, in fact, we only need the first time the view and its layout is bound together, there is no need to set the layout for the view each time, which is the purpose of using Settag;

Here is just a way to modify the Listviewadapter Geyview method:

@Overridepublic view GetView (int position, view Convertview, ViewGroup parent) {view view = null; Viewholder viewholder = null; System.out.println ("Before:" +list.get (position) + "-------  " +convertview); if (Convertview = = null) {view = Inflater.inflate (R.layout.item, null); Viewholder = new Viewholder (); Viewholder.textview = (TextView) View.findviewbyid (R.id.textview); View.settag (Viewholder);} Else{view = Convertview;viewholder = (viewholder) View.gettag ();} ViewHolder.textView.setText ("Item" +list.get (position)); return view;} Static class Viewholder{textview TextView;}
In this case, the static inner class is used to define the individual controls of the item, and if Convertview is not empty, it means that the layout of the view already exists and only needs to call Gettag to get it, if Convertview is empty, The control in this layout needs to be obtained through Findviewbyid, and finally the layout can be set through Settag to view;

The output of the program is the same as above, no longer listed here;

In our usual practical application, each entry may not be the same, and in this case there will be different layout of the project, so what should we do then? We also use examples to learn how this time the RecycleBin mechanism is how to implement the cache;

Here, we add an entry that shows only one button, layout file Button.xml

<?xml version= "1.0" encoding= "Utf-8"? ><linearlayout xmlns:android= "http://schemas.android.com/apk/res/ Android "    android:layout_width=" match_parent "    android:layout_height=" match_parent "    android:o rientation= "vertical" >    <button        android:id= "@+id/button"        android:layout_width= "Wrap_content"        android:layout_height= "Wrap_content"        /></linearlayout>
Modify the Listviewadapter class as follows:

public class Listviewadapter extends baseadapter{list<string> List = new arraylist<string> (); Layoutinflater inflater = Null;public listviewadapter (list<string> list,context Context) {this.list = List; Inflater = Layoutinflater.from (context);} @Overridepublic int Getitemviewtype (int position) {///0 means that the display is textview,1 to show buttonif (position% 4! = 0) return 0;else return 1;} @Overridepublic int Getviewtypecount () {///indicates there are two types of item layout return 2;} @Overridepublic int GetCount () {return list.size ();} @Overridepublic Object getItem (int position) {return list.get (position);} @Overridepublic long Getitemid (int position) {return position;} @Overridepublic view GetView (int position, view Convertview, ViewGroup parent) {view view = null; Textviewholder textviewholder = null; Buttonviewholder buttonviewholder = null; System.out.println ("Before:" +list.get (position) + "-------" +convertview); int type = Getitemviewtype (position); if ( Convertview = = null) {switch (type) {Case 0:view = inflater.inflate (r.laYout.item, null); Textviewholder = new Textviewholder (); Textviewholder.textview = (TextView) View.findviewbyid ( R.id.textview); View.settag (Textviewholder); TextViewHolder.textView.setText (List.get (position)); Break;case 1: View = Inflater.inflate (R.layout.button, null); Buttonviewholder = new Buttonviewholder (); Buttonviewholder.button = ( button) View.findviewbyid (R.id.button); View.settag (Buttonviewholder); ButtonViewHolder.button.setText ("button" + List.get (position)); break;default:break;}} Else{view = Convertview;switch (type) {case 0:textviewholder = (textviewholder) view.gettag (); TextViewHolder.textView.setText (List.get (position)); Break;case 1:buttonviewholder = (buttonviewholder) view.gettag (); ButtonViewHolder.button.setText ("button" +list.get (position)); break;default:break;}} return view;} Static class Textviewholder{textview TextView;} Static class Buttonviewholder{button Button;}}
the getviewtypecount () returns the number of layouts you have, and we have two

Returned by getitemviewtype (int) is the ID of the corresponding layout obtained from your position, of course, this ID can be determined by you;

Modify Activity Class

public class Mainactivity extends Activity {list<string> List = new arraylist<string> (); ListView listview = null; @Overrideprotected void OnCreate (Bundle savedinstancestate) {super.oncreate ( Savedinstancestate); Setcontentview (R.layout.listview); listview = (ListView) Findviewbyid (R.id.listview); for (int i = 1;i < 50;i++) {if (i% 4 = = 0) {list.add ("button" +i);} Elselist.add ("item" +i);} Listviewadapter adapter = new Listviewadapter (list, this); Listview.setadapter (adapter);}}
the interface runs as follows:

You can find that every 3 entries we load another different entry, and then look at the Logcat output:

After we swipe the screen, the output is:

Note that the highlighted section of the figure shows that for button item, we have also been reused, of course, the order of reuse is not necessarily sequential, because the recyclebin mechanism only caches the item that you have slid out of the screen, but when it is taken from the cache, is not necessarily in the order you have to take out, this should be noted, to this general ListView optimization test is over, let us summarize:

(1) By reusing view to take full advantage of the Android system itself with the RecycleBin cache mechanism, can guarantee that even if there are more than the actual item will only have a limited number of item, greatly saving memory;

(2) using the static inner class and the Settag method, the view is bound to its corresponding control, which avoids the need to get the control by Findviewbyid every time the view is obtained.

(3) for a ListView with multiple layouts, we can get the type of layout through getviewtypecount () , via getitemviewtype (int) To get the layout of the current position in the end belongs to which category;

Well, this article first introduced here, the next one will focus on the ListView loading image optimization measures;

Android-----takes you step by step to optimize the ListView (i)

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.