亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Android開發(fā)筆記之:AsyncTask的應(yīng)用詳解

 更新時(shí)間:2013年05月21日 10:29:02   作者:  
本篇文章是對Android中AsyncTask的應(yīng)用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
AsyncTask的介紹及基本使用方法
關(guān)于AsyncTask的介紹和基本使用方法可以參考官方文檔和《Android開發(fā)筆記之:深入理解多線程AsyncTask》這里就不重復(fù)。
AsyncTask引發(fā)的一個(gè)問題
上周遇到了一個(gè)極其詭異的問題,一個(gè)小功能從網(wǎng)絡(luò)上下載一個(gè)圖片,然后放到ImageView中,是用AsyncTask來實(shí)現(xiàn)的,本身邏輯也很簡單,僅是在doInBackground中用HTTP請求把圖片的輸入流取出,然后用BitmapFactory去解析,然后再把得到的Bitmap放到ImageView中。這個(gè)應(yīng)用是用4.0的SDK開發(fā)的,也是運(yùn)行在4.0上面的。但是有時(shí)候下載這張圖片去要用很久很久,甚至要等上幾分鐘。通過調(diào)試發(fā)現(xiàn)一個(gè)令人難以接受的事實(shí):竟然是doInBackground()未及時(shí)執(zhí)行,也就是它并沒有在#execute()調(diào)用之后馬上執(zhí)行,而是等待了很久才得以執(zhí)行。
神馬情況,難道AsyncTask不是線程,難道不是異步,難道AsyncTask另有內(nèi)幕?
AsyncTask的內(nèi)幕
AsyncTask主要有二個(gè)部分:一個(gè)是與主線各的交互,另一個(gè)就是線程的管理調(diào)度。雖然可能多個(gè)AsyncTask的子類的實(shí)例,但是AsyncTask的內(nèi)部Handler和ThreadPoolExecutor都是進(jìn)程范圍內(nèi)共享的,其都是static的,也即屬于類的,類的屬性的作用范圍是CLASSPATH,因?yàn)橐粋€(gè)進(jìn)程一個(gè)VM,所以是AsyncTask控制著進(jìn)程范圍內(nèi)所有的子類實(shí)例。
與主線程交互
與主線程交互是通過Handler來進(jìn)行的,因?yàn)楸疚闹饕接慉syncTask在任務(wù)調(diào)度方面的,所以對于這部分不做細(xì)致介紹,感興趣的朋友可以去看AsyncTask的源碼
線程任務(wù)的調(diào)度
內(nèi)部會創(chuàng)建一個(gè)進(jìn)程作用域的線程池來管理要運(yùn)行的任務(wù),也就就是說當(dāng)你調(diào)用了AsyncTask#execute()后,AsyncTask會把任務(wù)交給線程池,由線程池來管理創(chuàng)建Thread和運(yùn)行Therad。對于內(nèi)部的線程池不同版本的Android的實(shí)現(xiàn)方式是不一樣的:
Android2.3以前的版本,也即SDK/API 10和以前的版本
內(nèi)部的線程池限制是5個(gè),也就是說同時(shí)只能有5個(gè)線程運(yùn)行,超過的線程只能等待,等待前面的線程某個(gè)執(zhí)行完了才被調(diào)度和運(yùn)行。換句話說,如果一個(gè)進(jìn)程中的AsyncTask實(shí)例個(gè)數(shù)超過5個(gè),那么假如前5個(gè)都運(yùn)行很長時(shí)間的話,那么第6個(gè)只能等待機(jī)會了。這是AsyncTask的一個(gè)限制,而且對于2.3以前的版本無法解決。如果你的應(yīng)用需要大量的后臺線程去執(zhí)行任務(wù),那么你只能放棄使用AsyncTask,自己創(chuàng)建線程池來管理Thread,或者干脆不用線程池直接使用Thread也無妨。不得不說,雖然AsyncTask較Thread使用起來比較方便,但是它最多只能同時(shí)運(yùn)行5個(gè)線程,這也大大局限了它的實(shí)力,你必須要小心的設(shè)計(jì)你的應(yīng)用,錯(cuò)開使用AsyncTask的時(shí)間,盡力做到分時(shí),或者保證數(shù)量不會大于5個(gè),否則就可能遇到上面提到的問題。要不然就只能使用JavaSE中的API了。



Android 3.0以后,也即SDK/API 11和以后的版本
可能是Google意識到了AsyncTask的局限性了,從Android 3.0開始對AsyncTask的API做出了一些調(diào)整:
1.#execute()提交的任務(wù),按先后順序每次只運(yùn)行一個(gè)
也就是說它是按提交的次序,每次只啟動一個(gè)線程執(zhí)行一個(gè)任務(wù),完成之后再執(zhí)行第二個(gè)任務(wù),也就是相當(dāng)于只有一個(gè)后臺線程在執(zhí)行所提交的任務(wù)(Executors.newSingleThreadPool())。



