AsyncTask

用于執(zhí)行異步任務(wù)
AsyncTask<Params,Progress,Result>是一個(gè)抽象類,通常用于被繼承
需要指定以下三個(gè)泛型參數(shù):

Params:啟動(dòng)任務(wù)時(shí)輸入?yún)?shù)的類型
Progress:后臺(tái)任務(wù)執(zhí)行中返回進(jìn)度值的類型
Result:后臺(tái)執(zhí)行任務(wù)完成后返回結(jié)果的類型

耗時(shí)操作:如加載網(wǎng)絡(luò)圖片等需要等待的操作,通常不允許放進(jìn)主線程中

回調(diào)方法:

doInBackground:必須重寫,異步執(zhí)行后臺(tái)線程將要完成的任務(wù),所有耗時(shí)操作都將要在這個(gè)方法內(nèi)執(zhí)行
onPreExecute:執(zhí)行后臺(tái)耗時(shí)操作前被調(diào)用,通常用于完成一些初始化操作
onPostExecute:當(dāng)doInBackground()完成后系統(tǒng)會(huì)自動(dòng)調(diào)用onPostExecute()方法,并將doInBackground()的值傳給該方法
onProgressUpdate():在doInBackground()方法中調(diào)用publishProgress()方法更新任務(wù)執(zhí)行進(jìn)度后就會(huì)觸發(fā)該方法

回調(diào)方法調(diào)用順序:
onPreExecute()-->doInBackground()-->onProgressUpdate()-->onPostExecute()

通過(guò)一個(gè)例子也加深了對(duì)AsyncTask的理解:

加載一張網(wǎng)絡(luò)圖片

作為一個(gè)不穩(wěn)定的耗時(shí)操作,是嚴(yán)禁被放入主線程中的,所以需要在異步處理中下載圖像,在UI線程中設(shè)置圖像

過(guò)程:
1.創(chuàng)建一個(gè)布局文件,并創(chuàng)建一個(gè)imageView組件和一個(gè)progressBar組件
image.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    
android:padding="16dp"    
android:layout_width="match_parent"    
android:layout_height="match_parent">    
<ImageView        
android:id="@+id/imageview"        
android:layout_width="match_parent"        
android:layout_height="match_parent" />    
<ProgressBar       
android:id="@+id/progressbar"        
android:visibility="gone"        
android:layout_centerInParent="true"        
android:layout_width="wrap_content"        
android:layout_height="wrap_content" />
</RelativeLayout>

注意progressBar 使用android:visibility="gone"設(shè)置其默認(rèn)不顯示出來(lái)
android:layout_centerInParent="true"設(shè)置其居中顯示

2.創(chuàng)建ImageTest類,并創(chuàng)建內(nèi)部類myAsyncTask

public class ImageTest extends Activity {    
private ImageView mImageView;    
private ProgressBar mProgressBar;   
private static  String URL="http://img1.gtimg.com/digi/pics/hv1/109/199/2039/132636829.jpg";    
@Override    
protected void onCreate(Bundle savedInstanceState) {        
super.onCreate(savedInstanceState);        
setContentView(R.layout.image);        
mImageView=(ImageView)findViewById(R.id.imageview);        
mProgressBar=(ProgressBar)findViewById(R.id.progressbar);       
 new myAsyncTask().execute(URL);    
}    
class myAsyncTask extends AsyncTask<String,Void,Bitmap>{        
@Override        
protected void onPreExecute() {            
super.onPreExecute();            
mProgressBar.setVisibility(View.VISIBLE);       
 }        
@Override        
protected void onPostExecute(Bitmap bitmap) {            
super.onPostExecute(bitmap);            //操作UI設(shè)置圖像            
mProgressBar.setVisibility(View.GONE);            
mImageView.setImageBitmap(bitmap);       
 }        
@Override        //傳入可變長(zhǎng)數(shù)組        
protected Bitmap doInBackground(String... params) {           
 //獲取傳遞進(jìn)來(lái)的參數(shù)            
String url=params[0];            
Bitmap bitmap=null;            
URLConnection connection;           
 InputStream is;           
 try {               
 connection=new URL(url).openConnection();                
is=connection.getInputStream();//獲取輸入流                
BufferedInputStream bis=new BufferedInputStream(is);                
Thread.sleep(3000);                bitmap= 
BitmapFactory.decodeStream(bis);//將輸入流解析成bitmap                
is.close();                
bis.close();           
 } catch (IOException e) {                
e.printStackTrace();            
} catch (InterruptedException e) {                
e.printStackTrace();           
 }            
return bitmap;      
  }   
 }
}

