Most of the time we are using Baseadapter.getview () in the Convertview to improve the performance of the ListView, this time if my ListView item has an update ProgressBar, the result is tragic ... The sliding interface did not achieve the desired effect. It is easy to solve this problem, save the update progress in the data set, and then set the progress in GetView.
Another problem is that when there is a progress update, we are constantly madapter.notifydatasetchanged () to update the ListView? This can, of course, be very inefficient, knowing that the cost of notifydatasetchanged is very high. So, is there a better way? Of course, that's how you manually update item.
Below, we come to a step by step implementation of an optimal update, as to when the use of manual update, when the use of notify, I think in the case of frequent updating of data or only need to update a data to choose the former, the general situation or choose notify easier.
First, let's create an entity class that represents the task:
public class Task {private string name;private boolean isdownload;private int progress;public task () {}public Task (String Name) {this.name = name;} .... Setter and getter ...}
It is easy to understand that name represents the title of the task, isdownload indicates whether it is being downloaded, we will control the display and hiding of ProgressBar by isdownload below, progress of course is progress.
The layout of the ListView let's take a look:
<listview android:id= "@+id/list" android:layout_width= "wrap_content" android:layout_height= " Wrap_content " android:cachecolorhint=" @android: color/transparent " android:divider=" @android: color/ Darker_gray " android:dividerheight=" 1DP " android:listselector=" @android: Color/transparent "/>
There is also the layout of the ListView item:
<?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:paddingtop=" 10DP "an Droid:paddingbottom= "10DP" android:minheight= "Android:attr/listpreferreditemheight" android:orientation= " Vertical "> <textview android:id=" @+id/item_name "android:layout_width=" Match_parent "Androi d:layout_height= "Wrap_content"/> <progressbar android:id= "@+id/item_progress" style= "? android:attr /progressbarstylehorizontal "android:layout_width=" match_parent "android:layout_height=" Wrap_content " android:visibility= "Invisible"/></LINEARLAYOUT>
is the simplest layout, we skip directly, the layout of item contains a title and a progress bar.
How to simulate the download process? Look at the following code:
private void Download (final int positioninadapter) {... new Thread (new Runnable () {@Overridepublic void Run () {for (int i = 1; I < 101; i++) {Final int progress = I;runonuithread (new Runnable () {@Overridepublic void run () {publishprogress (positioninadapter , progress);}); Systemclock.sleep (500);}}). Start ();}
This code means to update the progress every 500ms, and positioninadapter This parameter represents the position of the item we clicked in the adapter (that is, in the data set).
I'm looking at how adapter wrote it.
public class Myadapter extends Baseadapter {private Context mcontext;private arraylist<task> mtasks;public Myadapter (Context context, arraylist<task> tasks) {Mcontext = Context;mtasks = tasks;} @Overridepublic int GetCount () {return mtasks.size ();} @Overridepublic Object getItem (int position) {return mtasks.get (position);} @Overridepublic long Getitemid (int position) {return position;} @Overridepublic view GetView (int position, view Convertview, ViewGroup parent) {final Viewholder holder;if (Convertview = = NULL) {Convertview = View.inflate (mcontext, r.layout.item, null); holder = new Viewholder (); holder.name = (TextView) conve Rtview.findviewbyid (r.id.item_name); holder.progress = (ProgressBar) Convertview.findviewbyid (r.id.item_progress); Convertview.settag (holder);} else {holder = (Viewholder) Convertview.gettag ();} Holder.name.setText (Mtasks.get (position). GetName ()); if (Mtasks.get (position). Isdownload ()) { Holder.progress.setVisibility (view.visible); Holder.progress.setProgress (mtasks. get (position). Getprogress ());} else {holder.progress.setVisibility (view.invisible);} return Convertview;} Static class Viewholder {TextView name; ProgressBar Progress;}}
one of the most common adapter notation, a little noteworthy is the 40~45 line, we determine whether to display and update ProgressBar according to Isdownload.
Here we have the basic work done, the following is to be in the activity to update the ListView item, rather than through the Notifydatasetchanged method.
In the activity, we use the ItemClick of the ListView to achieve the simulation download, in ItemClick we call the download method, look at the download we omit the code.
private void Download (final int positioninadapter) {mtasks.get (positioninadapter). Setdownload (True); if ( Positioninadapter >= mlistview.getfirstvisibleposition () && positioninadapter <= Mlistview.getlastvisibleposition ()) {int positioninlistview = Positioninadapter-mlistview.getfirstvisibleposition ( ); ProgressBar item = (ProgressBar) mlistview.getchildat (Positioninlistview). Findviewbyid (r.id.item_progress); Item.setvisibility (view.visible);} ...}
come on, let's go. Update the Boolean variable in the Task list that represents the download, indicating that the data is being downloaded.
The following judgment is the key, we need to determine whether the current click on the item is in the ListView's visible domain (this judgment is actually superfluous, since can click, certainly is visible, but in order to be rigorous, we still add this judgment), here why should so judge? View
In this diagram, the first visible item in our ListView should be 2 in the dataset, but 0 and 1 are invisible. So, we just need to determine whether the position in the current data set is between Listview.getfirstvisibleitem () and Listview.getlastvisibleitem () to determine whether the item is in the visible area.
Next line 5th, we get the current item position in the ListView via Positioninadapter-mlistview.getfirstvisibleitem (), if we click on position 4th in the corresponding image, Then we need to update item 4-2=2 in the ListView. Now we can get the ListView item again, of course we can get the item in the ProgressBar, 6~8 line, we get the exact ProgressBar, and update ProgressBar for the display state.
So far, the display of control ProgressBar can be achieved through ItemClick, of course, we did not use notifydatasetchanged ().
Next, let's see if the update is progressing. The process of updating the progress is mainly in the Publishprogress method.
public void publishprogress (final int positioninadapter, final int progress) {//mtasks.get (positioninadapter). Setdownload (True); Mtasks.get (Positioninadapter) setprogress (progress); if (Positioninadapter >= Mlistview.getfirstvisibleposition () &&positioninadapter <= mlistview.getlastvisibleposition ()) {int Positioninlistview = Positioninadapter-mlistview.getfirstvisibleposition (); ProgressBar item = (ProgressBar) mlistview.getchildat (Positioninlistview). Findviewbyid (r.id.item_progress); Item.setprogress (progress);}}
The code is very similar to the above, but the principle is the same.
First, take a look at the parameters of this method: Positioninadapter represents the position in the data set, progress represents the progress, this is not difficult to understand.
Next, we save the current progress by updating the progress of the corresponding entry in the task list, but we have no notify.
The same logic follows, except that we replace the control ProgressBar display with the update ProgressBar progress.
In this way, we implement the purpose of updating the ListView item without calling Notifydatasetchanged (). One obvious benefit of this is that every time we update only one item, the other item we don't update, and the notifydatasetchanged is implemented by saving the current location, updating all the item, and then recovering the location. Such a comparison, the advantages of our approach is reflected.
Some people may have doubts, how do we deal with it when we slide? Don't forget, we've updated the data in the Task list before the update, so when we swipe, we give Adapter.getview () to deal with it.
ListView Nested ProgressBar Update mode