Android提供了一個工具類:AsyncTask,它使創建需要與用戶界面交互的長時間運行的任務變得更簡單。相對Handler來說AsyncTask更輕量級一些,適用於簡單的異步處理,不需要借助線程和Handter即可實現。AsyncTask是抽象類。AsyncTask定義了三種泛型類型Params,Progress和Result:
Params啟動任務執行的輸入參數,比如,HTTP請求的URL。
Progress后台任務執行的百分比。
Result后台執行任務最終返回的結果,比如String。
通過用AsyncTask實現文件下載以及進度更新提示的演示動圖:
本次真機演示的下載目錄為Download文件夾,首先進入Download文件夾,沒有圖片文件,下載完成后,再次查看,可以看到本次演示的下載圖片
首先我們簡單介紹AsyncTask的執行步驟:
AsyncTask的執行分為四個步驟,每一步對應一個回調方法,我們需要的就是實現這些方法。
(1)首先定義一個類繼承AsyncTask
(2)實現AsyncTask中定義的下面一個或幾個方法
四個步驟方法分別為:
(1)onPreExecute():被UIThread調用,該方法用來做一些准備工作,如在界面上顯示一個進度條。
(2)dolnBackground(Params…):將在onPreExecute之后執行,運行在后台線程中。負責執行耗時工作。可以調用publishProgress方法來更新實時任務進度。
(3)onProgressUpdate(Progress…):在publishProgress方法被調用后,UIThread將調用該方法在界面上展示任務的進展情況,例如通過一個進度條進行展示。
(4)onPostExecute(Result):在dolnBackground執行完成后,onPostExecute方法將被UIThread調用,后台的計算結果將通過該方法傳遞到UIThread。
效果實現代碼示例:
第一步:Layout中Activity的布局文件activity_main.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout 3 xmlns:android="http://schemas.android.com/apk/res/android" 4 xmlns:tools="http://schemas.android.com/tools" 5 android:id="@+id/activity_main" 6 android:layout_width="match_parent" 7 android:layout_height="match_parent" 8 android:orientation="vertical" 9 tools:context="com.example.administrator.asynctask.MainActivity"> 10 <TextView 11 android:id="@+id/tv" 12 android:layout_width="match_parent" 13 android:layout_height="wrap_content" 14 android:text="panhouye!" 15 android:textSize="20sp"/> 16 <ProgressBar 17 android:id="@+id/progress" 18 android:layout_width="match_parent" 19 android:layout_height="wrap_content" 20 style="@style/Base.Widget.AppCompat.ProgressBar.Horizontal" 21 android:visibility="visible"/> 22 <Button 23 android:layout_width="match_parent" 24 android:layout_height="wrap_content" 25 android:onClick="image" 26 android:text="下載圖片"/> 27 </LinearLayout>
第二步:Java實現代碼MainActivity.java文件
1 import android.os.AsyncTask; 2 import android.os.Environment; 3 import android.support.v7.app.AppCompatActivity; 4 import android.os.Bundle; 5 import android.view.View; 6 import android.widget.ProgressBar; 7 import android.widget.TextView; 8 import java.io.BufferedInputStream; 9 import java.io.BufferedOutputStream; 10 import java.io.File; 11 import java.io.FileOutputStream; 12 import java.net.HttpURLConnection; 13 import java.net.URL; 14 /** 15 * Created by panchengjia on 2016/12/19. 16 */ 17 public class MainActivity extends AppCompatActivity { 18 //聲明publishProgress的更新標記 19 private static final int PROGRESS_MAX = 0X1; 20 private static final int UPDATE = 0X2; 21 private TextView tv; 22 ProgressBar progress; 23 int contentLen;//聲明要下載的文件總長 24 @Override 25 protected void onCreate(Bundle savedInstanceState) { 26 super.onCreate(savedInstanceState); 27 setContentView(R.layout.activity_main); 28 tv = (TextView) findViewById(R.id.tv); 29 progress = (ProgressBar) findViewById(R.id.progress); 30 } 31 public void image(View view){ 32 //啟用AsyncTask,傳入需要執行的內容(圖片地址) 33 new DownLoad().execute("http://cdnq.duitang.com/uploads/item/201402/22/20140222115440_jWNmx.thumb.700_0.jpeg"); 34 } 35 class DownLoad extends AsyncTask<String,Integer,String>{ 36 //在執行實際的后台操作前被UI Thread調用 37 @Override 38 protected void onPreExecute() { 39 super.onPreExecute(); 40 //准備下載前的初始進度 41 progress.setProgress(0); 42 } 43 //在onPreExecute執行,該方法運行在后台線程中 44 @Override 45 protected String doInBackground(String... params) { 46 try { 47 URL url = new URL(params[0]); 48 //獲取連接 49 HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 50 //獲取下載文件的大小 51 contentLen = connection.getContentLength(); 52 //根據下載文件大小設置進度條最大值(使用標記區別實時進度更新) 53 publishProgress(PROGRESS_MAX,contentLen); 54 //循環下載(邊讀取邊存入) 55 BufferedInputStream bis = new BufferedInputStream(connection.getInputStream()); 56 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new 57 File(Environment.getExternalStorageDirectory()+"/Download/ss.jpg"))); 58 int len =-1; 59 byte[] bytes = new byte[1024]; 60 while((len=bis.read(bytes))!=-1){ 61 bos.write(bytes,0,len); 62 bos.flush(); 63 //實時更新下載進度(使用標記區別最大值) 64 publishProgress(UPDATE,len); 65 //演示下載的圖片太小,網速太快,休眠300毫秒,方便大家觀察 66 Thread.sleep(300); 67 } 68 bos.close(); 69 bis.close(); 70 } catch (Exception e) { 71 e.printStackTrace(); 72 } 73 return "下載完成"; 74 } 75 //在publishProgress被調用后,UI thread會調用這個方法 76 @Override 77 protected void onProgressUpdate(Integer... values) { 78 super.onProgressUpdate(values); 79 switch (values[0]){ 80 case PROGRESS_MAX: 81 progress.setMax(values[1]); 82 break; 83 case UPDATE: 84 progress.incrementProgressBy(values[1]); 85 //獲取下載進度百分比並更新textview 86 int i=(progress.getProgress()*100)/contentLen; 87 tv.setText("下載進度為:"+i+"%"); 88 break; 89 } 90 } 91 //doInBackground方法執行完后被UI thread執行 92 @Override 93 protected void onPostExecute(String s) { 94 super.onPostExecute(s); 95 progress.setVisibility(View.GONE); 96 tv.setText(s); 97 } 98 } 99 }
第三步:AndroidMainfest.xml配置文件中添加權限
因為要使用網絡下載圖片以及使用手機存儲下載圖片,所以需要在AndroidMainfest.xml文件添加網絡以及讀寫手機外部存儲的權限:
1 <uses-permission android:name="android.permission.INTERNET" /> 2 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
最后強調一下AsyncTask的設計准則:
(1)AsyncTask的實例必須在UlThread中創建。
(2)execute方法必須在UlThread中調用。
(3)不要手動的調用onPreExecute(),onPostExecute(Result),dolnBackground(Params…),onProgressUpdate(Progress…)這幾個方法。
(4)該Task只能被執行一次,否則多次調用時將會出現異常。
(5)AsyncTask不能完全取代線程,在一些邏輯較為復雜或者需要在后台反復執行的邏輯就可能需要線程來實現了。