其中注意:
1.傳入U(xiǎn)RL為String類型,表示需要加載的圖片地址

protected Bitmap doInBackground(String... params) {                    
String url=params[0]; 

doInBackground()方法傳遞進(jìn)來(lái)的數(shù)組是一個(gè)可變長(zhǎng)數(shù)組,也就是說(shuō)可以傳遞不只一個(gè)參數(shù),由于本例子只傳入一個(gè)參數(shù),所以只需要取出第一位即可,即params[0]

connection=new URL(url).openConnection();

這里獲取網(wǎng)絡(luò)連接對(duì)象

is=connection.getInputStream();

這里獲取輸入流

BufferedInputStream bis=new BufferedInputStream(is);
//將輸入流包裝
bitmap= BitmapFactory.decodeStream(bis);

將輸入流解析成bitmap

6.在線程開始之前需要先把progressBar設(shè)置成可見

protected void onPreExecute() {    
super.onPreExecute();    
mProgressBar.setVisibility(View.VISIBLE);}
protected void onPostExecute(Bitmap bitmap) {    super.onPostExecute(bitmap);      mProgressBar.setVisibility(View.GONE);    mImageView.setImageBitmap(bitmap);}

doInBackground()方法執(zhí)行后返回一個(gè)bitmap圖像,獲取到圖像后就可以操作UI設(shè)置圖像,同時(shí)將progressBar隱藏

new myAsyncTask().execute(URL);

設(shè)置傳遞進(jìn)去的參數(shù),首先調(diào)用onPreExecute()方法,接下來(lái)調(diào)用doInBackground()方法,最后調(diào)用onPostExecute()方法

9.最后補(bǔ)充Mainfest文件,并添加activity和網(wǎng)絡(luò)權(quán)限
<uses-permission android:name="android.permission.INTERNET"/>
再在主線程中添加按鈕事件

10.若覺得圖片加載太快看不見progressBar可以添加Thread.sleep(3000)讓其睡眠3秒再開始加載

onPreExecute()加載進(jìn)度條
doInBackground()下載網(wǎng)絡(luò)數(shù)據(jù)(耗時(shí)操作)
onPostExecute()顯示圖片

下面用ProgressBar來(lái)模擬進(jìn)度條

首先創(chuàng)建布局文件并設(shè)置progressBar樣式
progressbar.xml

<RelativeLayout 
xmlns:android="http://schemas.android.com/apk/res/android"    
android:orientation="vertical"    android:padding="16dp"    
android:layout_width="match_parent"    
android:layout_height="match_parent">    
<ProgressBar        
android:id="@+id/pg"        
style="?android:attr/progressBarStyleHorizontal"        
android:layout_gravity="center_horizontal"        
android:layout_width="match_parent"        
android:layout_height="wrap_content"        
android:layout_centerVertical="true"        
android:layout_centerHorizontal="true"        
android:layout_alignParentStart="true" />
</RelativeLayout>

然后創(chuàng)建ProgressBarTest類

public class ProgressBarTest extends Activity {    
ProgressBar mProgressBar;    
private myAsyncTask mTask;    
@Override    
protected void onCreate(Bundle savedInstanceState) {        
super.onCreate(savedInstanceState);        
setContentView(R.layout.progressbar);        
mProgressBar=(ProgressBar)findViewById(R.id.pg);        
mTask=new myAsyncTask();        
mTask.execute();    
}    
class myAsyncTask extends AsyncTask<Void,Integer,Void>{        
@Override        
protected Void doInBackground(Void... params) {            
for(int i=0;i<100;i++){                
publishProgress(i);                
try {                    
Thread.sleep(1000);                
} 
catch (InterruptedException e) {                    
e.printStackTrace();               
 }           
 }          
  return null;     
   }       
 @Override     
   
protected void onProgressUpdate(Integer... values) {            
super.onProgressUpdate(values);            
mProgressBar.setProgress(values[0]);       
 }   
 }
}

其中

protected Void doInBackground(Void... params) {   
 for(int i=0;i<100;i++){       
 publishProgress(i);        
try {            
Thread.sleep(1000);      
  } 
catch (InterruptedException e) {           
 e.printStackTrace();        }    }   
 return null;}

publishProgress(i);用于調(diào)用更新進(jìn)度的函數(shù),所以將i傳入

protected void onProgressUpdate(Integer... values) {            
super.onProgressUpdate(values);            
mProgressBar.setProgress(values[0]);       
 }   
將values即傳入的i取出并設(shè)置給progressBar
可是運(yùn)行時(shí),若退出再進(jìn)入頁(yè)面,progressBar會(huì)等一段時(shí)間再開始動(dòng),這是因?yàn)楸仨毜鹊角懊娴膖ask執(zhí)行完成后才能執(zhí)行后面的操作,所以要等到for循環(huán)執(zhí)行完畢后才能執(zhí)行下一次循環(huán)

