-
AsyncTask四個(gè)方法:onPreExecute()、doInBackground()、onProgressUpdate()、onPostExecute()。 四個(gè)方法中只有doInBackground()運(yùn)行在其他線程,而其他都運(yùn)行在主線程。所以其他3個(gè)方法都可以更新UI,而只有doInBackground()需要做異步處理,并且不可以直接更新UI。 另外,安卓提供的onPostExecute()和onPregressUpdate()方法來承接了異步處理的操作,從而能夠在異步處理的過程中,去更新UI,這也是AsyncTask所簡(jiǎn)化、所封裝的非常好的方面。查看全部
-
doInBackground:所有耗時(shí)操作都要在此完成查看全部
-
AsyncTask四個(gè)方法:onPreExecute()、doInBackground()、onProgressUpdate()、onPostExecute()。 四個(gè)方法中只有doInBackground()運(yùn)行在其他線程,而其他都運(yùn)行在主線程。所以其他3個(gè)方法都可以更新UI,而只有doInBackground()需要做異步處理,并且不可以直接更新UI。 另外,安卓提供的onPostExecute()和onPregressUpdate()方法來承接了異步處理的操作,從而能夠在異步處理的過程中,去更新UI,這也是AsyncTask所簡(jiǎn)化、所封裝的非常好的方面。查看全部
-
反復(fù)執(zhí)行上一節(jié)課的異步加載,而且是不等進(jìn)度條滿就后退再執(zhí)行,會(huì)發(fā)現(xiàn)后面執(zhí)行的進(jìn)度條遲遲沒有響應(yīng),為什么呢?這并非bug,而是 AsyncTask 所實(shí)行的一種機(jī)制。AsyncTask的底層是通過線程池去作用的。當(dāng)一個(gè)線程沒有完成的時(shí)候,后面的線程就無法開始。我們上一節(jié)課用了for()循環(huán)去執(zhí)行進(jìn)度條 的更新操作,必須等到for()循環(huán)結(jié)束后才會(huì)執(zhí)行下一個(gè)Task。 --------- 那么,如何去解決這樣的問題呢? 很簡(jiǎn)單,令A(yù)syncTask的生命周期和Activity或者Fragment的生命周期保持一致就可以了。 回到ProgressBar,重寫onPause(),在Activity執(zhí)行onPause()的時(shí)候,對(duì)AsyncTask進(jìn)行判斷: 如果AsyncTask不為空且處于Running狀態(tài),我們就要取消該線程: protected void onPause() { super.onPause(); if(mTask!=null && mTask.getStatus()==AsyncTask.Status.RUNNING){ mTask.cancel(true); } } cancle()方法只是將對(duì)應(yīng)的AsyncTask標(biāo)記為cancel狀態(tài),并不是真正地取消線程的執(zhí)行。 另外,我們?cè)贘ava中也是沒辦法直接粗暴地停止一個(gè)線程,我們必須要等一個(gè)線程執(zhí)行完畢之后才能繼續(xù)其他線程的操作。 -------------- 那要如何快速停止線程呢? 1. 在onPause()中標(biāo)記取消狀態(tài):mTask.cancel(true); 既然我們已經(jīng)標(biāo)記了cancel狀態(tài),那么可以在AsyncTask中監(jiān)測(cè)這樣的改變,一旦當(dāng)前狀態(tài)改為cancelled,我們就要跳出循環(huán),立刻結(jié)束當(dāng)前操作,從而結(jié)束整個(gè)線程邏輯。 2. 在doInBackground()方法的for()循環(huán)內(nèi)添加isCancelled()對(duì)線程的狀態(tài)進(jìn)行判斷: if(isCancelled())break; 3. 同理,在onProgressUpdate()方法中也做類似的處理: if(isCancelled())return; 通過如上操作,我們就能快速停止當(dāng)前線程,將處理權(quán)交給下一個(gè)AsyncTask。查看全部
-
創(chuàng)建內(nèi)部類 MyAsyncTask 繼承 AsyncTask: 1. MyAsyncTask extends AsyncTask<Void,Integer,Void>,因?yàn)檫@里不需要URL路徑也不需要返回值,只需要傳進(jìn)一個(gè)更新進(jìn)度分參數(shù)類型,這里指定為整型。 2. 通過for循環(huán)設(shè)置進(jìn)度值,但是如何將進(jìn)度傳遞給ProgressBar呢?當(dāng)然是通過publishProgress();此方法可以傳遞一個(gè)Integer類型的參數(shù)。 3. 通過publishProgress(i)將for循環(huán)的i傳出之后,還需要設(shè)置一個(gè)方法接收i,這個(gè)方法就是onProgressUpdate(Integer... values),明顯可以看出該方法傳進(jìn)的是Integer類型的參數(shù)。注意這里的values是一個(gè)數(shù)組,我們真正需要的是values[0],這才是傳進(jìn)來的進(jìn)度值。再通過mProgressBar.setProgress(values[0]);將values[0]設(shè)置為當(dāng)前進(jìn)度值。 4. 定義一個(gè)MyAsyncTask(屬于ProgrssBar的)對(duì)象myTask,并在onCreate()方法中進(jìn)行實(shí)例化。調(diào)用mTask的execute()方法啟動(dòng)異步加載,這里的execute()無需參數(shù)。 流程: 1. execute()啟動(dòng)異步加載; 2. doInBackground的for循環(huán)模擬進(jìn)度的更新(publishProgress(i));并添加了線程睡眠以便觀察(Thread.sleep(300))。 3. onProgressUpdate()獲取進(jìn)度的更新值;這樣我們可以在UI線程中獲得異步線程實(shí)時(shí)傳遞的進(jìn)度更新值,用來更新我們的ProgressBar。 其他操作: 1. 在activity_main.xml中添加新的Button、新的點(diǎn)擊事件。 2. 將ProgressBarTest部署到MainActivity: public void loadProgress(View view){ startActivity(new Intent(this,ProgressBarTest.class)); } 3. 配置文件ActivityManifest: <activity android:name=".ProgressBarTest"/>查看全部
-
調(diào)用異步操作的流程: 我們?cè)谥骶€程中創(chuàng)建MyAsyncTask的實(shí)例,調(diào)用execute()方法,就可以開啟AsyncTask異步線程操作。 1. 在ImageTask.java的onCreate()方法中創(chuàng)建內(nèi)部類MyAsyncTask對(duì)象,調(diào)用該對(duì)象的execute()方法,該方法開啟異步線程的操作,execute()傳進(jìn)一個(gè)或多個(gè)參數(shù),作為doInBackground(String... params)的參數(shù)。 2. onPreExecute()對(duì)整個(gè)異步操作做一些初始化操作,這里是顯示進(jìn)度條,提示用戶等待。 3. doInBackground()做真正的異步操作處理,做任意的耗時(shí)操作,并返回指定的類型。 4. onPostExecute()獲取異步操作的返回結(jié)果,由于onPostExecute()運(yùn)行在主線程,方便我們操作UI,而這里的例子就是設(shè)置ImageView。 ----------------- 其他事項(xiàng): 1. 在配置文件AndroidManifest.xml 中添加Activity: <activity android:name=".ImageTest" /> 并設(shè)置網(wǎng)絡(luò)權(quán)限: <uses-permission android:name="android.permission.INTERNET"></uses> 2. 如果網(wǎng)速太給力,為了看到異步加載的效果,我們需要人為地增加時(shí)間。。。在doInBackgroung()中添加一句線程休眠操作: Thread.sleep(3000); 此方法需要捕捉異常。 3. 增加點(diǎn)擊事件:在activity_main.xml中添加一個(gè)Button,直接在Buttonn中添加屬性: android:onClick="loadImage",就聲明了點(diǎn)擊事件,然后在MainActivity中創(chuàng)建該方法: //點(diǎn)擊事件 public void loadImage(View view){ startActivity(new Intent(this,ImageTest.class));//Activity之間的通信 } 該方法在onCreate()外面。查看全部
-
AsyncTask<String,Void,Bitmap>三個(gè)參數(shù)分別為:url類型,進(jìn)度值類型,返回值類型。 這里的例子暫時(shí)不設(shè)置進(jìn)度值,url設(shè)置為String類型,又因?yàn)槲覀兗虞d的是一張Bitmap,所以返回的參數(shù)類型設(shè)置為 Bitmap。 1. doInBackground(String...params)傳進(jìn)來的是一個(gè)可變長(zhǎng)數(shù)組,也就是說,我們可以傳進(jìn)不止一個(gè)參數(shù)(通過execute()傳進(jìn)來),這些參數(shù)依次存在于這個(gè)數(shù)組中。現(xiàn)在只有一個(gè)參數(shù),所以只要寫個(gè)params[0]取出對(duì)應(yīng)的URL即可。 2. 定義一個(gè)Bitmap,也就是我們所要獲取的Bitmap。 3. 定義一個(gè)訪問網(wǎng)絡(luò)的URLconnection,也就是一個(gè)網(wǎng)絡(luò)連接對(duì)象connection。 4. 定義一個(gè)InputStream,用于獲取數(shù)據(jù)的輸入流。 5. 初始化connection:connection = new URL(url).openConnection();這里需要自行導(dǎo)入jar包:import java.net.URL; 另外需要try-catch包圍。 6. 獲取輸入流:is = connection.getInputStream(); 7. 對(duì)輸入流進(jìn)行包裝:BufferedInputStream bis = new BufferedInputStream(is); 8. 通過decodeStream()將輸入流解析成 Bitmap:bitmap = BitmapFactory.decodeStream(bis); 9. 關(guān)閉輸入流、返回 bitmap。查看全部
-
網(wǎng)絡(luò)操作作為一種不穩(wěn)定的耗時(shí)操作,從4.0開始就嚴(yán)禁放入主線程中。 所以去顯示一張網(wǎng)絡(luò)圖片的時(shí)候,我們需要在異步處理中下載圖像,在UI線程(主線程)中去設(shè)置圖像。 --------------- 本節(jié)課的步驟: 1. 創(chuàng)建image.xml,放置ImageView和ProgressBar; 2. 創(chuàng)建Image.java,繼承Activity類,重寫onCreate(),加載image.xml做為視圖(setContentView(R.layout.image);)。 創(chuàng)建并初始化ImageView、ProgressBar。另外附上網(wǎng)絡(luò)圖片的URL地址: private static String URL = "http://img.my.csdn.net/uploads/201504/12/1428806103_9476.png";查看全部
-
構(gòu)建AsyncTack子類的參數(shù) AsyncTask<Params,Progress,Result>是一個(gè)抽象類,通常用于被繼承,繼承AsyncTask需要指定如下三個(gè)泛型參數(shù): params:?jiǎn)?dòng)任務(wù)時(shí)輸入?yún)?shù)的類型。 progress:后臺(tái)任務(wù)執(zhí)行中,返回進(jìn)度值的類型。 Result:后臺(tái)執(zhí)行任務(wù)完成后,返回結(jié)果的類型。 ------------------------ 如何構(gòu)建AsyncTask子類的回調(diào)方法? 一個(gè)完整的AsyncTask通常需要指定如下幾個(gè)方法: 1. doInBackground:這是AsyncTask子類所必須要重寫的方法,異步執(zhí)行后臺(tái)線程將要完成的任務(wù)。我們所有的耗時(shí)操作都將在這個(gè)方法中進(jìn)行操作。 2. onPreExecute:執(zhí)行后臺(tái)耗時(shí)操作之前被調(diào)用,通常是用戶完成一些初始化操作。 3. onPostExecute:當(dāng)doInBackground()完成后,系統(tǒng)會(huì)自動(dòng)調(diào)用此方法,并將doInBackground()返回的值傳給該方法,也就是展示處理完成的結(jié)果。 4. onProgressUpdate:在doInBackground()方法中調(diào)用publishProgrsss()更新任務(wù)的執(zhí)行進(jìn)度后,就會(huì)觸發(fā)該方法(必須先調(diào)用publishProgrsss()),就可以知道當(dāng)前耗時(shí)操作的完成進(jìn)度。 ---------------------------------- 額外補(bǔ)充: 1. 注意這里的例子繼承的是 AsyncTask<Void,Void,Void>,需要帶上三個(gè)泛型,定義Void泛型要注意V是大寫。。。 2. 執(zhí)行順序:onPrRreExecute() --> doInBackground() --> onProgressUpdate() --> onPostExecute()。查看全部
-
異步任務(wù)——AsyncTask 為什么要異步任務(wù)? Android中只有主線程(也就是UI線程)可以對(duì)UI進(jìn)行操作,其他線程不能對(duì)UI進(jìn)行操作。這樣做的好處自然是保證UI的穩(wěn)定性和準(zhǔn)確性,避免了多線程同時(shí)對(duì)UI進(jìn)行操作而造成的混亂。 AsyncTask為何而生? 但同時(shí)Android又是一個(gè)多線程的操作系統(tǒng),我們不可能把所有的事情都放在主線程中去實(shí)現(xiàn),比如一些網(wǎng)絡(luò)操作、讀取文件這樣的耗時(shí)操作,如果都放在主線中執(zhí)行,就會(huì)造成后面任務(wù)的阻塞。Android系統(tǒng)會(huì)檢測(cè)這樣的阻塞,當(dāng)阻塞時(shí)間太長(zhǎng)的時(shí)候,系統(tǒng)就會(huì)拋出ANR異常(無響應(yīng))。所以我們要把耗時(shí)操作放在非主線中去執(zhí)行,這樣既保證Android的單線程模型,又防止出現(xiàn)ANR。 提到異步任務(wù),我們能想到用線程,線程池去實(shí)現(xiàn).確實(shí),Android給我們提供了主線程與其他線程通訊的機(jī)制.但同時(shí),Android也給我們提供了一個(gè)封裝好的組件--AsyncTask.利用AsyncTask,我們可以很方便的實(shí)現(xiàn)異步任務(wù)處理.AsyncTask可以在子線程中更新UI,也封裝簡(jiǎn)化了異步操作.使用線程,線程池處理異步任務(wù)涉及到了線程的同步,管理等問題.而且當(dāng)線程結(jié)束的時(shí)候還需要使用Handler去通知主線程來更新UI.而AsyncTask封裝了這一切,使得我們可以很方便的在子線程中更新UI.查看全部
-
回調(diào)方法查看全部
-
內(nèi)部類MyAsyncTask的三個(gè)泛型分別是String,Void,Bitmap查看全部
-
當(dāng)我們?cè)赿oInBackground()方法中調(diào)用publishProgress()方法的時(shí)候,就可以將一個(gè)進(jìn)度值以參數(shù)的形式傳遞給publishProgress(),這樣在onProgressUpdate()我們可以就獲取到這樣一個(gè)參數(shù),從而用于更新一個(gè)異步線程的完成進(jìn)度查看全部
-
Void是空類型查看全部
-
所有的耗時(shí)操作都將在doInBackground這個(gè)方法中完成查看全部
舉報(bào)
0/150
提交
取消