ListView is similar to the use of WeChat circle of friends function refreshing, listview circle of friends

Source: Internet
Author: User
Tags addall

ListView is similar to the use of the circle of friends function refresh, listview circle of friends

This blog is followed by the previous one. The previous one is not perfect. Here we make improvements.

First, we need to clarify our thinking: It is very convenient to use ListView to display data. The data of ListVIew is connected through the adapter as a bridge. When we need to use listview to display a large amount of data, we need to use the paging function. For example, if we have one thousand pieces of data, we should separate the display of 1.1 points of data, for example, every time a user refreshes, I add 20 pieces of data and display it to the user. Each time, a certain amount of data is added to the user until the data does not exist. To improve the user experience, we should keep the last 20 latest data records displayed when the user exits locally. the user can view the data directly when they click in next time, when you click Refresh, load the latest 20 data on the server to the user, and overwrite the original data. Then, when you pull down to the bottom of 20 pieces of data, load the 20 pieces of data after that, so that the reciprocating loop can be implemented. I am only simulating this time.

First, how to determine whether a user needs to load new data is to listen to the scrolling event of the listview. When the user rolls to tHe bottommost screen, one of the following can be uniquely determined, the position + 1 of the last data displayed on the current user's screen is equal to the total data volume. At this time, we should add new data and open a new thread to complete the work. Then, use handler to add the data to the data of the adapter, and then call adapter. yydatasetchanged () to update the ListVIew. But there are some issues that need attention.

1. We need to ensure that new data can be loaded only when all the downloaded data is loaded to the data of the adapter after clicking the pull-down and refresh. This is because some users may be impatient, continuously pull down the listview, resulting in the continuous display of the last piece of data + 1 is equal to the total data volume, constantly trigger the thread to download new data, so we need to have a flag to control.

2. All data downloads need to be completed through a thread or asynchronous tasks. We recommend that you use Asynchronous tasks when downloading images, it is assumed that many threads will be enabled to download images during quick scrolling. asynchronous tasks can control the number of threads or use the Imageloder framework.

3. cache images. Every time we load new resources, we need to overwrite the latest 20 data records and save them locally, he should open a thread to complete every time he requests data. Note that the input stream of each request can only be used once. Therefore, you need to write data locally to the memory. Therefore, you need to request two data streams to obtain two data streams. Here, you can see getData () method.

Code details:

MainActivity