2.新增了接口#executeOnExecutor()
這個(gè)接口允許開發(fā)者提供自定義的線程池來運(yùn)行和調(diào)度Thread,如果你想讓所有的任務(wù)都能并發(fā)同時(shí)運(yùn)行,那就創(chuàng)建一個(gè)沒有限制的線程池(Executors.newCachedThreadPool()),并提供給AsyncTask。這樣這個(gè)AsyncTask實(shí)例就有了自己的線程池而不必使用AsyncTask默認(rèn)的。
3.新增了二個(gè)預(yù)定義的線程池SERIAL_EXECUTOR和THREAD_POOL_EXECUTOR
其實(shí)THREAD_POOL_EXECUTOR并不是新增的,之前的就有,只不過之前(Android 2.3)它是AsyncTask私有的,未公開而已。THREAD_POOL_EXECUTOR是一個(gè)corePoolSize為5的線程池,也就是說最多只有5個(gè)線程同時(shí)運(yùn)行,超過5個(gè)的就要等待。所以如果使用executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)就跟2.3版本的AsyncTask.execute()效果是一樣的。



而SERIAL_EXECUTOR是新增的,它的作用是保證任務(wù)執(zhí)行的順序,也就是它可以保證提交的任務(wù)確實(shí)是按照先后順序執(zhí)行的。它的內(nèi)部有一個(gè)隊(duì)列用來保存所提交的任務(wù),保證當(dāng)前只運(yùn)行一個(gè),這樣就可以保證任務(wù)是完全按照順序執(zhí)行的,默認(rèn)的execute()使用的就是這個(gè),也就是executeOnExecutor(AsyncTask.SERIAL_EXECUTOR)與execute()是一樣的。
前面問題的解法
了解了AsyncTask的內(nèi)幕就知道了前面問題的原因:因?yàn)槭?.0平臺,所以所有的AsyncTask并不都會運(yùn)行在單獨(dú)的線程中,而是被SERIAL_EXECUTOR順序的使用線程執(zhí)行。因?yàn)閼?yīng)用中可能還有其他地方使用AsyncTask,所以到網(wǎng)絡(luò)取圖片的AsyncTask也許會等待到其他任務(wù)都完成時(shí)才得以執(zhí)行而不是調(diào)用executor()之后馬上執(zhí)行。
那么解決方法其實(shí)很簡單,要么直接使用Thread,要么創(chuàng)建一個(gè)單獨(dú)的線程池(Executors.newCachedThreadPool())。或者最簡單的解法就是使用executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR),這樣起碼不用等到前面的都結(jié)束了再執(zhí)行。
AsyncTask的使用注意事項(xiàng)
前面的文章曾建議使用AsyncTask而不是使用Thread,但是AsyncTask似乎又有它的限制,這就要根據(jù)具體的需求情況而選擇合適的工具,No Silver Bullet。下面是一些建議:
•改善你的設(shè)計(jì),少用異步處理
線程的開銷是非常大的,同時(shí)異步處理也容易出錯(cuò),難調(diào)試,難維護(hù),所以改善你的設(shè)計(jì),盡可能的少用異步。對于一般性的數(shù)據(jù)庫查詢,少量的I/O操作是沒有必要啟動線程的。
•與主線程有交互時(shí)用AsyncTask,否則就用Thread
AsyncTask被設(shè)計(jì)出來的目的就是為了滿足Android的特殊需求:非主線程不能操作(UI)組件,所以AsyncTask擴(kuò)展Thread增強(qiáng)了與主線程的交互的能力。如果你的應(yīng)用沒有與主線程交互,那么就直接使用Thread就好了。
•當(dāng)有需要大量線程執(zhí)行任務(wù)時(shí),一定要創(chuàng)建線程池
線程的開銷是非常大的,特別是創(chuàng)建一個(gè)新線程,否則就不必設(shè)計(jì)線程池之類的工具了。當(dāng)需要大量線程執(zhí)行任務(wù)時(shí),一定要創(chuàng)建線程池,無論是使用AsyncTask還是Thread,因?yàn)槭褂肁syncTask它內(nèi)部的線程池有數(shù)量限制,可能無法滿足需求;使用Thread更是要線程池來管理,避免虛擬機(jī)創(chuàng)建大量的線程。比如從網(wǎng)絡(luò)上批量下載圖片,你不想一個(gè)一個(gè)的下,或者5個(gè)5個(gè)的下載,那么就創(chuàng)建一個(gè)CorePoolSize為10或者20的線程池,每次10個(gè)或者20個(gè)這樣的下載,即滿足了速度,又不至于耗費(fèi)無用的性能開銷去無限制的創(chuàng)建線程。
•對于想要立即開始執(zhí)行的異步任務(wù),要么直接使用Thread,要么單獨(dú)創(chuàng)建線程池提供給AsyncTask
默認(rèn)的AsyncTask不一定會立即執(zhí)行你的任務(wù),除非你提供給他一個(gè)單獨(dú)的線程池。如果不與主線程交互,直接創(chuàng)建一個(gè)Thread就可以了,雖然創(chuàng)建線程開銷比較大,但如果這不是批量操作就沒有問題。
•Android的開發(fā)沒有想像中那樣簡單,要多花心思和時(shí)間在代碼上和測試上面,以確信程序是優(yōu)質(zhì)的
附上相關(guān)資源:
使用自定義的CorePoolSize為7的Executor(Executors.newFixedThreadPool(7)):


