AsyncTask導致FC研究

來源:互聯網
上載者:User

導語:在開發Android應用的過程中,我們需要時刻注意保障應用的穩定性和介面響應性,因為不穩定或者響應速度慢的應用將會給使用者帶來非常差的互動體驗。在越來越講究使用者體驗的大環境下,使用者也許會因為應用的一次Force Close(簡稱FC)或者延遲嚴重的動畫效果而卸載你的應用。由於現在的應用大多需要非同步串連網路,本系列文章就以構建網路應用為例,從穩定性和響應性兩個角度分析多線程網路任務的效能最佳化方法。
 
概述:為了不阻塞UI線程(亦稱主線程),提高應用的響應性,我們經常會使用新開線程的方式,非同步處理那些導致阻塞的任務(如要瞭解Android非同步處理的實現方式和原理,請先閱讀《Android非同步處理系列文章索引》)。
AsyncTask是Android為我們提供的方便編寫非同步任務的工具類,但是,在瞭解AsyncTask的實現原理之後,發現AsyncTask並不能滿足我們所有的需求,使用不當還有可能導致應用FC。
本文主要通過分析AsyncTask提交任務的策略和一個具體的例子,說明AsyncTask的不足之處,至於解決辦法,我們將在下篇再講解。
分析:
AsyncTask類包含一個全域靜態線程池,線程池的配置參數如下:
private static final int CORE_POOL_SIZE =5;//5個核心背景工作執行緒  
   private static final int MAXIMUM_POOL_SIZE = 128;//最多128個背景工作執行緒  
   private static final int KEEP_ALIVE = 1;//空閑線程的逾時時間為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

V

問題:拋出的錯誤不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的風險,因此,我們需要根據自己的需求自訂不同的線程池,由於篇幅問題,將留到下篇再講。

作者“libo19881179”
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

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.