轉發請註明出處:http://blog.csdn.net/qq_28055429/article/details/51934966
前言:因爲handler+message來實現異步操作相對複雜,故而如果只需簡單異步操作的話,可用異步任務AsyncTask來實現
一,基本知識:
(1)原型:
android.os.AsyncTask<Params,Progress,Result> :
三個參數
Params --------啓動任務執行的輸入參數,比如HTTP請求的URL。
Progress -----後臺任務執行的百分比,。
Result --------後臺執行任務最終返回的結果,比如Drawable。
(2)基本步驟:
4個步驟:
onPreExecute(): 執行後臺操作前回調的函數,常用來設置任務,例如:在用戶界面中顯示一個進度條。
doInBackground(Void... params) :後臺執行耗時的操作,常用於接受參數返回結果,結果返回到onPostExecute()中
不能直接操作UI,在執行過程中可以調用publicProgress(Progress…)來更新任務的進度。
onProgressUpdate(Progress...) : 在調用publishProgress(Progress... values)時,此方法被執行,直接將進度信息更新到UI組件上。
onPostExecute (String result):執行後臺操作完畢後自動回調此函數,後臺操作結束後的結果會返回到這裏,來使用
(3)基本方法:
boolean cancel(boolean mayInterruptIfRunning) :嘗試取消,如任務下載時,突然想停止,可設置XX.cancel(true);
execute(Params... params) :根據參數來開始執行
get():如果有必要,就等待計算完成,然後取它的結果
get(long timeout, TimeUnit unit) :如果有必要,等待規定時間的計算,然後取它的結果
boolean isCancelled() :判斷操作是否已經取消了
AsyncTask.Status getStatus() :獲取當前任務的狀態,
(4)4個原則:
1.異步任務的實例必須在UI線程中創建。
2.execute(Params... params)方法必須在UI線程中調用。
3.不要手動調用onPreExecute(),doInBackground(Params... params),onProgressUpdate(Progress... values),onPostExecute(Result result)這幾個方法。
4.一個任務實例只能執行一次,如果執行第二次將會拋出異常。
(5)用法:一般都是一個類去繼承AsyncTask,重寫裏面的方法,一般重寫的方法有:doInBackground和onPostExecute
這是官方的例子:
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}
在MainActivity中執行代碼:
new DownloadFilesTask().execute(url1, url2, url3);
二,例子:
例子(1):加載網絡圖片:
佈局:activity_third:放置一個imageView用於顯示圖片
<?xml version="1.0" encoding="utf-8"?>
<!--定義基本佈局:LinearLayout-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!--定義一個imageView來顯示圖片-->
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:src="@drawable/load"/>
</LinearLayout>
異步類:ImageAsyncTask:繼承自AsyncTask<Void , Void, Drawable>,實現其中的方法:
package testsdcard.com.maiyu.s04_79.domain;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.widget.ImageView;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import testsdcard.com.maiyu.s04_79.R;
/**自定義ImageAsynTask類,繼承自異步任務類
* Created by maiyu on 2016/7/17.
*/
public class ImageAsynTask extends AsyncTask<Void ,Void ,Drawable> {
private ImageView m ; //用來顯示圖片
private String imageUrl ; //記錄網絡圖片地址
//根據imageView對象和網絡圖片網址的,構造函數
public ImageAsynTask(ImageView i , String t){
m = i ;
imageUrl = t ;
}
//後臺執行耗時的操作
@Override
protected Drawable doInBackground(Void... voids) {
return loadImages(imageUrl); //自定義加載圖片的方法
}
//執行後臺操作完畢後自動回調此方法
@Override
protected void onPostExecute(Drawable drawable) {
super.onPostExecute(drawable);
if(drawable != null){ //判斷圖片加載是否成功
m.setImageDrawable(drawable);
}else {
m.setImageResource(R.drawable.failed);
}
}
//執行後臺操作前的回調函數
@Override
protected void onPreExecute() {
super.onPreExecute();
}
//根據網址加載圖片
private Drawable loadImages(String url) {
try{
//生成URL對象
URL mUrl = new URL(url);
//得到inputStream
InputStream inputStream = (InputStream)mUrl.openStream();
return Drawable.createFromStream(inputStream , "test"); //生成並返回圖片
}catch(IOException e){
e.printStackTrace();
}
return null;
}
}
測試類:ThridActivity:在裏面主要新建異步任務來測試加載圖片:
new ImageAsynTask(mImage , "http://p4.so.qhimg.com/t01aade72dccf26cffe.jpg").execute();
代碼如下:
package testsdcard.com.maiyu.s04_79.activity;
import android.app.Activity;
import android.os.Bundle;
import android.widget.ImageView;
import testsdcard.com.maiyu.s04_79.R;
import testsdcard.com.maiyu.s04_79.domain.ImageAsynTask;
/**
* Created by maiyu on 2016/7/17.
*/
public class ThirdActivity extends Activity {
private ImageView mImage ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_third);
mImage = (ImageView)findViewById(R.id.imageView);
//新建一個異步任務,開始加載網絡圖片
new ImageAsynTask(mImage , "http://p4.so.qhimg.com/t01aade72dccf26cffe.jpg").execute();
}
}
記得加網絡權限:
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
結果:略,,,
例子2:根據網址下載網絡Html內容,可中斷下載,即測試類cancel(boolean)方法:
佈局:activity_four:放置一個editText,兩個按鈕,即下載和停止,一個ScrollView(裏面放置一個TextView)用於顯示內容:
<?xml version="1.0" encoding="utf-8"?>
<!--定義當前的基本佈局;LinearLayout-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!--定義獲得用戶需要加載的網址的輸入框-->
<EditText
android:id="@+id/Et"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/four_edt1"/>
<!--定義用戶單擊開始加載按鈕控件-->
<Button
android:id="@+id/BtnStart"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/four_btn1"/>
<!--定義用戶單擊終止加載按鈕控件-->
<Button
android:id="@+id/BtnStop"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/four_btn2"/>
<!--用於顯示內容-->
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/Tv"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</ScrollView>
</LinearLayout>
異步類:HtmlAsyncTask繼承自AsyncTask<Void , Void, String>,再去實現裏面方法,
代碼如下:
package testsdcard.com.maiyu.s04_79.domain;
import java.io.IOException;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.TextView;
//自定義ImageAsynTask類,繼承自異步任務類
public class HtmlAsyncTask extends AsyncTask<Void, Void, String> {
//用來存儲加載網址內容成功後展示網絡源代碼的TextView對象
private TextView m;
//記錄需要加載的網絡地址
private String url;
//構造函數,傳入TextView對象和網絡地址
public HtmlAsyncTask(TextView i, String t) {
m = i;
url = t;
}
//後臺執行耗時的操作
@Override
protected String doInBackground(Void... params) {
return requestByHttpGet(url);
}
//執行後臺操作完畢後自動回調此函數
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
Log.e("isCancelled()", isCancelled() + "");
//如果用戶取消此異步任務
if (isCancelled()) {
m.setText("取消加載");
}
//如果加載的得到的網絡地址的源代碼不爲空的話,設置textview對象的值
else if (null != result) {
m.setText(result);
}
//如果加載的內容爲空的話,顯示加載失敗
else {
m.setText("加載失敗");
}
}
//執行後臺操作前回調的函數
@Override
protected void onPreExecute() {
super.onPreExecute();
}
//通過加載url的網絡內容
public String requestByHttpGet(String url) {
//新建HttpGet對象
HttpGet httpGet = new HttpGet(url);
//定義HttpClient對象
HttpClient httpClient = new DefaultHttpClient();
//定義HttpResponse實例
HttpResponse httpResp;
try {
httpResp = httpClient.execute(httpGet);
// 判斷是夠請求成功
if (httpResp.getStatusLine().getStatusCode() == 200) {
// 獲取返回的數據
String result = EntityUtils.toString(httpResp.getEntity(), "UTF-8");
Log.e("TAG", "HttpGet方式請求成功,返回數據如下:");
return result;
} else {
Log.e("TAG", "HttpGet方式請求失敗");
}
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
測試類:同理:代碼如下:
package testsdcard.com.maiyu.s04_79.activity;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import testsdcard.com.maiyu.s04_79.R;
import testsdcard.com.maiyu.s04_79.domain.HtmlAsyncTask;
//定義了本實例的主要Activity
public class FourActivity extends Activity {
//定義佈局中的TextView控件
private TextView tv;
//定義佈局中的EditText控件
private EditText et;
//定義佈局中的開始加載Button控件
private Button btnstart;
//定義佈局中的終止加載Button控件
private Button btnstop;
//定義異步請求html代碼的異步任務
protected HtmlAsyncTask hat;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findView();
setListener();
}
private void setListener() {
//設置btn的點擊監聽器
btnstart.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//初始textview的內容
tv.setText("Html加載中.........");
//獲取EditText的用戶輸入值
String str = et.getText().toString();
//啓動異步任務加載用戶輸入的url中的網絡html
hat = new HtmlAsyncTask(tv, str);
hat.execute();
}
});
btnstop.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//終止異步任務
hat.cancel(true);
}
});
}
private void findView() {
//得到佈局中的TextView的對象
tv = (TextView) findViewById(R.id.Tv);
//得到佈局中的EditText的對象
et = (EditText) findViewById(R.id.Et);
//得到佈局中的開始加載的Button的對象
btnstart = (Button) findViewById(R.id.BtnStart);
//得到佈局中的開始加載的Button的對象
btnstop = (Button) findViewById(R.id.BtnStop);
}
}
同樣要加網絡權限:
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
結果:略,,
三,總結:
AsyncTask使用的一般步驟:
(1)創建一個類,繼承AsyncTask<參數1,參數2,參數3>,參數一般爲<Void,Void,你想要返回的類型>,
如:ImageAsyncTask extends AsyncTask<Void ,Void ,Drawable> {}//獲取圖片
StringAsyncTask extends AsyncTask<Void ,Void ,String>{}//獲取字符串數據
(2)然後去重寫其中的方法,一般重寫的有doInBackground和onPostExecute
如:略,,,
(3)在測試類中去調用,並執行execute()方法。
上一個例子中:
new HtmlAsyncTask(tv, str).execute();