Public class MainActivity extends Activity {// each time the latest data is saved to the local device, the latest data can be directly displayed the next time you click it, // After the user refresh the data from the drop-down list, read the data from the refresh drop-down list to the file, each time the user clicks it, it is the last latest File, but the File is not refreshed now. public static final File saveXMLToSD = new File (Environment. getExternalStorageDirectory (), "list. xml "); private ListView listview; // listviewprivate File cache; // cache directory public static final int OK = 1; // The public static final int is obtained successfully. YES = 2; // obtain the latest data publi C static final int ERROR =-1; // failure to obtain data private boolean flag = true; private View footer; private ListAdapter adapter; private boolean isFinsh = false; // bind the adapter after the data is downloaded. When the user clicks the screen for the first time, the private Handler mHandler = new Handler () {@ SuppressWarnings ("unchecked") will not be abnormal ") public void handleMessage (android. OS. message msg) {if (msg. what = OK) {adapter = new ListAdapter (MainActivity. this, R. layout. list_item, cache, (Lis T <Contacts>) msg. obj); System. out. println ("(List <Contacts>) msg. obj "+ (List <Contacts>) msg. obj ). size (); listview. addFooterView (footer); // Add a footer to improve the user experience of listview. setAdapter (adapter); // bind the adapter listview. removeFooterView (footer); // no explicit footer for the first time} if (msg. what = YES) // the latest data is loaded successfully {flag = true; // you can continue downloading the data adapter at this time. setData (List <Contacts>) msg. obj); adapter. notifyDataSetChanged (); // notifies you that the data has been changed successfully. Update ListViewif (listvie W. getFooterViewsCount ()> 0) listview. removeFooterView (footer); // if a footer exists, data is completely loaded.} if (msg. what = ERROR) {Toast. makeText (getApplicationContext (), "network connection failed", Toast. LENGTH_SHORT ). show () ;};};@ Overrideprotected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); listview = (ListView) findViewById (R. id. listview); cache = new File (Environme Nt. getExternalStorageDirectory (), "cahce"); if (! Cache. exists () cache. mkdirs (); footer = getLayoutInflater (). inflate (R. layout. footer, null); // load the footer listview. setOnScrollListener (new ListViewScrollListener (); // listens to the rolling event new Thread (new Runnable () {public void run () {try {List <Contacts> data = new ArrayList <Contacts> (); if (! SaveXMLToSD. exists () {// data. addAll (ContactsService. getData (); // load data when the object does not exist for the first time. addAll (ContactsService. getData ();} else {// read data from the user's xml file when the first data exists, which gives the user a quick feeling, the last login result is displayed for each login. FileInputStream is new FileInputStream (saveXMLToSD); // data = ContactsService. parserXML (FCM); data. addAll (ContactsService. parserXML (FCM);} Message msg = Message. obtain (); msg. what = OK; msg. obj = data; mHandler. sendMessage (msg); // message sent successfully} catch (Exception e) {mHandler. sendEmptyMessage (ERROR); e. printStackTrace ();}}}). start ();} class ListViewScrollListener implements OnScrollListener {public void onScrollStateChanged (AbsListView view, int scrollState) {}/*** number of items visible on the position * visibleItemCount screen of the first visible item on the firstVisibleItem screen, * totalItemCount total data volume */public void onScroll (AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {int lastItemId = listview. getLastVisiblePosition (); // positionSystem of the last visible item in the screen. out. println ("lastItemId =" + lastItemId + "firstVisibleItem =" + firstVisibleItem + "visibleItemCount =" + visibleItemCount + "totalItemCount =" + totalItemCount ); // when the last part of the visible item reaches the total number, it indicates that the user has reached the lowest part of the data, at this time, you should obtain the latest data from the network if (lastItemId + 1 = totalItemCount & totalItemCount> 0) {if (flag) {flag = false; // Prevent Users From pulling down the listview continuously, so once the data is downloaded from the drop-down list to the lowest end, it is immediately set to false. Only after the data is downloaded is set to true in handlr. // at this time, the flag value is true, because at the bottom of the drop-down list, we need to completely retrieve the pull-down for this time without loading it again. Instead, it takes time to get it from a thread. Therefore, we must set the flag value to truelistview first. addFooterView (footer); // enable the Thread to load the latest data. new Thread (new Runnable () {@ Overridepublic void run () {try {Thread. currentThread (). sleep (3000); List <Contacts> data = ContactsService. getData (); Message msg = Message. obtain (); msg. what = YES; msg. obj = data; mHandler. sendMessage (msg);} catch (Exception e) {mHandler. sendEmptyMessage (-1); e. printStackTrace ();}}}). start () ;}}}// when the user exits the current application, delete all cached images @ Overrideprotected void onDestroy () {if (cache. exists () {for (File item: cache. listFiles () {item. delete ();} cache. delete ();} super. onDestroy (); // This sentence must be required, otherwise it will fail }}
Adapter, download images, bind data, and update data

Public class ListAdapter extends BaseAdapter {public List <Contacts> data = new ArrayList <Contacts> (); private int listItem; private File cache; private LayoutInflater inflater; private Contacts contact; private static ImageView imageview;/*** @ return the data */public List <Contacts> getData () {return data ;} /*** @ param data the data to set */public void setData (List <Contacts> data) {this. data. addAll (data) ;} Public ListAdapter (Context mainActivity, int listItem, File cache, List <Contacts> data) {this. data. addAll (data); this. listItem = listItem; this. cache = cache; inflater = (LayoutInflater) mainActivity. getSystemService (Context. LAYOUT_INFLATER_SERVICE);} @ Overridepublic int getCount () {return data. size () ;}@ Overridepublic Object getItem (int position) {return data. get (position) ;}@ Overridepublic long get ItemId (int position) {return position ;}@ Overridepublic View getView (int position, View convertView, ViewGroup parent) {ViewHolder holder = null; if (null = convertView) {convertView = inflater. inflate (listItem, null); holder = new ViewHolder (); holder. imageview = (ImageView) convertView. findViewById (R. id. imageview); holder. textView = (TextView) convertView. findViewById (R. id. textview); convertView. setTag (Holder);} else {holder = (ViewHolder) convertView. getTag () ;}contact = data. get (position); holder. textView. setText (contact. name); imageview = holder. imageview; loadImageView (contact. path); return convertView;} static class ViewHolder {ImageView imageview; TextView textView;} private void loadImageView (String path) {new myasynctask(imageviewcmd.exe cuteOnExecutor (AsyncTask. THREAD_POOL_EXECUTOR, path);} private cl Ass MyAsyncTask extends AsyncTask <String, Void, Uri> {private ImageView imageView; public MyAsyncTask (ImageView imageView) {super (); this. imageView = imageView;} // download the image in the background and use the thread pool control. You can also reuse the thread object @ Overrideprotected Uri doInBackground (String... params) {String path = params [0]; try {Uri uri = ContactsService. loadSaveImage (path, cache); return uri;} catch (Exception e) {e. printStackTrace ();} return null;} @ Overridepr Otected void onPostExecute (Uri result) {if (result! = Null & imageView! = Null) imageView. setImageURI (result); // directly update ImageViewelse if (imageView! = Null) {imageView. setImageResource (R. drawable. ic_launcher); // default image }}}}
Service, download data, cache images, parse XML

Public class ContactsService {/*** returns the latest data list set ** @ return * @ throws Exception * @ throws IOException */public static List <Contacts> getData () throws Exception, IOException {String pathXML = "http: // 10.10.117.197: 8080/web/list2.xml"; HttpClient client = new DefaultHttpClient (); HttpPost post = new HttpPost (pathXML ); httpResponse httpResponse = client.exe cute (post); if (200 = httpResponse. getStatusLi Ne (). getStatusCode () {HttpEntity entity = httpResponse. getEntity (); final InputStream content = entity. getContent (); new Thread (new Runnable () {public void run () {saveToSD (content ); // each time the latest data is downloaded, it must be saved locally }}). start (); return parserXML(client.exe cute (post ). getEntity (). getContent (); // return the latest data to the listview display} return null;}/*** Parse XML data, return * @ param content * @ return * @ throws Exception */public static Lis in a collection. T <Contacts> parserXML (InputStream content) throws Exception {XmlPullParser parser = Xml. newPullParser (); parser. setInput (content, "UTF-8"); int event = parser. getEventType (); List <Contacts> data = new ArrayList <Contacts> (); Contacts item = null; int I = 1; while (event! = XmlPullParser. END_DOCUMENT) {switch (event) {case XmlPullParser. START_TAG: if ("contact ". equals (parser. getName () {item = new Contacts (); item. id = Integer. valueOf (parser. getAttributeValue (0); break;} if ("name ". equals (parser. getName () {item. name = parser. nextText () + I ++; break;} if ("image ". equals (parser. getName () {item. path = parser. getAttributeValue (0); break;} break; case XmlPullParser. END_TAG: if ("co Ntact ". equals (parser. getName () {data. add (item); item = null;} break;} event = parser. next ();} return data;}/*** Save the latest data locally ** @ param content * input stream */private static void saveToSD (InputStream content) {try {FileOutputStream fos = new FileOutputStream (MainActivity. saveXMLToSD); int len; byte [] buffer = new byte [1024]; while (len = content. read (buffer ))! =-1) {fos. write (buffer, 0, len);} fos. close ();} catch (FileNotFoundException e) {e. printStackTrace ();} catch (IOException e) {e. printStackTrace ();}} /*** cached image ** @ param path * download path * @ param cache * cache directory * @ return * @ throws Exception */public static Uri loadSaveImage (String path, file cache) throws Exception {File localFile = new File (cache, MD5.getMD5 (path) + path. substring (path. lastIndexOf (". "); if (LocalFile. exists () {return Uri. fromFile (localFile);} else {BufferedOutputStream response = null; HttpResponse httpResponse = null; FileOutputStream localFileOutputStream = new FileOutputStream (localFile); response = new response (localFileOutputStream ); httpClient client = new DefaultHttpClient (); HttpPost post = new HttpPost (path); httpResponse = cli Ent.exe cute (post); if (200 = httpResponse. getStatusLine (). getStatusCode () {InputStream content = null; try {HttpEntity entity = httpResponse. getEntity (); content = entity. getContent (); int len; byte [] buffer = new byte [1024]; while (len = content. read (buffer ))! =-1) {localFileBufferedOutputStream. write (buffer, 0, len); localFileBufferedOutputStream. flush ();} return Uri. fromFile (localFile);} catch (IllegalStateException e) {e. printStackTrace ();} catch (IOException e) {e. printStackTrace ();} finally {try {localFileBufferedOutputStream. close ();} catch (IOException e) {e. printStackTrace () ;}}} return null ;}}
Domain

public class Contacts{public int id;public String name;public String path;public Contacts (){}public Contacts (int id , String name , String path){super();this.id = id;this.name = name;this.path = path;}@Overridepublic boolean equals(Object o){return false;}}
Util class MD5 name

public class MD5 {public static String getMD5(String content) {try {MessageDigest digest = MessageDigest.getInstance("MD5");digest.update(content.getBytes());return getHashString(digest);} catch (NoSuchAlgorithmException e) {e.printStackTrace();}return null;}    private static String getHashString(MessageDigest digest) {        StringBuilder builder = new StringBuilder();        for (byte b : digest.digest()) {            builder.append(Integer.toHexString((b >> 4) & 0xf));            builder.append(Integer.toHexString(b & 0xf));        }        return builder.toString();    }}

Layout File

Main

<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"    android:paddingBottom="@dimen/activity_vertical_margin"    android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin"    tools:context="com.example.asynctasklistdemo.MainActivity" >    <ListView        android:layout_width="match_parent"        android:layout_height="match_parent"        android:id="@+id/listview" /></LinearLayout>
Item of listview

<?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:gravity="center"    android:orientation="horizontal" >    <ImageView        android:id="@+id/imageview"        android:layout_width="100dp"        android:layout_height="100dp"        android:layout_gravity="center"        android:src="@drawable/ic_launcher" />    <TextView        android:id="@+id/textview"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_gravity="center"        android:textColor="#000000"        android:textSize="40sp" /></LinearLayout>

Footer

<LinearLayout xmlns: android = "http://schemas.android.com/apk/res/android" android: layout_width = "match_parent" android: layout_height = "match_parent" android: gravity = "center" android: orientation = "horizontal"> <ProgressBar android: layout_width = "wrap_content" android: layout_height = "wrap_content"/> <TextView android: layout_width = "match_parent" android: layout_height = "match_parent" android: text = "data is being loaded... "Android: textSize =" 20sp "android: layout_gravity =" center "/> </LinearLayout>

Permission:

    <uses-permission android:name="android.permission.INTERNET" />    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />

Result:








Related Article

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.