使用未設(shè)限制的Executor(Executors.newCachedThreadPool()):



這些例子所用的代碼:
復(fù)制代碼 代碼如下:

public class AsyncTaskDemoActivity extends Activity {
    private static int ID = 0;
    private static final int TASK_COUNT = 9;
    private static ExecutorService SINGLE_TASK_EXECUTOR;
    private static ExecutorService LIMITED_TASK_EXECUTOR;
    private static ExecutorService FULL_TASK_EXECUTOR;

    static {
        SINGLE_TASK_EXECUTOR = (ExecutorService) Executors.newSingleThreadExecutor();
        LIMITED_TASK_EXECUTOR = (ExecutorService) Executors.newFixedThreadPool(7);
        FULL_TASK_EXECUTOR = (ExecutorService) Executors.newCachedThreadPool();
    };

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.asynctask_demo_activity);
        String title = "AsyncTask of API " + VERSION.SDK_INT;
        setTitle(title);
        final ListView taskList = (ListView) findViewById(R.id.task_list);
        taskList.setAdapter(new AsyncTaskAdapter(getApplication(), TASK_COUNT));
    }

    private class AsyncTaskAdapter extends BaseAdapter {
        private Context mContext;
        private LayoutInflater mFactory;
        private int mTaskCount;
        List<SimpleAsyncTask> mTaskList;

        public AsyncTaskAdapter(Context context, int taskCount) {
            mContext = context;
            mFactory = LayoutInflater.from(mContext);
            mTaskCount = taskCount;
            mTaskList = new ArrayList<SimpleAsyncTask>(taskCount);
        }

        @Override
        public int getCount() {
            return mTaskCount;
        }
        @Override
        public Object getItem(int position) {
            return mTaskList.get(position);
        }
        @Override
        public long getItemId(int position) {
            return position;
        }
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            if (convertView == null) {
                convertView = mFactory.inflate(R.layout.asynctask_demo_item, null);
                SimpleAsyncTask task = new SimpleAsyncTask((TaskItem) convertView);
                /*
                 * It only supports five tasks at most. More tasks will be scheduled only after
                 * first five finish. In all, the pool size of AsyncTask is 5, at any time it only
                 * has 5 threads running.
                 */
//                task.execute();
                // use AsyncTask#SERIAL_EXECUTOR is the same to #execute();
//                task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
                // use AsyncTask#THREAD_POOL_EXECUTOR is the same to older version #execute() (less than API 11)
                // but different from newer version of #execute()
//                task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
                // one by one, same to newer version of #execute()
//                task.executeOnExecutor(SINGLE_TASK_EXECUTOR);
                // execute tasks at some limit which can be customized
//                task.executeOnExecutor(LIMITED_TASK_EXECUTOR);
                // no limit to thread pool size, all tasks run simultaneously
                task.executeOnExecutor(FULL_TASK_EXECUTOR);

                mTaskList.add(task);
            }
            return convertView;
        }
    }

    private class SimpleAsyncTask extends AsyncTask<Void, Integer, Void> {
        private TaskItem mTaskItem;
        private String mName;

        public SimpleAsyncTask(TaskItem item) {
            mTaskItem = item;
            mName = "Task #" + String.valueOf(++ID);
        }

        @Override
        protected Void doInBackground(Void... params) {
            int prog = 1;
            while (prog < 101) {
                SystemClock.sleep(100);
                publishProgress(prog);
                prog++;
            }
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
        }

        @Override
        protected void onPreExecute() {
            mTaskItem.setTitle(mName);
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            mTaskItem.setProgress(values[0]);
        }
    }
}
class TaskItem extends LinearLayout {
    private TextView mTitle;
    private ProgressBar mProgress;

