本篇內(nèi)容主要講解“怎么構(gòu)建AsyncTask”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“怎么構(gòu)建AsyncTask”吧!
創(chuàng)新互聯(lián)是一家專注于成都網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站與策劃設(shè)計(jì),黔西南州網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)做網(wǎng)站,專注于網(wǎng)站建設(shè)10年,網(wǎng)設(shè)計(jì)領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:黔西南州等地區(qū)。黔西南州做網(wǎng)站價(jià)格咨詢:13518219792
Android 單線程模型,多線程的操作系統(tǒng)
耗時(shí)操作放在非主線程中運(yùn)行
子線程中更新UI
封裝簡(jiǎn)化異步操作
AsyncTask
doInBackground(): 必須重寫,異步執(zhí)行后臺(tái)線程將要完成的任務(wù)
onPreExecute(): 執(zhí)行后臺(tái)線程前被調(diào)用,通常用來(lái)做一些初始化操作
onPostExecute():當(dāng)doInBackground() 方法完成后系統(tǒng)會(huì)自動(dòng)調(diào) 用,并將doInBackground() 方法的返回值作為參數(shù)春遞給onPostExecute()方法
onProgressUpdate():在doBackground() 方法中調(diào)用publishProgress()方法更新任務(wù)的執(zhí)行進(jìn)度后,就會(huì)調(diào)用該方法
接下來(lái)我們寫個(gè)程序測(cè)試一下這些方法的執(zhí)行順序
首先創(chuàng)建一個(gè)AsyncTask的子類 MyAsyncTask
public class MyAsyncTask extends AsyncTask{ String LOGCAT = "LOGCAT"; @Override protected Void doInBackground(Void... params) { Log.d(LOGCAT, "doInBackground------------"); System.out.println("doInBackground------------"); return null; } @Override protected void onPreExecute() { super.onPreExecute(); Log.d(LOGCAT, "onPreExecute"); } @Override protected void onPostExecute(Void result) { super.onPostExecute(result); Log.d(LOGCAT, "onPostExecute"); } @Override protected void onProgressUpdate(Void... values) { super.onProgressUpdate(values); Log.d(LOGCAT, "onProgressUpdate"); } }
在 MainActivity 中進(jìn)行測(cè)試
public class MainActivity extends Activity @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); MyAsyncTask asyncTask = new
在模擬器上部署運(yùn)行之后,查看Logcat 可以看到下面的日志
從日志中可以看到,幾個(gè)方法的執(zhí)行順序依次為 : onPreExecute –>doInBackground –>onPostExecute
然后我們?cè)赿oInBackground 方法中添加這句代碼 publishProgress();
@Override protected Void doInBackground(Void... params) { Log.d(LOGCAT, "doInBackground------------"); //調(diào)用該方法后,會(huì)執(zhí)行 onPostExecute() 方法 publishProgress(); return null; }
再次運(yùn)行,觀察logcat 輸出,可看到在 doInBackground() 方法中執(zhí)行了 publishProgress()方法后會(huì)調(diào)用 onProgressUpdate() 方法,顧名思義就是更新進(jìn)度條的方法
下面我們來(lái)看一個(gè)典型的異步操作的例子,網(wǎng)絡(luò)操作,從 Android4.0 之后,網(wǎng)絡(luò)操作就嚴(yán)禁被放入到主線程中執(zhí)行.下面是一個(gè)采用在異步線程處理下載圖像
在UI線程設(shè)置圖像的例子
布局界面代碼比較簡(jiǎn)單,如下
MainActivity代碼如下
public class MainActivity extends Activity private ImageView image;// 要展示的圖片 private ProgressBar pb;// 進(jìn)度條 // 要加載的圖片的url String imageUrl = "/upload/otherpic59/2016_10_09logo_61d59f1e74db0be41ffe1d31fb8edef3.png"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); image = (ImageView) findViewById(R.id.iv); pb = (ProgressBar) findViewById(R.id.pb); } // 下載按鈕的點(diǎn)擊事件 public void loadImage(View view) { AsyncTaskTest asyncTaskTest = new AsyncTaskTest(); // execute()方法接受一個(gè)可變長(zhǎng)數(shù)組的參數(shù),可在 doInBackground()方法中獲取 asyncTaskTest.execute(imageUrl); } class AsyncTaskTest extends AsyncTask{ Bitmap bitmap; // 下載開始前的一些初始化操作 @Override protected void onPreExecute() { // TODO Auto-generated method stub super.onPreExecute(); pb.setVisibility(View.VISIBLE);// 在下載之前將 Progress 顯示出來(lái) } // 在此方法中進(jìn)行網(wǎng)絡(luò)耗時(shí)操作,下載完成后會(huì)執(zhí)行 onPostExecute 方法,并把返回值傳遞給它 @Override protected Bitmap doInBackground(String... params) { // 獲取傳遞進(jìn)來(lái)的參數(shù) String url = params[0]; Bitmap btm = null; URLConnection connection; InputStream is; try { connection = new URL(url).openConnection(); is = connection.getInputStream(); BufferedInputStream bis = new BufferedInputStream(is); // 通過(guò) BitmapFactory.decodeStream 方法吧輸入流轉(zhuǎn)換為 bitmap 對(duì)象 bitmap = BitmapFactory.decodeStream(bis); is.close(); bis.close(); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } // 為了看清楚進(jìn)度條,人為加一個(gè)延時(shí)操作,便于觀察 try { Thread.sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } return bitmap; } // doInBackground()方法執(zhí)行完畢后會(huì)自動(dòng)調(diào)用此方法, 此方法的參數(shù)是 doInBackground() 方法的返回值. @Override protected void onPostExecute(Bitmap result) { // TODO Auto-generated method stub super.onPostExecute(result); pb.setVisibility(View.GONE);// 隱藏進(jìn)度條 image.setImageBitmap(result);// 顯示下載的網(wǎng)絡(luò)圖片
上面代碼注釋很詳細(xì),不再多做解釋,只要搞懂了 AsyncTask 的幾個(gè)方法的作用于執(zhí)行周期,上面的代碼很容易理解.
下面我們?cè)偻ㄟ^(guò)一個(gè)模擬進(jìn)度條的小例子,進(jìn)一步認(rèn)識(shí)AsyncTask 異步任務(wù)的用法
布局界面很簡(jiǎn)單,如下
Activity 代碼也很簡(jiǎn)單
public class progressBarTest extends Activity private ProgressBar pb; private TextView tv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.pro); pb = (ProgressBar) findViewById(R.id.pb); tv = (TextView) findViewById(R.id.tv_show); MyAsyncTask myAsyncTask = new MyAsyncTask(); myAsyncTask.execute(); } class MyAsyncTask extends AsyncTask{ @Override protected Void doInBackground(Void... params) { //模擬進(jìn)度的更新 for (int i = 0; i <= 100; i++) { // 更新進(jìn)度條,重寫 onProgressUpdate()方法,參數(shù)為 publishProgress(i)的參數(shù) publishProgress(i);// 此方法傳入的參數(shù)就是 AsyncTask 的第二個(gè)指定的參數(shù)類型 // 睡眠200毫秒 try { Thread.sleep(200); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return null; } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); // 更新顯示數(shù)據(jù) tv.setText(values[0] + "%"); // 更新進(jìn)度條 pb.setProgress(values[0]);// 水平進(jìn)度條的進(jìn)度為百分制
是不是很簡(jiǎn)單,但是不要高興太早,對(duì)于這個(gè)程序,當(dāng)我們點(diǎn)擊下載,然后點(diǎn)擊返回,然后再點(diǎn)擊下載,進(jìn)度條居然等了好久才開始更新
這是為啥呢?
其實(shí)AsyncTask 底層是通過(guò)線程池進(jìn)行作用的,當(dāng)一個(gè)線程沒有作用完畢的時(shí)候,其它線程即必須進(jìn)入線程池進(jìn)行等待,等到前面的線程完事后,才會(huì)輪到自己執(zhí)行,所以,當(dāng)我們返回再次進(jìn)入的時(shí)候,因?yàn)榍耙粋€(gè)線程正在執(zhí)行更新進(jìn)度條操作,所以當(dāng)前線程必須等待前一個(gè)AsyncTask執(zhí)行完畢后自己才可以執(zhí)行.
那么如何解決這個(gè)問(wèn)題呢?
其實(shí)很簡(jiǎn)單,AsyncTask 框架已經(jīng)為我們考慮到了這個(gè)問(wèn)題,我們可以通過(guò) cancel() 方法來(lái)取消掉一個(gè)AsyncTask開啟的一個(gè)異步任務(wù).此方法接受一個(gè)布爾值的參數(shù),
我們要做的很簡(jiǎn)單,重寫Activity的 onPause() 方法,把AsyncTask的聲明周期和Activity綁定到一起. 并且在 doInBackground() 方法中做異步判斷.代碼如下
@Override protected Void doInBackground(Void... params) { // 模擬進(jìn)度的更新 for (int i = 0; i <= 100; i++) { // 當(dāng)收到取消請(qǐng)求時(shí),不要在更新進(jìn)度條,直接break結(jié)束for循環(huán) if (isCancelled()) { break; } // 更新進(jìn)度條,重寫 onProgressUpdate()方法,參數(shù)為 publishProgress(i)的參數(shù) publishProgress(i);// 此方法傳入的參數(shù)就是 AsyncTask的第二個(gè)指定的參數(shù)類型 // 睡眠200毫秒 try { Thread.sleep(200); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return null; }
并且在 onProgressUpdate () 方法中也做同樣處理
@Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); // 當(dāng)收到取消請(qǐng)求時(shí),不要在更新進(jìn)度條,直接return結(jié)束 if (isCancelled()) { return; } // 更新顯示數(shù)據(jù) tv.setText(values[0] + "%"); // 更新進(jìn)度條 pb.setProgress(values[0]);// 水平進(jìn)度條的進(jìn)度為百分制
好了一切都做完了,我們?cè)俅芜\(yùn)行程序可以看到
這里有一個(gè)注意事項(xiàng),是關(guān)于AsyncTask 的 cancel(true);方法.其實(shí)當(dāng)我們調(diào)用了 AsyncTask的cancel(true)方法時(shí),并不會(huì)中斷當(dāng)前的線程,有人對(duì)此做出的解釋是
AsyncTask不會(huì)不考慮結(jié)果而直接結(jié)束一個(gè)線程。調(diào)用cancel()其實(shí)是給AsyncTask設(shè)置一個(gè)”canceled”狀態(tài)。這取決于你去檢查AsyncTask是否已經(jīng)取消,之后決定是否終止你的操作。對(duì)于mayInterruptIfRunning——它所作的只是向運(yùn)行中的線程發(fā)出interrupt()調(diào)用。在這種情況下,你的線程是不可中斷的,也就不會(huì)終止該線程。
說(shuō)的不是很清楚,我們可以查看 cancel()方法的源代碼
public boolean cancel(boolean mayInterruptIfRunning) { if (!(state == NEW && U.compareAndSwapInt(this, STATE, NEW, mayInterruptIfRunning ? INTERRUPTING : CANCELLED))) return false; try { // in case call to interrupt throws exception if (mayInterruptIfRunning) { try { Thread t = runner; if (t != null) t.interrupt(); } finally { // final state U.putOrderedInt(this, STATE, INTERRUPTED); } } } finally { finishCompletion(); } return true; }
可以看到,這里只是調(diào)用了該線程的 t.interrupt(); 方法.對(duì)java線程中斷機(jī)制的理解在此就顯得非常重要了:
Java的中斷是一種協(xié)作機(jī)制。也就是說(shuō)調(diào)用線程對(duì)象的interrupt方法并不一定就中斷了正在運(yùn)行的線程,它只是要求線程自己在合適的時(shí)機(jī)中斷自己,
所以我們要想完全停掉這個(gè)線程,最好的做法是通過(guò)isCanceled()方法.做出顯影的判斷
到此,相信大家對(duì)“怎么構(gòu)建AsyncTask”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!