This article translated from: http://developer.android.com/training/displaying-bitmaps/process-bitmap.html
If the source image is from a disk or network (or any other place outside the memory), The bitmapfactory discussed in "Loading Large bitmap efficiently. the decode * method should not be executed in the main UI thread. The time required to attach an image is unpredictable and depends on various factors (such as the reading speed of the disk or network, the size of the image, and the CPU processing capability ). If one of these factors blocks the UI thread, the system marks your application as a non-responsive program and you can choose to close it.
This article discusses how to use asynctask to process bitmaps in background threads and how to handle concurrency issues.
Use asynctask
The asynctask class provides an easy way to execute some tasks in the background thread and returns the execution results to the UI thread. To use it, you must create a subclass and override the corresponding method. The following is an example of loading a large bitmap to an imageview using the asynctask class and decodesamplebitmapfromresource () method:
Classbitmapworkertaskextendsasynctask <integer, void, bitmap> {
Private Final weakreference <imageview> imageviewreference;
Private int DATA = 0;
Public bitmapworkertask (imageview ){
// Use aweakreference to ensure the imageview can be garbage collected
Imageviewreference = new weakreference <imageview> (imageview );
}
// Decode image inbackground.
@ Override
Protected bitmap doinbackground (integer... Params ){
Data = Params [0];
Return decodesampledbitmapfromresource (getresources (), data, 100,100 ));
}
// Once complete, see ifimageview is still around and set bitmap.
@ Override
Protected void onpostexecute (Bitmap bitmap ){
If (imageviewreference! = NULL & bitmap! = NULL ){
Final imageview = imageviewreference. Get ();
If (imageview! = NULL ){
Imageview. setimagebitmap (Bitmap );
}
}
}
}
Use weakreference for the imageview object to ensure that asynctask does not affect the imageview object and any reference to this object that is put in the garbage collection bin. Therefore, when the task is completed, the imageview object does not exist. Therefore, you must check the reference in the onpostexecute () method. For example, if the user leaves the activity or the related configuration changes before the task is completed, the imageview may no longer exist.
To load bitmap asynchronously, you just need to create a new task and execute it:
Publicvoidloadbitmap (int
Resid, imageviewimageview ){
Bitmapworkertask task = new bitmapworkertask (imageview );
Task.exe cute (resid );
}
Processing concurrency
When a view component such as listview and gridview is used with asynctask, another problem is introduced. To improve the memory usage efficiency, these components reclaim the sub-view when the user scrolls. If each sub-view triggers an asynctask task, it cannot be ensured that the related sub-view will not be recycled before the asynctask task is completed. In addition, asynchronous tasks cannot be completed in the startup sequence.
Create a dedicated drawable subclass to store work task references. In this article, bitmapdrawable is used to display the corresponding image in imageview when the task is completed.
Staticclassasyncdrawableextendsbitmapdrawable {
Private Final weakreference <bitmapworkertask> bitmapworkertaskreference;
Public asyncdrawable (Resources res, Bitmap bitmap,
Bitmapworkertask ){
Super (Res, bitmap );
Bitmapworkertaskreference =
New weakreference <bitmapworkertask> (bitmapworkertask );
}
Public bitmapworkertaskgetbitmapworkertask (){
Return bitmapworkertaskreference. Get ();
}
}
Before executing bitmapworkertask, you need to create an asyncdrawable object and bind it to the target imageview object:
Publicvoidloadbitmap (int
Resid, imageviewimageview ){
If (cancelpotentialwork (resid, imageview )){
Final bitmapworkertask task = new bitmapworkertask (imageview );
Final asyncdrawableasyncdrawable =
New asyncdrawable (getresources (), mplaceholderbitmap, task );
Imageview. setimagedrawable (asyncdrawable );
Task.exe cute (resid );
}
}
The cancelpotentialwork method in the preceding code checks whether other running tasks are associated with the imageview object. If it is associated, it will try to call the cancel () method to cancel the previous task. In a few cases, the data of a new task will match the existing task and there will be no other requirements. The implementation of the cancelpotentialwork method is as follows:
Publicstaticbooleancancelpotentialwork (int
Data, imageviewimageview ){
Final bitmapworkertaskbitmapworkertask = getbitmapworkertask (imageview );
If (bitmapworkertask! = NULL ){
Final int bitmapdata = bitmapworkertask. Data;
If (bitmapdata! = Data ){
// Cancel previous Task
Bitmapworkertask. Cancel (true );
} Else {
// The same work is already in progress
Return false;
}
}
// No task associated withthe imageview, or an existing task was canceled
Return true;
}
An auxiliary method: getbitmapworkertask () is used to obtain the imageview object associated with the preceding task:
Privatestaticbitmapworkertaskgetbitmapworkertask (imageviewimageview ){
If (imageview! = NULL ){
Final drawable = imageview. getdrawable ();
If (drawable instanceof asyncdrawable ){
Final asyncdrawable = (asyncdrawable) drawable;
Return asyncdrawable. getbitmapworkertask ();
}
}
Return NULL;
}
Finally, update the onpostexecute () method of the bitmapworkertask class so that it can check whether the task is canceled and whether the current task is assigned a matching imageview object:
Classbitmapworkertaskextendsasynctask <integer, void, bitmap> {
...
@ Override
Protected void onpostexecute (Bitmap bitmap ){
If (iscancelled ()){
Bitmap = NULL;
}
If (imageviewreference! = NULL & bitmap! = NULL ){
Final imageview = imageviewreference. Get ();
Final bitmapworkertask =
Getbitmapworkertask (imageview );
If (this = bitmapworkertask & imageview! = NULL ){
Imageview. setimagebitmap (Bitmap );
}
}
}
}
Now, this implementation can be applied to listview and gridview components, as well as any other components that recycle child views. By simply calling the loadbitmap method, you can set an image to an imageview object. For example, this mode is implemented in the getview method supported by the adapter in the gridview.
Sample Code: http://download.csdn.net/detail/fireofstar/4874551