Android AsyncTask的使用及泛式引數
阿新 • • 發佈:2019-01-30
Android中我們可以通過Theater+Handler來實現多執行緒通訊,當子執行緒的耗時任務完成後通過Handler向主執行緒傳送message,主執行緒收到message後開始更新UI,而為了使程式碼更加統一,我們會使用AsyncTask類。
- 什麼是AsyncTask
- AsyncTask怎麼用
- 需要實現的幾個方法、這些方法有什麼用
- 泛型引數
- 長度可變的泛式引數
- 案例–倒計時Demo
什麼是AsyncTask
- AsyncTask是Android提供的輕量級非同步類。
- 為了降低非同步通訊的開發難度,提供了AsyncTask。
- AsyncTask直接繼承與Object類,位於android.os包中。
- 使用AsyncTask可以忽略Looper、MessageQueue、Handler等複雜物件,更便捷地完成耗時操作。
AsyncTask的使用
- 新建內部類繼承AsyncTask
- 定義AsyncTask的三種泛型引數
- 重寫doInBackground抽象方法
- 重寫onPreExecute方法
- 重寫onProgressUpdate方法
- 重寫onPostExecute方法
- 在需要啟動的地方呼叫execute方法
需要實現的幾個方法及作用
AsyncTask有四種重要的回撥方法
- onProgressUpdate
- doInBackground
- onPostExecute
- onPreExecute
這四個方法會在AsyncTask的不同時期進行自動呼叫,我們只需要實現這幾個方法的內部邏輯即可。這四個方法的一些引數和返回值都是基於泛型的,而且泛型的型別還不一樣,所以在AsyncTask的使用中會遇到三種泛型引數:Params, Progress 和 Result,如下圖所示:
Params表示用於AsyncTask執行任務的引數的型別
Progress表示在後臺執行緒處理的過程中,可以階段性地釋出結果的資料型別
Result表示任務全部完成後所返回的資料型別
我們通過呼叫AsyncTask的execute()方法傳入引數並執行任務,然後AsyncTask會依次呼叫以下四個方法: - onPreExecute
- doInBackground
- onProgressUpdate
<RelativeLayout 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:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".MainActivity">
<Button android:id="@+id/btnDownload"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="開始下載" />
<TextView android:id="@+id/textView"
android:layout_below="@id/btnDownload"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
java:
public class MainActivity extends Activity implements Button.OnClickListener {
TextView textView = null;
Button btnDownload = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView)findViewById(R.id.textView);
btnDownload = (Button)findViewById(R.id.btnDownload);
Log.i("iSpring", "MainActivity -> onCreate, Thread name: " + Thread.currentThread().getName());
}
@Override
public void onClick(View v) {
//要下載的檔案地址
String[] urls = {
"http://blog.csdn.net/iispring/article/details/47115879",
"http://blog.csdn.net/iispring/article/details/47180325",
"http://blog.csdn.net/iispring/article/details/47300819",
"http://blog.csdn.net/iispring/article/details/47320407",
"http://blog.csdn.net/iispring/article/details/47622705"
};
DownloadTask downloadTask = new DownloadTask();
downloadTask.execute(urls);
}
//public abstract class AsyncTask<Params, Progress, Result>
//在此例中,Params泛型是String型別,Progress泛型是Object型別,Result泛型是Long型別
private class DownloadTask extends AsyncTask<String, Object, Long> {
@Override
protected void onPreExecute() {
Log.i("iSpring", "DownloadTask -> onPreExecute, Thread name: " + Thread.currentThread().getName());
super.onPreExecute();
btnDownload.setEnabled(false);
textView.setText("開始下載...");
}
@Override
protected Long doInBackground(String... params) {
Log.i("iSpring", "DownloadTask -> doInBackground, Thread name: " + Thread.currentThread().getName());
//totalByte表示所有下載的檔案的總位元組數
long totalByte = 0;
//params是一個String陣列
for(String url: params){
//遍歷Url陣列,依次下載對應的檔案
Object[] result = downloadSingleFile(url);
int byteCount = (int)result[0];
totalByte += byteCount;
//在下載完一個檔案之後,我們就把階段性的處理結果釋出出去
publishProgress(result);
//如果AsyncTask被呼叫了cancel()方法,那麼任務取消,跳出for迴圈
if(isCancelled()){
break;
}
}
//將總共下載的位元組數作為結果返回
return totalByte;
}
//下載檔案後返回一個Object陣列:下載檔案的位元組數以及下載的部落格的名字
private Object[] downloadSingleFile(String str){
Object[] result = new Object[2];
int byteCount = 0;
String blogName = "";
HttpURLConnection conn = null;
try{
URL url = new URL(str);
conn = (HttpURLConnection)url.openConnection();
InputStream is = conn.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int length = -1;
while ((length = is.read(buf)) != -1) {
baos.write(buf, 0, length);
byteCount += length;
}
String respone = new String(baos.toByteArray(), "utf-8");
int startIndex = respone.indexOf("<title>");
if(startIndex > 0){
startIndex += 7;
int endIndex = respone.indexOf("</title>");
if(endIndex > startIndex){
//解析出部落格中的標題
blogName = respone.substring(startIndex, endIndex);
}
}
}catch(MalformedURLException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}finally {
if(conn != null){
conn.disconnect();
}
}
result[0] = byteCount;
result[1] = blogName;
return result;
}
@Override
protected void onProgressUpdate(Object... values) {
Log.i("iSpring", "DownloadTask -> onProgressUpdate, Thread name: " + Thread.currentThread().getName());
super.onProgressUpdate(values);
int byteCount = (int)values[0];
String blogName = (String)values[1];
String text = textView.getText().toString();
text += "\n部落格《" + blogName + "》下載完成,共" + byteCount + "位元組";
textView.setText(text);
}
@Override
protected void onPostExecute(Long aLong) {
Log.i("iSpring", "DownloadTask -> onPostExecute, Thread name: " + Thread.currentThread().getName());
super.onPostExecute(aLong);
String text = textView.getText().toString();
text += "\n全部下載完成,總共下載了" + aLong + "個位元組";
textView.setText(text);
btnDownload.setEnabled(true);
}
@Override
protected void onCancelled() {
Log.i("iSpring", "DownloadTask -> onCancelled, Thread name: " + Thread.currentThread().getName());
super.onCancelled();
textView.setText("取消下載");
btnDownload.setEnabled(true);
}
}
}
泛型引數
AsyncTask是抽象類.AsyncTask定義了三種泛型型別 Params,Progress和Result。
- Params 啟動任務執行的輸入引數,比如HTTP請求的URL。
- Progress 後臺任務執行的百分比。
- Result 後臺執行任務最終返回的結果,比如String,Integer等。
長度可變的泛型引數
可輸入多種引數
protected void onProgressUpdate(String... values)
案例-Demo倒計時
java:
public class Main2Activity extends AppCompatActivity {
private TextView tv1;
private Button button;
int time = 10;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
bindID();
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new DownloadTask().execute();
}
});
}
private void bindID() {
button = findViewById(R.id.btn);
tv1 = findViewById(R.id.tv);
}
class DownloadTask extends AsyncTask<String, String, String> {
@Override
protected String doInBackground(String... strings) {
while (time > 0) {
publishProgress(time + "");
time--;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "下載完成";
}
@Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
tv1.setText(values[0]);
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
tv1.setText(s);
}
}
}
xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Main2Activity"
android:orientation="vertical">
<Button
android:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="button"/>
<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>