AsyncTask 異步任務(wù)基本使用--下載視頻

轉(zhuǎn)載請注明出處:http://www.reibang.com/p/295a24564237


1 簡介##

在Android中,我們需要將一些耗時的操作放到子線程中漂彤,如果放在UI線程會造成主線程阻塞,出現(xiàn)ANR友驮。在子線程中處理耗時操作旨涝,需要進行更新UI蹬屹,一般的做法是通過Handler發(fā)送消息到UI線程進行處理,相對來說使用Handler的代碼比較臃腫白华。對于Handler的知識可以看這兩篇文章:
[Android Handler的基本使用]
[深入理解Handler哩治、Looper、Messagequeue]
Android 提供了一個異步任務(wù)類AsyncTask衬鱼,使創(chuàng)建異步任務(wù)业筏、更新UI變得更加簡單,不再需要編寫任務(wù)線程和Handler實例即可完成相同的任務(wù)鸟赫。


2 AsyncTask##

AsyncTask 允許在UI線程上執(zhí)行后臺操作和發(fā)布結(jié)果蒜胖,而不必操作Thread和Handler。
它是圍繞Thread和Handler設(shè)計的一個輔助類抛蚤,主要應(yīng)用于短操作(最多幾秒)台谢。如果想要運行長時間的任務(wù),強烈建議使用Executor岁经、ThreadPoolExecutor和FuterTask朋沮。

AsyncTask:一個在后臺線程上運行,而結(jié)果在UI線程上發(fā)布的任務(wù)缀壤。異步任務(wù)必須被繼承使用樊拓,子類至少覆蓋一個方法(doInBackground)。異步任務(wù)用到了3個泛型類型:

  • Params:執(zhí)行任務(wù)時發(fā)送給任務(wù)的參數(shù)類型塘慕。
  • Progress:后臺任務(wù)執(zhí)行期間筋夏,發(fā)布的進度、百分比图呢。
  • Result:后臺計算的結(jié)果類型条篷。

異步任務(wù)中,并不是所有的泛型類型都要被使用蛤织,如果某個類型不需要使用赴叹,只需要使用Void類型就可以。如:

private  class MyTask extends AsyncTask<Void, Void, Void>{....}指蚜。

2.1 任務(wù)執(zhí)行步驟

執(zhí)行一個異步任務(wù)需要經(jīng)歷4個步驟:

  1. onPreExecute():在UI線程上調(diào)用execute方法后乞巧,執(zhí)行onPreExecute(運行在UI線程上)。此步驟通常用于設(shè)置任務(wù)姚炕,例如在用戶界面顯示進度條摊欠。
  2. doInBackground(Params...):執(zhí)行完onPreExecute后丢烘,立即在后臺線程運行柱宦,此步驟可能需要長時間的后臺計算些椒。execute()參數(shù)也被傳到這步。計算結(jié)果必須由這步驟返回掸刊,并返回到最后一步免糕。這一步驟也可以使用publishprogress發(fā)布任務(wù)的進度,進度會被發(fā)送到onProgressUpdata忧侧。
  3. onProgressUpdate(Progress...):調(diào)用publishprogress后石窑,執(zhí)行該步驟(運行在UI線程),執(zhí)行時間是不確定的蚓炬。這個方法用于在后臺計算仍在執(zhí)行時在用戶界面顯示進度松逊。例如:用一個進度條顯示下載視頻的百分比。
  4. onPostExecute(Result):后臺計算(doInBackground)完成時肯夏,在UI線程運行該方法经宏。后臺計算結(jié)果作為一個參數(shù)傳遞到這步。

2.2 取消任務(wù)

一個任務(wù)可以隨時取消驯击,通過調(diào)用cancel(boolean),調(diào)用此方法將導(dǎo)致隨后使用iscancelled()返回ture烁兰。調(diào)用此方法后,在doInBackground執(zhí)行完后不再調(diào)用onPostExecute(Result)徊都,而是調(diào)用oncancelled(Result)沪斟。

2.3 線程規(guī)則

要想使AsyncTask類能正常工作,必須遵循一些線程規(guī)則:

  • AsyncTask類必須在UI線程中加載暇矫。
  • 任務(wù)實例必須在UI線程中創(chuàng)建主之。
  • execute(Params...)必須在UI線程中調(diào)用。
  • 不要手動調(diào)用onPreExecute()李根、doInBackground(Params...)杀餐、onProgressUpdate(Progress...)、onPostExecute(Result)朱巨。
  • 一個任務(wù)實例只能執(zhí)行一次史翘,(多次執(zhí)行會拋出異常)。

2.4 執(zhí)行順序

在1.6之前冀续,AsyncTask是串行執(zhí)行任務(wù)的琼讽;
1.6的時候AsyncTask開始采用線程池里處理并行任務(wù);
但是從3.0開始洪唐,為了避免AsyncTask所帶來的并發(fā)錯誤钻蹬,AsyncTask又采用一個線程來串行執(zhí)行任務(wù)。


3 案例##

如下是通過使用AsyncTask下載一個段視頻的列子凭需,下載成功或失敗后設(shè)置按鈕內(nèi)容问欠,并在下載過程中更新下載進度肝匆。
先看下效果圖。


下載視頻
package cn.vn.asynctaskdemo;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;

