Analysis and Comparison of asynchronous loading of large amounts of data through AsyncTask and ThreadPool for Android Application Development

Source: Internet
Author: User


In today's example, we use a custom control written in the previous article. If you are interested, click here to study the implementation of this control first, in order to work with the asynchronous loading effect, I made some modifications to this control. The following will explain the changes.

Next, we will explain the implementation methods of ThreadPool and AsyncTask respectively. I will post the key code following the implementation idea, and post the Implementation Effect and source code download at the end of the article, if you are interested, you can download and compare them.

First, we will explain how ThreadPool is implemented.

First, we need to implement a thread pool manager, which contains an independent round-robin subthread, which is used to check the working queue from time to time. If there are unexecuted tasks in the queue, the task is handed over to the thread pool for execution. In addition, the thread pool manager is responsible for managing the thread pool and maintaining the task queue. The specific implementation code is as follows:

Package com. carrey. asyncloaddemo; import java. util. using list; import java. util. concurrent. executorService; import java. util. concurrent. executors; import android. util. log;/*** thread pool management class * @ author carrey **/public class ThreadPoolManager {private static final String TAG = "ThreadPoolManager "; /** thread pool size */private int poolSize; private static final int MIN_POOL_SIZE = 1; private static final int MAX_POOL_SIZ E = 10;/** thread pool */private ExecutorService threadPool;/** Request queue */private worker list <ThreadPoolTask> asyncTasks;/** Working Method */private int type; public static final int TYPE_FIFO = 0; public static final int TYPE_LIFO = 1;/** polling Thread */private Thread poolThread; /** polling time */private static final int SLEEP_TIME = 200; public ThreadPoolManager (int type, int poolSize) {this. type = (type = TYPE_FIFO )? TYPE_FIFO: TYPE_LIFO; if (poolSize <MIN_POOL_SIZE) poolSize = MIN_POOL_SIZE; if (poolSize> MAX_POOL_SIZE) poolSize = MAX_POOL_SIZE; this. poolSize = poolSize; threadPool = Executors. newFixedThreadPool (this. poolSize); asyncTasks = new queue list <ThreadPoolTask> ();}/*** Add a task to the task queue * @ param task */public void addAsyncTask (ThreadPoolTask task) {synchronized (asyncTasks) {Log. I (TAG, "add task:" + task. g EtURL (); asyncTasks. addLast (task) ;}}/*** extract task from task queue * @ return */private ThreadPoolTask getAsyncTask () {synchronized (asyncTasks) {if (asyncTasks. size ()> 0) {ThreadPoolTask task = (this. type = TYPE_FIFO )? AsyncTasks. removeFirst (): asyncTasks. removeLast (); Log. I (TAG, "remove task:" + task. getURL (); return task;} return null;}/*** enable thread pool polling * @ return */public void start () {if (poolThread = null) {poolThread = new Thread (new PoolRunnable (); poolThread. start () ;}/ *** end the round robin and close the thread pool */public void stop () {poolThread. interrupt (); poolThread = null;}/*** Runnable * @ author carrey **/private class PoolR Unnable implements Runnable {@ Overridepublic void run () {Log. I (TAG, "start polling"); try {while (! Thread. currentThread (). isInterrupted () {ThreadPoolTask task = getAsyncTask (); if (task = null) {try {Thread. sleep (SLEEP_TIME);} catch (InterruptedException e) implements thread.currentthread().interrupt();contincontinue##threadpool.exe cute (task);} finally {threadPool. shutdown ();} Log. I (TAG, "End Round Robin ");}}}
Note that in the above Code, we have customized the implementation of the task unit. The task unit is a series of Runnable objects and will be handed over to the thread pool for execution. The implementation code of the task unit is as follows:

ThreadPoolTask. java:

Package com. carrey. asyncloaddemo;/*** job unit * @ author carrey **/public abstract class ThreadPoolTask implements Runnable {protected String url; public ThreadPoolTask (String url) {this. url = url;} public abstract void run (); public String getURL () {return this. url ;}}

ThreadPoolTaskBitmap. java:

Package com. carrey. asyncloaddemo; import com. carrey. customview. customview. customView; import android. graphics. bitmap; import android. OS. process; import android. util. log;/*** task unit for image loading * @ author carrey **/public class ThreadPoolTaskBitmap extends ThreadPoolTask {private static final String TAG = "ThreadPoolTaskBitmap"; private CallBack callBack; private CustomView view; private int position; public Thread PoolTaskBitmap (String url, CallBack callBack, int position, CustomView view) {super (url); this. callBack = callBack; this. position = position; this. view = view ;}@ Overridepublic void run () {Process. setThreadPriority (Process. THREAD_PRIORITY_LOWEST); Bitmap bitmap = ImageHelper. loadBitmapFromNet (url); Log. I (TAG, "loaded:" + url); if (callBack! = Null) {callBack. onReady (url, bitmap, this. position, this. view) ;}} public interface CallBack {public void onReady (String url, Bitmap bitmap, int position, CustomView view );}}
The callback implementation in the above Code is located in MainActivity. in java, the main task in the run method of the job unit is to get the Bitmap of the image to be loaded from the server, and then call the callback, in the callback, the image is loaded into the UI.

The ImageHelper tool class is used when loading server images. The main function of this class is to obtain the server image address and parse the image. The specific code is as follows:

Package com. carrey. asyncloaddemo; import java. io. IOException; import java. io. inputStream; import java.net. URL; import java.net. URLConnection; import android. graphics. bitmap; import android. graphics. bitmapFactory; import android. util. log;/*** tool class, used to obtain the image resource to be loaded * @ author carrey **/public class ImageHelper {private static final String TAG = "ImageHelper "; public static String getImageUrl (String webServerStr, Int position) {return "http: //" + webServerStr + "/" + (position % 50) + ". jpg ";}/*** get the network image Bitmap * @ param imageUrl * @ return */public static Bitmap loadBitmapFromNet (String imageUrlStr) {Bitmap bitmap = null; URL imageUrl = null; if (imageUrlStr = null | imageUrlStr. length () = 0) {return null;} try {imageUrl = new URL (imageUrlStr); URLConnection conn = imageUrl. openConnection (); conn. setDoInput (True); conn. connect (); InputStream is = conn. getInputStream (); int length = conn. getContentLength (); if (length! =-1) {byte [] imgData = new byte [length]; byte [] temp = new byte [512]; int readLen = 0; int destPos = 0; while (readLen = is. read (temp ))! =-1) {System. arraycopy (temp, 0, imgData, destPos, readLen); destPos ++ = readLen;} bitmap = BitmapFactory. decodeByteArray (imgData, 0, imgData. length) ;}} catch (IOException e) {Log. e (TAG, e. toString (); return null;} return bitmap ;}}
Now the preparation is complete. The next step is to start the thread pool manager and add our loading tasks to the task queue, this part of work is executed in the getView method of the GridView Adapter. The key code is as follows:

holder.customView.setTitleText("ThreadPool");holder.customView.setSubTitleText("position: " + position);poolManager.start();String imageUrl = ImageHelper.getImageUrl(webServerStr, position);poolManager.addAsyncTask(new ThreadPoolTaskBitmap(imageUrl, MainActivity.this, position, holder.customView));

The following describes how to implement AsyncTask.

The AsyncTask implementation method is simpler than the implementation method of the thread pool.

First, we define our AsyncTask subclass, in which we will load image data in doInBackground and refresh the UI in onPostExecute. The Code is as follows:

Package com. carrey. asyncloaddemo; import com. carrey. customview. customview. customView; import android. graphics. bitmap; import android. OS. asyncTask; import android. util. log; import android. util. pair; public class AsyncLoadTask extends AsyncTask <Integer, Void, Pair <Integer, Bitmap> {private static final String TAG = "AsyncLoadTask "; /** view to be refreshed */private CustomView view; public AsyncLoadTask (CustomView view) {this. view = view ;}@ Overrideprotected void onPreExecute () {super. onPreExecute () ;}@ Overrideprotected Pair <Integer, Bitmap> doInBackground (Integer... params) {int position = params [0]; String imageUrl = ImageHelper. getImageUrl (MainActivity. webServerStr, position); Log. I (TAG, "AsyncLoad from NET:" + imageUrl); Bitmap bitmap = ImageHelper. loadBitmapFromNet (imageUrl); return new Pair <Integer, Bitmap> (position, bitmap) ;}@ Overrideprotected void onPostExecute (Pair <Integer, Bitmap> result) {if (result. first = view. position) {view. setImageBitmap (result. second );}}}

The following code calls AsyncTask asynchronous loading in the Adapter:

holder.customView.setTitleText("AsyncTask");holder.customView.setSubTitleText("position: " + position);new AsyncLoadTask(holder.customView).execute(position);

Here, the key code is basically finished. Let's take a look at the effects of the two methods:

Through comparison, we can find that ThreadPool has higher concurrency capability and faster loading speed than AsyncTask. AsyncTask obviously changes the order during loading and the loading speed is slower.

The following is all the code that calls the MainActivity of the two loading methods:

Package com. carrey. asyncloaddemo; import android. app. activity; import android. content. context; import android. graphics. bitmap; import android. graphics. bitmapFactory; import android. OS. bundle; import android. util. log; import android. view. layoutInflater; import android. view. menu; import android. view. view; import android. view. view. onClickListener; import android. view. viewGroup; import android. widget. baseAdapter; import android. widget. button; import android. widget. gridView; import com. carrey. customview. customview. customView;/*** asynchronous loading methods: AsyncTask and ThreadPool * @ author carrey **/public class MainActivity extends Activity implements ThreadPoolTaskBitmap. callBack {/** server address */public static String webServerStr; private static final String TAG = "MainActivity"; private LayoutInflater inflater; private Button btnAsync; private Button btnPool; private GridView gridView; private GridAdapter adapter;/** Loading Method */private int loadWay; private static final int LOAD_ASYNC = 1; private static final int LOAD_POOL = 2; private ThreadPoolManager poolManager; @ Overrideprotected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); loadWay = LOAD_ASYNC; webServerStr = getResources (). getString (R. string. web_server); inflater = (LayoutInflater) getSystemService (Context. LAYOUT_INFLATER_SERVICE); btnAsync = (Button) findViewById (R. id. btn_async); btnAsync. setOnClickListener (new AsyncButtonClick (); btnPool = (Button) findViewById (R. id. btn_pool); btnPool. setOnClickListener (new PoolButtonClick (); gridView = (GridView) findViewById (R. id. gridview); adapter = new GridAdapter (); gridView. setAdapter (adapter); poolManager = new ThreadPoolManager (ThreadPoolManager. TYPE_FIFO, 5);} private class AsyncButtonClick implements OnClickListener {@ Overridepublic void onClick (View v) {loadWay = LOAD_ASYNC; adapter. notifyDataSetChanged () ;}} private class PoolButtonClick implements OnClickListener {@ Overridepublic void onClick (View v) {loadWay = LOAD_POOL; adapter. notifyDataSetChanged () ;}} private class GridAdapter extends BaseAdapter {private Bitmap mBackgroundBitmap; public GridAdapter () {mBackgroundBitmap = BitmapFactory. decodeResource (getResources (), R. drawable. item_bg) ;}@ Overridepublic int getCount () {return 999 ;}@ Overridepublic Object getItem (int position) {return null ;}@ Overridepublic long getItemId (int position) {return 0 ;}@ Overridepublic View getView (int position, View convertView, ViewGroup parent) {ViewHolder holder = null; if (convertView = null) {holder = new ViewHolder (); convertView = inflater. inflate (R. layout. item, null); holder. customView = (CustomView) convertView. findViewById (R. id. customview); convertView. setTag (holder);} else {holder = (ViewHolder) convertView. getTag ();} holder. customView. position = position; holder. customView. setImageBitmap (null); holder. customView. setBackgroundBitmap (mBackgroundBitmap); if (loadWay = LOAD_ASYNC) {holder. customView. setTitleText ("AsyncTask"); holder. customView. setSubTitleText ("position:" + position); new asyncloadtask(holder.customviewcmd.exe cute (position);} else if (loadWay = LOAD_POOL) {holder. customView. setTitleText ("ThreadPool"); holder. customView. setSubTitleText ("position:" + position); poolManager. start (); String imageUrl = ImageHelper. getImageUrl (webServerStr, position); poolManager. addAsyncTask (new ThreadPoolTaskBitmap (imageUrl, MainActivity. this, position, holder. customView);} return convertView;} static class ViewHolder {CustomView customView;} @ Overrideprotected void onDestroy () {poolManager. stop (); super. onDestroy () ;}@ Overridepublic boolean onCreateOptionsMenu (Menu menu) {// Inflate the menu; this adds items to the action bar if it is present. getMenuInflater (). inflate (R. menu. activity_main, menu); return true;} @ Overridepublic void onReady (String url, Bitmap bitmap, int position, CustomView view) {Log. I (TAG, "thread pool done task:" + url); if (view. position = position) {view. setImageBitmap (bitmap );}}}

At the beginning of the article, we mentioned that I made some modifications to CustomView. The following describes some of the changes:

I added an mDrawableBackground attribute to the control. This Drawable will be rendered before the image content is rendered. During asynchronous loading, I will first set it as a blank background, in this way, we will first see a white background (or you can customize an hourglass or clock image) before the image is loaded, giving users a visual latency effect.

In addition, I added a pisition attribute and used it for judgment when I finally refreshed the UI, the following code executes the task unit in the thread pool implementation mode to the final callback implementation and the onPostExecute in the AsyncTask implementation mode:

@Overridepublic void onReady(String url, Bitmap bitmap, int position, CustomView view) {Log.i(TAG, "thread pool done task: " + url);if (view.position == position) {view.setImageBitmap(bitmap);}}

@Overrideprotected void onPostExecute(Pair<Integer, Bitmap> result) {if (result.first == view.position) {view.setImageBitmap(result.second);}}

Why should we make such a decision? This is because the convertView of BaseAdapter is repeatedly used. If we slide very quickly, there will be such a situation where convertView is not fully loaded yet, it will be reused for the second time. If the second loading is slower than the first loading, the result will be overwritten for the first time, which is inaccurate. Therefore, we need to add a judgment, to ensure the accuracy of the refresh.

Finally, download the source code. If you are interested, you can download and compare it. Please leave a message.

Source code download


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.