Android提供了一個工具類:AsyncTask,它使創建需要與用戶界面交互的長時間運行的任務變得更簡單。相對Handler來說AsyncTask更輕量級一些,適用於簡單的異步處理,不需要借助線程和Handter即可實現。AsyncTask是抽象類。AsyncTask定義了三種泛型類型Params,Progress和Result:
Params啟動任務執行的輸入參數,比如,HTTP請求的URL。
Progress後台任務執行的百分比。
Result後台執行任務最終返回的結果,比如String。
本次真機演示的下載目錄為Download文件夾,首先進入Download文件夾,沒有圖片文件,下載完成後,再次查看,可以看到本次演示的下載圖片
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。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.administrator.asynctask.MainActivity">
<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="panhouye!"
android:textSize="20sp"/>
<ProgressBar
android:id="@+id/progress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="visible"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="image"
android:text="下載圖片"/>
</LinearLayout>
第二步:Java實現代碼MainActivity.java文件
import android.os.AsyncTask;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* Created by panchengjia on 2016/12/19.
*/
public class MainActivity extends AppCompatActivity {
//聲明publishProgress的更新標記
private static final int PROGRESS_MAX = 0X1;
private static final int UPDATE = 0X2;
private TextView tv;
ProgressBar progress;
int contentLen;//聲明要下載的文件總長
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.tv);
progress = (ProgressBar) findViewById(R.id.progress);
}
public void image(View view){
//啟用AsyncTask,傳入需要執行的內容(圖片地址)
new DownLoad().execute("http://cdnq.duitang.com/uploads/item/201402/22/20140222115440_jWNmx.thumb.700_0.jpeg");
}
class DownLoad extends AsyncTask<String,Integer,String>{
//在執行實際的後台操作前被UI Thread調用
@Override
protected void onPreExecute() {
super.onPreExecute();
//准備下載前的初始進度
progress.setProgress(0);
}
//在onPreExecute執行,該方法運行在後台線程中
@Override
protected String doInBackground(String... params) {
try {
URL url = new URL(params[0]);
//獲取連接
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
//獲取下載文件的大小
contentLen = connection.getContentLength();
//根據下載文件大小設置進度條最大值(使用標記區別實時進度更新)
publishProgress(PROGRESS_MAX,contentLen);
//循環下載(邊讀取邊存入)
BufferedInputStream bis = new BufferedInputStream(connection.getInputStream());
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new
File(Environment.getExternalStorageDirectory()+"/Download/ss.jpg")));
int len =-1;
byte[] bytes = new byte[1024];
while((len=bis.read(bytes))!=-1){
bos.write(bytes,0,len);
bos.flush();
//實時更新下載進度(使用標記區別最大值)
publishProgress(UPDATE,len);
//演示下載的圖片太小,網速太快,休眠300毫秒,方便大家觀察
Thread.sleep(300);
}
bos.close();
bis.close();
} catch (Exception e) {
e.printStackTrace();
}
return "下載完成";
}
//在publishProgress被調用後,UI thread會調用這個方法
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
switch (values[0]){
case PROGRESS_MAX:
progress.setMax(values[1]);
break;
case UPDATE:
progress.incrementProgressBy(values[1]);
//獲取下載進度百分比並更新textview
int i=(progress.getProgress()*100)/contentLen;
tv.setText("下載進度為:"+i+"%");
break;
}
}
//doInBackground方法執行完後被UI thread執行
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
progress.setVisibility(View.GONE);
tv.setText(s);
}
}
}
因為要使用網絡下載圖片以及使用手機存儲下載圖片,所以需要在AndroidMainfest.xml文件添加網絡以及讀寫手機外部存儲的權限:
1 <uses-permission android:name="android.permission.INTERNET" /> 2 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
(1)AsyncTask的實例必須在UlThread中創建。
(2)execute方法必須在UlThread中調用。
(3)不要手動的調用onPreExecute(),onPostExecute(Result),dolnBackground(Params…),onProgressUpdate(Progress…)這幾個方法。
(4)該Task只能被執行一次,否則多次調用時將會出現異常。
(5)AsyncTask不能完全取代線程,在一些邏輯較為復雜或者需要在後台反復執行的邏輯就可能需要線程來實現了。