解決方法:使Activity的生命周期和AsyncTask的生命周期保持一致即可

添加onPause()方法

@Override
//當(dāng)mTask線程不為空而且狀態(tài)是Running
protected void onPause() {    
super.onPause();    
if(mTask!=null&&            
mTask.getStatus() == AsyncTask.Status.RUNNING){        
mTask.cancel(true);    
}}

判斷當(dāng)mTask線程不為空而且狀態(tài)是Running時(shí),取消線程
可是運(yùn)行后還是沒解決,這是因?yàn)閏ancel只是將對(duì)應(yīng)的AsyncTask標(biāo)記為Cancel狀態(tài),并不是真正的取消線程的執(zhí)行
而且在java中也是不能直接停止線程的,必須等一個(gè)線程執(zhí)行完畢后才能執(zhí)行后面的操作

所以應(yīng)該在具體的異步線程中去檢測(cè)狀態(tài)值的改變,一旦當(dāng)前AsyncTask的狀態(tài)改為cancel,就跳出循環(huán)來(lái)結(jié)束掉操作,從而結(jié)束掉整個(gè)線程的邏輯

在doInBackground()方法中加入判斷

protected Void doInBackground(Void... params) {    
for(int i=0;i<100;i++){        
if(isCancelled()){            
break;        
}       
 publishProgress(i);       
 try {           
 Thread.sleep(1000);        
} catch (InterruptedException e) {           
 e.printStackTrace();        }    }   
 return null;}

同理在更新操作中也要加入判斷

protected void onProgressUpdate(Integer... values) {        
super.onProgressUpdate(values);        
if (isCancelled()){           
 return;      
  }        
mProgressBar.setProgress(values[0]);    }}

總結(jié)

