Listview plays a very important role in Android applications, but many developers have encountered a lot of trouble when using listview. A common problem is that the List displays a series of records with a thumbnail (product photos, user portraits, etc ), the thumbnail is identified by a remote URL address. How can we implement such an application scenario?
To avoid the delay caused by image downloading, all remote images should be loaded asynchronously, that is, images can be downloaded in a separate thread and displayed in the imageview after the image is downloaded. In Android, a new thread can be started like a normal Java thread, but when the thread wants to update the interface, handler must be used for the request; otherwise, the applicationProgramBrings potential harm.
Remoteimagehelper
To separate complicated logic, we write a class named remoteimagehelper to handle the problem of "downloading images asynchronously and updating images to the interface". This class can implement the following functions:
- Before the image is downloaded, a bitmap indicating "loading" is displayed in the imageview;
- The image is downloaded in the background and displayed in the imageview after the download is complete;
- If the image fails to be downloaded, imageview displays a bitmap indicating that the image fails to be downloaded;
Next let's take a look at the implementationCode:
First, you need a method to download the remote image. Here we do not need to download the image to your mobile phone, and directly return an inputstream result. If this method returns an error during running, check whether Android. Permission. Internet permission is added to androidmanifest. xml.
PrivateInputstream download (string urlstring)ThrowsMalformedurlexception, ioexception {inputstream= (Inputstream)NewURL (urlstring). getcontent ();ReturnInputstream ;}
Next is the most important method for loading images asynchronously. You can replace the "downloading" and "downloading failed" images as needed. The Code is as follows:
Private Final Map <string, drawable> cache = New Hashmap <string, drawable> (); Public Void LoadImage (Final Imageview, Final String urlstring, Boolean Usecache ){ If (Usecache && Cache. containskey (urlstring) {imageview. setimagedrawable (Cache. Get (urlstring ));} // Show a "loading" image here Imageview. setimageresource (R. drawable. image_indicator); log. D ( This . Getclass (). getsimplename (), "image URL:" + Urlstring ); Final Handler handler = New Handler () {@ override Public Void Handlemessage (message) {imageview. setimagedrawable (drawable) message. OBJ) ;}; runnable = New Runnable (){ Public Void Run () {drawable = Null ; Try {Inputstream is = Download (urlstring); drawable = Drawable. createfromstream (is, "src" ); If (Drawable! = Null ) {Cache. Put (urlstring, drawable );}} Catch (Exception e) {log. E ( This . Getclass (). getsimplename (), "image download failed", E ); // Show a "Download fail" Image Drawable = Imageview. getresources (). getdrawable (R. drawable. image_fail );} // Y ui thread to show this image using Handler Message MSG = handler. obtainmessage (1 , Drawable); handler. sendmessage (MSG );}}; New Thread (runnable). Start ();}
About cache: In this example, we use a hashmap in memory as the image cache, which is simple, but the cache will be cleared when the application exits. In actual projects, you can consider implementing a file-based Cache Mechanism to save the downloaded images to the SD card. Pay attention to regularly clear unused images for a long time to save storage space.
Use remoteimagehelper
How to use this class? The following is an example. Please note that, in order to achieve better demonstration results, when the LoadImage () method is called in the Code, the third parameter uses false to disable the image caching function. In the actual project, you may need to change to true to avoid repeated image downloads to improve performance.
List <myrecord> Examplerecords;Lazyimagehelper =NewLazyimagehelper (); Class Myadapter Extends Arrayadapter <myrecord> { Public Myadapter (context ){ Super (Context, R. layout. record_row, R. Id. lbllabel, examplerecords) ;}@ override Public View getview ( Int Position, view convertview, viewgroup parent) {view = Super . Getview (Position, convertview, parent); myrecord record = Getitem (position); textview lbllabel = (Textview) view. findviewbyid (R. Id. lbllabel); imageview = (Imageview) view. findviewbyid (R. Id. IMG); lbllabel. settext (record. getlabel ()); // For demo purpose, cache is disabled here. Lazyimagehelper. LoadImage (imageview, record. getimageurl (),False); // To enable cache, simply use following code: // Lazyimagehelper. LoadImage (imageview, record. getimageurl (), true ); Return View ;}}
In the above Code, myrecord is a simple pojo class that represents a business object. It has three attributes: ID, label, and imageurl. You can find it in the complete project code.
Code download
The APK file compiled by the example project aboveClick hereDownload and run on Android 2.1 or later.
TheSource codeClick hereDownload.
References
Handler
Message Processing Mechanism of Android
How do I do a lazy load of images in listview
Issue 13959: Make listviews more programmer friendly