L遷客

          技術博客
          隨筆 - 1, 文章 - 12, 評論 - 1, 引用 - 0
          數據加載中……

          AsyncTask的缺陷

          AsyncTask的缺陷

          導語:在開發Android應用的過程中,我們需要時刻注意保障應用的穩定性和界面響應性,因為不穩定或者響應速度慢的應用將會給用戶帶來非常差的交互體驗。在越來越講究用戶體驗的大環境下,用戶也許會因為應用的一次Force Close(簡稱FC)或者延遲嚴重的動畫效果而卸載你的應用。由于現在的應用大多需要異步連接網絡,本系列文章就以構建網絡應用為例,從穩定性和響應性兩個角度分析多線程網絡任務的性能優化方法。

          概述:為了不阻塞UI線程(亦稱主線程),提高應用的響應性,我們經常會使用新開線程的方式,異步處理那些導致阻塞的任務。

          AsyncTask是Android為我們提供的方便編寫異步任務的工具類,但是,在了解AsyncTask的實現原理之后,發現AsyncTask并不能滿足我們所有的需求,使用不當還有可能導致應用FC。

          本文主要通過分析AsyncTask提交任務的策略和一個具體的例子,說明AsyncTask的不足之處,至于解決辦法,我們將在下篇再講解。

          分析

          AsyncTask類包含一個全局靜態的線程池,線程池的配置參數如下:

          //5個核心工作線程

          private static final int CORE_POOL_SIZE =5;

          //最多128個工作線程

          private static final int MAXIMUM_POOL_SIZE = 128;

          //空閑線程的超時時間為1秒

          private static final int KEEP_ALIVE = 1;

          private static final BlockingQueue<Runnable> sWorkQueue =

                     new LinkedBlockingQueue<Runnable>(10);//等待隊列

          private static final ThreadPoolExecutorsExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,

                     //線程池是靜態變量,所有的異步任務都會放到這個線程池的工作線程內執行。

                     MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue,sThreadFactory);

          我們這里不詳細講解ThreadPoolExecutor的原理,但將會講解一個異步任務提交到AsyncTask的線程池時可能會出現的4種情況,并會提出在Android硬件配置普遍較低這個客觀條件下,每個情況可能會出現的問題。

          1、線程池中的工作線程少于5個時,將會創建新的工作線程執行異步任務(紅色表示新任務,下同)

          2、線程池中已經有5個線程,緩沖隊列未滿,異步任務將會放到緩沖隊列中等待

          3、線程池中已經有5個線程,緩沖隊列已滿,那么線程池將新開工作線程執行異步任務

          問題:Android的設備一般不超過2個cpu核心,過多的線程會造成線程間切換頻繁,消耗系統資源。

          4、線程池中已經有128個線程,緩沖隊列已滿,如果此時向線程提交任務,將會拋出RejectedExecutionException

          問題:拋出的錯誤不catch的話會導致程序FC。

          好吧,理論分析之后還是要結合實際例子,我們通過實現一個模擬異步獲取網絡圖片的例子,看看會不會出現上面提到的問題。

          例子:使用GridView模擬異步加載大量圖片

          ActivityA.java

          package com.zhuozhuo;

           

          import java.util.ArrayList;

          import java.util.Collection;

          import java.util.HashMap;

          import java.util.Iterator;

          import java.util.List;

          import java.util.ListIterator;

          import java.util.Map;

           

          import android.app.Activity;

          import android.app.AlertDialog;

          import android.app.Dialog;

          import android.app.ListActivity;

          import android.app.ProgressDialog;

          import android.content.Context;

          import android.content.DialogInterface;

          import android.content.Intent;

          import android.database.Cursor;

          import android.graphics.Bitmap;

          import android.os.AsyncTask;

          import android.os.Bundle;

          import android.provider.ContactsContract;

          import android.util.Log;

          import android.view.LayoutInflater;

          import android.view.View;

          import android.view.ViewGroup;

          import android.widget.AbsListView;

          import android.widget.AbsListView.OnScrollListener;

          import android.widget.Adapter;

          import android.widget.AdapterView;

          import android.widget.AdapterView.OnItemClickListener;

          import android.widget.BaseAdapter;

          import android.widget.GridView;

          import android.widget.ImageView;

          import android.widget.ListAdapter;

          import android.widget.SimpleAdapter;

          import android.widget.TextView;

          import android.widget.Toast;

           

          public class ActivityA extends Activity {

              private GridView mGridView;

              private List<HashMap<String, Object>> mData;

              private BaseAdapter mAdapter;

              private ProgressDialog mProgressDialog;

              private static final int DIALOG_PROGRESS = 0;

              @Override

              public void onCreate(Bundle savedInstanceState) {

                  super.onCreate(savedInstanceState);

                  setContentView(R.layout.main);

                  mGridView = (GridView) findViewById(R.id.gridview);

                  mData = new ArrayList<HashMap<String,Object>>();

                  mAdapter = new CustomAdapter();

                  mGridView.setAdapter(mAdapter);

              }

              protected void onStart () {

                 super.onStart();

                 new GetGridDataTask().execute(null);//執行獲取數據的任務

              }

              @Override

              protected Dialog onCreateDialog(int id) {

                  switch (id) {

                  case DIALOG_PROGRESS:

                      mProgressDialog = new ProgressDialog(ActivityA.this);

                      mProgressDialog.setMessage("正在獲取數據");

                      mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);

                      return mProgressDialog;

                  }

                  return null;

              }

              class CustomAdapter extends BaseAdapter {

                 CustomAdapter() {

                    

                 }

                 @Override

                 public int getCount() {

                     return mData.size();

                 }

                 @Override

                 public Object getItem(int position) {

                     return mData.get(position);

                 }

                 @Override

                 public long getItemId(int position) {

                     return 0;

                 }

                 @Override

                 public View getView(int position, View convertView, ViewGroup parent) {

                     View view = convertView;

                     ViewHolder vh;

                     if(view == null) {

                        view = LayoutInflater.from(ActivityA.this).inflate(R.layout.list_item, null);

                        vh = new ViewHolder();

                        vh.tv = (TextView) view.findViewById(R.id.textView);

                        vh.iv = (ImageView) view.findViewById(R.id.imageView);

                        view.setTag(vh);

                     }

                     vh = (ViewHolder) view.getTag();

                     vh.tv.setText((String) mData.get(position).get("title"));

                     Integer id = (Integer) mData.get(position).get("pic");

                     if(id != null) {

                        vh.iv.setImageResource(id);

                     }

                     else {

                        vh.iv.setImageBitmap(null);

                     }

                    

                     FifoAsyncTask task = (FifoAsyncTask) mData.get(position).get("task");

                     if(task == null || task.isCancelled()) {

                        Log.d("Test", "" + position);

                        mData.get(position).put("task", new GetItemImageTask(position).execute(null));//執行獲取圖片的任務

                     }

                    

                     return view;

                 }

              }

              static class ViewHolder {

                 TextView tv;

                 ImageView iv;

              }

              class GetGridDataTask extends FifoAsyncTask<Void, Void, Void> {

                

                 protected void onPreExecute () {

                     mData.clear();

                     mAdapter.notifyDataSetChanged();

                    

                     showDialog(DIALOG_PROGRESS);//打開等待對話框

                 }

                 @Override

                 protected Void doInBackground(Void... params) {

                    

                     try {

                        Thread.sleep(500);//模擬耗時的網絡操作

                     } catch (InterruptedException e) {

                        e.printStackTrace();

                     }

                     for(int i = 0; i < 200; i++) {

                        HashMap<String, Object> hm = new HashMap<String, Object>();

                        hm.put("title", "Title");

                        mData.add(hm);

                     }

                    

                     return null;

                 }

                 protected void onPostExecute (Void result) {

                     mAdapter.notifyDataSetChanged();//通知ui界面更新

                     dismissDialog(DIALOG_PROGRESS);//關閉等待對話框

                 }

                

              }

              class GetItemImageTask extends FifoAsyncTask<Void, Void, Void> {

                

                 int pos;

                

                 GetItemImageTask(int pos) {

                     this.pos = pos;

                 }

                 @Override

                 protected Void doInBackground(Void... params) {

                     try {

                        Thread.sleep(2000); //模擬耗時的網絡操作

                     } catch (InterruptedException e) {

                        e.printStackTrace();

                     }

                     mData.get(pos).put("pic", R.drawable.icon);

                     return null;

                 }

                 protected void onPostExecute (Void result) {

                     mAdapter.notifyDataSetChanged();//通知ui界面更新

                 }

              }

          }

          當網絡情況較差,異步任務不能盡快完成執行的情況下,新開的線程會造成listview滑動不流暢。當開啟的工作線程過多時,還有出現FC的可能。

          至此,你還相信萬能的AsyncTask嗎?至于你信不信,反正我不信。

          總結:

          AsyncTask可能存在新開大量線程消耗系統資源和導致應用FC的風險,因此,我們需要根據自己的需求自定義不同的線程池,由于篇幅問題,將留到下篇再講。

          posted on 2013-02-24 16:37 L遷客 閱讀(73) 評論(0)  編輯  收藏


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 凌云县| 邛崃市| 雷波县| 轮台县| 鄂托克前旗| 中方县| 定兴县| 东明县| 施秉县| 尼勒克县| 淮南市| 宁都县| 鱼台县| 岚皋县| 永清县| 锡林浩特市| 晴隆县| 灌阳县| 化州市| 永顺县| 封开县| 辽宁省| 宁强县| 巴南区| 苍山县| 安庆市| 岐山县| 蓬莱市| 贺兰县| 衡山县| 连南| 万盛区| 嘉义市| 芜湖市| 壤塘县| 贵德县| 宜春市| 孝感市| 盈江县| 台中县| 深泽县|