AsyncTask使用注意事項(xiàng):
-必須在UI線程(onCreate())中創(chuàng)建AsyncTask實(shí)例
-必須在UI線程(onCreate())中調(diào)用AsyncTask的execute()方法
-重寫的四個(gè)方法時(shí)系統(tǒng)自動(dòng)調(diào)用的,不能手動(dòng)調(diào)用
-每個(gè)AsyncTask只能被執(zhí)行一次,多次調(diào)用會(huì)引起異常
-在AsyncTask中只有doInBackground()運(yùn)行在其他線程,其他方法都運(yùn)行在主線程,也就是說(shuō)在其他方法中可以更新UI,而唯一在這個(gè)方法中需要做異步處理,不能再此方法中更新UI,安卓提供了onPreExecute()和onPostExecute()去承接異步處理中的操作去更新UI

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末慨削,一起剝皮案震驚了整個(gè)濱河市瘩例,隨后出現(xiàn)的幾起案子础爬,更是在濱河造成了極大的恐慌,老刑警劉巖樟凄,帶你破解...
    沈念sama閱讀 216,651評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件奴饮,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡新啼,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門刹碾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)燥撞,“玉大人,你說(shuō)我怎么就攤上這事迷帜∥锸妫” “怎么了?”我有些...
    開封第一講書人閱讀 162,931評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵戏锹,是天一觀的道長(zhǎng)冠胯。 經(jīng)常有香客問我,道長(zhǎng)锦针,這世上最難降的妖魔是什么荠察? 我笑而不...
    開封第一講書人閱讀 58,218評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮奈搜,結(jié)果婚禮上悉盆,老公的妹妹穿的比我還像新娘。我一直安慰自己馋吗,他們只是感情好焕盟,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著宏粤,像睡著了一般脚翘。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上绍哎,一...
    開封第一講書人閱讀 51,198評(píng)論 1 299
  • 那天来农,我揣著相機(jī)與錄音,去河邊找鬼蛇摸。 笑死备图,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的赶袄。 我是一名探鬼主播,決...
    沈念sama閱讀 40,084評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼抠藕,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼饿肺!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起盾似,我...
    開封第一講書人閱讀 38,926評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤敬辣,失蹤者是張志新(化名)和其女友劉穎雪标,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體溉跃,經(jīng)...
    沈念sama閱讀 45,341評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡村刨,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了撰茎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嵌牺。...
    茶點(diǎn)故事閱讀 39,731評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖龄糊,靈堂內(nèi)的尸體忽然破棺而出逆粹,到底是詐尸還是另有隱情,我是刑警寧澤炫惩,帶...
    沈念sama閱讀 35,430評(píng)論 5 343
  • 正文 年R本政府宣布僻弹,位于F島的核電站,受9級(jí)特大地震影響他嚷,放射性物質(zhì)發(fā)生泄漏蹋绽。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評(píng)論 3 326
  • 文/蒙蒙 一筋蓖、第九天 我趴在偏房一處隱蔽的房頂上張望蟋字。 院中可真熱鬧,春花似錦扭勉、人聲如沸鹊奖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)忠聚。三九已至,卻和暖如春唱捣,著一層夾襖步出監(jiān)牢的瞬間两蟀,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工震缭, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留赂毯,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,743評(píng)論 2 368
  • 正文 我出身青樓拣宰,卻偏偏與公主長(zhǎng)得像党涕,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子巡社,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評(píng)論 2 354

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

  • Android開發(fā)者:你真的會(huì)用AsyncTask嗎膛堤? 導(dǎo)讀.1 在Android應(yīng)用開發(fā)中,我們需要時(shí)刻注意保證...
    cxm11閱讀 2,709評(píng)論 0 29
  • Android Handler機(jī)制系列文章整體內(nèi)容如下: Android Handler機(jī)制1之ThreadAnd...
    隔壁老李頭閱讀 3,206評(píng)論 1 15
  • 在Android中我們可以通過(guò)Thread+Handler實(shí)現(xiàn)多線程通信晌该,一種經(jīng)典的使用場(chǎng)景是:在新線程中進(jìn)行耗時(shí)...
    呂侯爺閱讀 2,051評(píng)論 2 23
  • 每天傍晚四點(diǎn)多肥荔,鷺鳥陸續(xù)回巢绿渣,五點(diǎn)來(lái)鐘,回巢的鳥群開始大起來(lái)燕耿,然后又小批陸續(xù)回巢中符。天黑前,運(yùn)氣好的話誉帅,可以看到兩三...
    山野印象閱讀 253評(píng)論 0 0
  • 眼睛疲勞時(shí)遮蔽了欲望的光 在烈日驕陽(yáng)下游蕩 抱著那份念想 熱烈淀散,發(fā)燙 觸摸,柔軟細(xì)膩而狂野 一步步淪陷 拒絕兩個(gè)字...
    霂隱閱讀 90評(píng)論 0 0