AsyncTask小案例

AsyncTask小案例

△關於安卓裏的異步任務

→安卓裏的異步任務,可以當做java裏面的多線程來看待了,在java語言裏,想要啓動多線程就只有兩個方法:繼承Thread類並重寫run()方法,或者實現Runnable接口並且重寫run()方法。

→安卓裏面,想要啓動多個線程可以通過:1,java原來有的兩個方法(Thread類和Runnable接口);2,Handler類提供方法啓動異步任務;3,AsyncTask類也能實現異步任務;4,IntentService類(Service的子類)也能實現異步任務,雖然這個和上述的相比有些勉強。


△爲什麼需要使用AsyncTask

Handler類提供很完整的異步任務機制,但是他的使用相對複雜,對於剛剛入手安卓的人來說,不好理解,AsyncTask的底層也是通過Handler來實現,通過封裝,相對來說比較能讓新手使用,簡單方便。

△關於安卓的單線程模型
雖說AsyncTask封裝的很好,能讓你幾乎在不瞭解安卓多線程工作的具體情況之下,照樣使用異步任務,但是如果想理解好異步任務,還得說說安卓的某些線程的知識。理解這些知識以後,對於理解AsyncTask使用的注意事項,也更方便。
→主線程與UI線程:安卓應用在啓動時,就是啓動一個進程,這個進程可能會有若干線程,其中有個就是所謂“主線程”,他又叫做UI線程,首先記住:UI線程==主線程
→安卓的單線程模型:詳細情況你可以在網上查到,我在這裏說說一定要記住的:
(1)不要阻塞UI線程:別在UI線程裏面進行耗時操作(一般就是不要執行超過五秒鐘的操作),否則將會出現ANR對話框(應用程序沒有響應 )。
(2)只能夠在主線程裏更新UI:所有對UI的更新(比如修改TextView顯示內容,修改ImageView的圖片),都只能在主線程裏進行,因爲安卓對UI的操作是線程不安全的,如果你在非UI線程裏更新UI,會拋異常。


△AsyncTask的簡介

→他是個類,而且還是個抽象類,一個安卓封裝好的用來簡化異步任務的類,只有繼承了並指定泛型參數,覆寫指定的方法後才能使用,使用他,你能在幾乎不瞭解安卓系統多線程的工作過程的前提下,使用安卓多線程的功能。
→類原型:public abstract class AsyncTask<Params, Progress,Result>,三個泛型參數的功能分別是:
(1)Params:啓動後臺任務時的輸入參數,比如你要下載一些文件,那參數是這些文件的URI。
(2)Progress:任務執行過程中更新進度的參數,比如傳給進度條的參數。
(3)Result:任務執行完成之後所返回的結果。
→主要方法:
(1)protected abstract Result doInBackground(Params... params);
這是必須要實現的方法,所有異步任務都在裏面這些執行,同時,該方法的所有代碼都運行在非UI線程裏,根據剛纔所說到的單線程的模型,這個方法裏面絕對不能進行任何對UI的操作。  
(2)protected void onPreExecute();
異步任務執行前的準備操作,該方法在異步任務正式啓動之前被回調(doInBackground()方法執行之前回調),該方法的所有代碼都執行在UI線程裏面,這裏可以進行UI操作,比如,將進度條的進度值設置爲零。但是這裏不能進行耗時操作,因爲是在UI線程。

(3)protected void onProgressUpdate(Progress... values);
任務執行過程中更新UI的操作,當你在"doInBackground()"方法裏面調用函數"publishProgress(Progress... values)",實際執行的代碼是"onProgressUpdate(Progress... values)"方法裏面所寫代碼。這個方法裏的所有代碼都運行在UI線程裏,可以進行更新UI操作,但是不能進行耗時操作。
(4)protected void onPostExecute(Result result);
當異步任務正常結束後(doInBackground()方法運行結束之後),這個方法將被回調,該方法的所有代碼都運行在UI線程,可以在這進行完成任務相關提示,這裏不能進行耗時操作,注意:如果異步任務是被取消掉的,這個方法不會執行。

AsyncTask類方法小結

(1)異步任務各個方法執行順序:onPreExecute()→doInBackground()→onProgressUpdate()(如果調用過publishProgress方法)→onPostExecute()。
(2)除了doInBackground()方法裏的代碼是運行在子線程裏面的,其與方法的代碼是跑在UI線程裏面。

△AsyncTask使用注意

→一個AsycnTask實例只能被執行一次(只能夠execute()一次),第二次會出現異常。
→剛纔提到所重寫的四個方法,都不能有開發者所調用,都不能有開發者所調用,都不能有開發者所調用,重要的事情說三遍,只能重寫,他們都有系統調用。

△示例代碼

下面來看看實例了,模擬一個文件下載效果,佈局文件很簡單的,先來看看佈局文件代碼:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/tv_print_content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="正下載第0個文件"
        android:gravity="center_horizontal"
        android:textSize="24sp" />

    <Button
        android:id="@+id/btn_star_asyncTask"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="啓動一個異步任務"
        android:onClick="asyncTask"/>
    <Button
        android:id="@+id/btn_pauseAsyncTask"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="取消當前異步任務"
        android:onClick="asyncTask"/>
    

    <ProgressBar
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/progressBar" />
</LinearLayout>

再來看看窗體代碼:
package com.example.masynctask;

import android.app.Activity;
import android.os.AsyncTask;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;

import java.io.File;
import java.io.InputStream;


public class MainActivity extends Activity {

    //準備數組待會傳遞異步任務
    private String[] strings = new String[]{"一號文件","二號文件","三號文件","四號文件"};
    private TextView textView = null;//這個用來更新窗體
    private ProgressBar progressBar = null;//進度
    private MAsyncTask mAsyncTask = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView)findViewById(R.id.tv_print_content);
        progressBar = (ProgressBar)findViewById(R.id.progressBar);

    }

    public void asyncTask(View view){
        switch(view.getId()) {
            case R.id.btn_star_asyncTask:
                mAsyncTask = new MAsyncTask();
                mAsyncTask.execute(strings);
                break;
            case R.id.btn_pauseAsyncTask:
                mAsyncTask.cancel(true);
                break;
        }
    }

//    第一參數:執行時傳遞進去的類型
//    第二參數:更新那時用的參數
//    第三參數:結束那是傳遞進去"onPostExecute"方法的參數
//AsyncTask裏面的泛型,和上述所介紹哪些方法裏的泛型,是對應的。
    private class MAsyncTask extends AsyncTask<String,Integer,Integer>{

        @Override
        protected Integer doInBackground(String... params) {
            Log.i("test", "doInBackGround");
            int i = 0;
            while(i<params.length) {
                publishProgress(i,params.length);
                try {
                    Thread.sleep(4000L);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                i++;
                if (isCancelled()){
                    break;
                }
            }
            Log.i("test","循環結束");
            return params.length;
        }

    //        這個方法將在子線程開始前執行
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        Log.i("test","onPreExecute");
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);
//        Log.i("test","正在下載第"+values[0]+"個文件");
        textView.setText("正下載第"+values[0]+"文件");
        progressBar.setProgress( (int)((values[0]+1)/(float)values[1]*100) );
    }

    //        這個方法將執行在異步任務結束之後
    @Override
    protected void onPostExecute(Integer integer) {
        super.onPostExecute(integer);
        Log.i("test", "onPostExecute");

    }

    @Override
    protected void onCancelled(Integer integer) {
        super.onCancelled(integer);
        Log.i("test", "onCancelled");
    }
}


   
    
    
發佈了43 篇原創文章 · 獲贊 20 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章