    public TaskItem(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public TaskItem(Context context) {
        super(context);
    }

    public void setTitle(String title) {
        if (mTitle == null) {
            mTitle = (TextView) findViewById(R.id.task_name);
        }
        mTitle.setText(title);
    }

    public void setProgress(int prog) {
        if (mProgress == null) {
            mProgress = (ProgressBar) findViewById(R.id.task_progress);
        }
        mProgress.setProgress(prog);
    }
}

復(fù)制代碼 代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="10dip"
    android:paddingRight="10dip"
    android:orientation="vertical" >
    <ListView android:id="@+id/task_list"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:divider="#cccccc"
        android:dividerHeight="0.6dip"
        android:footerDividersEnabled="true"
        android:headerDividersEnabled="true" />
</LinearLayout>

復(fù)制代碼 代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<com.hilton.effectiveandroid.os.TaskItem xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="50dip"
    android:gravity="center_vertical"
    android:layout_gravity="center_vertical"
    android:orientation="horizontal" >
    <TextView android:id="@+id/task_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#ffff00"
        android:textSize="26sp" />
    <ProgressBar android:id="@+id/task_progress"
        android:layout_width="fill_parent"
        android:layout_height="15dip"
        android:max="100"
        style="@android:style/Widget.ProgressBar.Horizontal" />
</com.hilton.effectiveandroid.os.TaskItem >

相關(guān)文章

  • Android性能之冷啟動優(yōu)化詳析

    Android性能之冷啟動優(yōu)化詳析

    這篇文章主要給大家介紹了關(guān)于Android性能之冷啟動優(yōu)化的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對各位Android開發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • android與asp.net服務(wù)端共享session的方法詳解

    android與asp.net服務(wù)端共享session的方法詳解

    這篇文章主要給大家介紹了關(guān)于android與asp.net服務(wù)端如何共享session的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)下吧。
    2017-09-09
  • Android實(shí)現(xiàn)調(diào)用震動的方法

    Android實(shí)現(xiàn)調(diào)用震動的方法

    這篇文章主要介紹了Android實(shí)現(xiàn)調(diào)用震動的方法,實(shí)例分析了Android中Vibrator類的調(diào)用與使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-11-11
  • Android pdf viewer在android studio應(yīng)用問題說明詳解

    Android pdf viewer在android studio應(yīng)用問題說明詳解

    這篇文章主要介紹了Android pdf viewer在android studio應(yīng)用問題說明的相關(guān)資料,本文介紹的非常詳細(xì),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-09-09
  • RecyclerView下拉刷新上拉加載

    RecyclerView下拉刷新上拉加載

    本文主要介紹了RecyclerView下拉刷新上拉加載的具體實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,下面跟著小編一起來看下吧
    2017-01-01
  • 詳解Android沉浸式實(shí)現(xiàn)兼容解決辦法

    詳解Android沉浸式實(shí)現(xiàn)兼容解決辦法

    本篇文章主要介紹了詳解Android沉浸式實(shí)現(xiàn)兼容解決辦法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-11-11
  • android繪制圓形圖片的兩種方式示例

    android繪制圓形圖片的兩種方式示例

    本篇文章主要介紹了android繪制圓形圖片的兩種方式,具有一定的參考價(jià)值,有興趣的可以了解一下。
    2017-01-01
  • Android--SQLite(增,刪,改,查)操作實(shí)例代碼

    Android--SQLite(增,刪,改,查)操作實(shí)例代碼

    Android--SQLite(增,刪,改,查)操作實(shí)例代碼,需要的朋友可以參考一下
    2013-02-02
  • Android開發(fā)使用自定義view實(shí)現(xiàn)ListView下拉的視差特效功能

    Android開發(fā)使用自定義view實(shí)現(xiàn)ListView下拉的視差特效功能

    這篇文章主要介紹了Android開發(fā)使用自定義view實(shí)現(xiàn)ListView下拉的視差特效功能,結(jié)合實(shí)例形式詳細(xì)分析了Android重寫ListView控件實(shí)現(xiàn)ListView下拉視差效果的步驟與相關(guān)操作技巧,需要的朋友可以參考下
    2017-10-10
  • 簡單實(shí)現(xiàn)安卓里百度地圖持續(xù)定位

    簡單實(shí)現(xiàn)安卓里百度地圖持續(xù)定位

    本文主要介紹了在安卓的百度地圖開發(fā)里面簡單實(shí)現(xiàn)持續(xù)定位的方法,具有一定的參考價(jià)值,下面跟著小編一起來看下吧
    2017-01-01

最新評論