public class MainActivity extends Activity implements OnClickListener {
    private final static String TAG = "MainActivity";
    public static final String VIDEO_DOWNLOAD_FOLDER = Environment
            .getExternalStorageDirectory().toString();
    private Button mExecuteBtn;
    private ProgressBar mProgressBar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mExecuteBtn = (Button) findViewById(R.id.btn_execute);
        mExecuteBtn.setOnClickListener(this);
        mProgressBar = (ProgressBar) findViewById(R.id.progress);
    }
    
    @Override
    public void onClick(View view) {
        mProgressBar.setProgress(0);
        //下載視頻
        new DownloadTask().execute("http://120.25.226.186:32812/resources/videos/minion_05.mp4");
    }

    public class DownloadTask extends AsyncTask<String, Double, Boolean>{

        @Override
        protected void onPreExecute() {
            Log.i(TAG,"onPreExecute ");
        }
        @Override
        protected Boolean doInBackground(String... params) {
            Log.i(TAG,"doInBackground params[0]="+params[0]);
            HttpURLConnection conn = null;
            try{
                URL url = new URL(params[0]);
                conn = (HttpURLConnection) url.openConnection();
                conn.setConnectTimeout(5000);
                conn.setReadTimeout(10000);
                conn.setRequestProperty("Connection", "Keep-Alive");
            }catch(Exception e){
                e.printStackTrace();
                return false;
            } //獲取文件長度
            long videoTotalLength = conn.getContentLength();
            File file = new File(VIDEO_DOWNLOAD_FOLDER, "test.mp4");
            try { //創(chuàng)建File對象顺献,文件路徑為/sdcard/test.mp4
                InputStream in = conn.getInputStream();
                if (in == null)
                    return false;
                //如果文件已經(jīng)存在旗国,并且第二個參數(shù)為true,則向原先的文件追加數(shù)據(jù)注整,否則重新寫能曾。
                FileOutputStream os = new FileOutputStream(file, false);
                byte[] buffer = new byte[4096];
                int len = 0;
                int current = 0;
                while ((len = in.read(buffer)) != -1) {
                    current += len;
                    //更新進度
                    publishProgress((double) current,
                            (double) videoTotalLength);
                    os.write(buffer, 0, len);
                }
                os.close();
                in.close();
            } catch (Exception e) {
                if (file.exists())
                    file.delete();
                e.printStackTrace();
                return false;
            }
            return true;
        }
        
        @Override
        protected void onProgressUpdate(Double... values) {
            //設(shè)置ProgressBar進度
            mProgressBar.setProgress((int) (values[0]/values[1]*100));
        }
        
        @Override
        protected void onPostExecute(Boolean result) {
            if(result){
                Log.i(TAG,"下載文件成功");
                mExecuteBtn.setText("下載成功");
            }else{
                Log.i(TAG,"下載文件失敗");
                mExecuteBtn.setText("下載失敗");
            }
        }
    }
}

該demo比較簡單,只有一個Activity——>MainActivity肿轨。該界面有一個Button和一個ProgressBar寿冕。點擊Button開始執(zhí)行異步任務(wù),下載網(wǎng)上視頻椒袍,并保存到本地文件中驼唱。打印信息如下:

06-23 11:14:50.890 I/MainActivity(28417): onPreExecute 
06-23 11:14:50.890 I/MainActivity(28417): doInBackground params[0]=http://120.25.226.186:32812/resources/videos/minion_01.mp4
06-23 11:15:33.562 I/MainActivity(28417): 下載文件成功

第37行:創(chuàng)建DownloadTask實例,調(diào)用其execute方法驹暑,開始執(zhí)行任務(wù)玫恳。
開始執(zhí)行任務(wù),先走onPreExecute方法岗钩,然后進入doInBackground纽窟,這里面用來進行耗時操作,這里未在主線程運行兼吓,調(diào)用publishProgress來更新下載進度臂港,會調(diào)用onProgressUpdate。
任務(wù)下載完成(失敗或成功)视搏,走onPostExecute方法审孽。下一篇在分析下AsyncTask的源碼。

歡迎大家關(guān)注浑娜、評論佑力、點贊
你們的支持是我堅持的動力筋遭。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末打颤,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子漓滔,更是在濱河造成了極大的恐慌编饺,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件响驴,死亡現(xiàn)場離奇詭異透且,居然都是意外死亡,警方通過查閱死者的電腦和手機豁鲤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進店門秽誊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鲸沮,“玉大人,你說我怎么就攤上這事锅论∷夏纾” “怎么了?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵棍厌,是天一觀的道長肾胯。 經(jīng)常有香客問我竖席,道長耘纱,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任毕荐,我火速辦了婚禮束析,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘憎亚。我一直安慰自己员寇,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布第美。 她就那樣靜靜地躺著蝶锋,像睡著了一般。 火紅的嫁衣襯著肌膚如雪什往。 梳的紋絲不亂的頭發(fā)上扳缕,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天,我揣著相機與錄音别威,去河邊找鬼躯舔。 笑死,一個胖子當(dāng)著我的面吹牛省古,可吹牛的內(nèi)容都是我干的粥庄。 我是一名探鬼主播,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼豺妓,長吁一口氣:“原來是場噩夢啊……” “哼惜互!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起琳拭,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤训堆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后臀栈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蔫慧,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年权薯,在試婚紗的時候發(fā)現(xiàn)自己被綠了姑躲。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片睡扬。...
    茶點故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖黍析,靈堂內(nèi)的尸體忽然破棺而出卖怜,到底是詐尸還是另有隱情,我是刑警寧澤阐枣,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布马靠,位于F島的核電站,受9級特大地震影響蔼两,放射性物質(zhì)發(fā)生泄漏甩鳄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一额划、第九天 我趴在偏房一處隱蔽的房頂上張望妙啃。 院中可真熱鬧,春花似錦俊戳、人聲如沸揖赴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽燥滑。三九已至,卻和暖如春阿逃,著一層夾襖步出監(jiān)牢的瞬間铭拧,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工盆昙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留羽历,地道東北人。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓淡喜,卻偏偏與公主長得像秕磷,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子炼团,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,960評論 2 355

推薦閱讀更多精彩內(nèi)容