Android攻城狮AsyncTask
生活随笔
收集整理的這篇文章主要介紹了
Android攻城狮AsyncTask
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
構(gòu)建AsyncTack子類的參數(shù)
AsyncTask<Params,Progress,Result>是一個(gè)抽象類,通常用于被繼承,繼承AsyncTask需要指定如下三個(gè)泛型參數(shù):
params:啟動任務(wù)時(shí)輸入?yún)?shù)的類型。
progress:后臺任務(wù)執(zhí)行中,返回進(jìn)度值的類型。
Result:后臺執(zhí)行任務(wù)完成后,返回結(jié)果的類型。
------------------------
如何構(gòu)建AsyncTask子類的回調(diào)方法?
一個(gè)完整的AsyncTask通常需要指定如下幾個(gè)方法:
1. doInBackground:這是AsyncTask子類所必須要重寫的方法,異步執(zhí)行后臺線程將要完成的任務(wù)。我們所有的耗時(shí)操作都將在這個(gè)方法中進(jìn)行操作。
2. onPreExecute:執(zhí)行后臺耗時(shí)操作之前被調(diào)用,通常是用戶完成一些初始化操作。
3. onPostExecute:當(dāng)doInBackground()完成后,系統(tǒng)會自動調(diào)用此方法,并將doInBackground()返回的值傳給該方法,也就是展示處理完成的結(jié)果。
4. onProgressUpdate:在doInBackground()方法中調(diào)用publishProgrsss()更新任務(wù)的執(zhí)行進(jìn)度后,就會觸發(fā)該方法(必須先調(diào)用publishProgrsss()),就可以知道當(dāng)前耗時(shí)操作的完成進(jìn)度。
----------------------------------
額外補(bǔ)充:
1. 注意這里的例子繼承的是 AsyncTask<Void,Void,Void>,需要帶上三個(gè)泛型,定義Void泛型要注意V是大寫。。。
2. 執(zhí)行順序:onPrRreExecute() --> doInBackground() --> onProgressUpdate() --> onPostExecute()。
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è)可變長數(shù)組,也就是說,我們可以傳進(jìn)不止一個(gè)參數(shù)(通過execute()傳進(jìn)來),這些參數(shù)依次存在于這個(gè)數(shù)組中。現(xiàn)在只有一個(gè)參數(shù),所以只要寫個(gè)params[0]取出對應(yīng)的URL即可。 2. 定義一個(gè)Bitmap,也就是我們所要獲取的Bitmap。 3. 定義一個(gè)訪問網(wǎng)絡(luò)的URLconnection,也就是一個(gè)網(wǎng)絡(luò)連接對象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. 對輸入流進(jìn)行包裝:BufferedInputStream bis = new BufferedInputStream(is); 8. 通過decodeStream()將輸入流解析成 Bitmap:bitmap = BitmapFactory.decodeStream(bis); 9. 關(guān)閉輸入流、返回 bitmap。
?
反復(fù)執(zhí)行上一節(jié)課的異步加載,而且是不等進(jìn)度條滿就后退再執(zhí)行,會發(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é)束后才會執(zhí)行下一個(gè)Task。 --------- 那么,如何去解決這樣的問題呢? 很簡單,令A(yù)syncTask的生命周期和Activity或者Fragment的生命周期保持一致就可以了。 回到ProgressBar,重寫onPause(),在Activity執(zhí)行onPause()的時(shí)候,對AsyncTask進(jìn)行判斷: 如果AsyncTask不為空且處于Running狀態(tài),我們就要取消該線程:protected void onPause() {super.onPause();if(mTask!=null && mTask.getStatus()==AsyncTask.Status.RUNNING){mTask.cancel(true);}} cancle()方法只是將對應(yīng)的AsyncTask標(biāo)記為cancel狀態(tài),并不是真正地取消線程的執(zhí)行。 另外,我們在Java中也是沒辦法直接粗暴地停止一個(gè)線程,我們必須要等一個(gè)線程執(zhí)行完畢之后才能繼續(xù)其他線程的操作。 -------------- 那要如何快速停止線程呢? 1. 在onPause()中標(biāo)記取消狀態(tài):mTask.cancel(true); 既然我們已經(jīng)標(biāo)記了cancel狀態(tài),那么可以在AsyncTask中監(jiān)測這樣的改變,一旦當(dāng)前狀態(tài)改為cancelled,我們就要跳出循環(huán),立刻結(jié)束當(dāng)前操作,從而結(jié)束整個(gè)線程邏輯。 2. 在doInBackground()方法的for()循環(huán)內(nèi)添加isCancelled()對線程的狀態(tài)進(jìn)行判斷: if(isCancelled())break; 3. 同理,在onProgressUpdate()方法中也做類似的處理: if(isCancelled())return; 通過如上操作,我們就能快速停止當(dāng)前線程,將處理權(quán)交給下一個(gè)AsyncTask。 1 public class ProgressBarTest extends Activity { 2 3 ProgressBar progressBar; 4 MyAsycnTask2 task; 5 @Override 6 protected void onCreate(Bundle savedInstanceState) { 7 // TODO Auto-generated method stub 8 super.onCreate(savedInstanceState); 9 setContentView(R.layout.progressbar); 10 progressBar = (ProgressBar) findViewById(R.id.progressBar1); 11 12 task = new MyAsycnTask2(); 13 task.execute(); 14 } 15 16 @Override 17 protected void onPause() { 18 // TODO Auto-generated method stub 19 super.onPause(); 20 if (task!=null&&task.getStatus()==AsyncTask.Status.RUNNING) { 21 task.cancel(true);//cancel()只是將對應(yīng)的task標(biāo)記為cancel狀態(tài),并不是真正取消線程執(zhí)行 22 } 23 } 24 25 class MyAsycnTask2 extends AsyncTask<Void, Integer, Void> { 26 27 @Override 28 protected void onProgressUpdate(Integer... values) { 29 // TODO Auto-generated method stub 30 // 獲取進(jìn)度更新值 31 super.onProgressUpdate(values); 32 if (isCancelled()) { 33 return; 34 } 35 progressBar.setProgress(values[0]); 36 } 37 38 @Override 39 protected Void doInBackground(Void... params) { 40 // TODO Auto-generated method stub 41 42 // 模擬進(jìn)度更新 43 for (int i = 0; i < 100; i++) { 44 if (isCancelled()) { 45 break; 46 } 47 publishProgress(i); 48 try { 49 Thread.sleep(300); 50 } catch (InterruptedException e) { 51 // TODO Auto-generated catch block 52 e.printStackTrace(); 53 } 54 } 55 return null; 56 } 57 } 58 }
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è)可變長數(shù)組,也就是說,我們可以傳進(jìn)不止一個(gè)參數(shù)(通過execute()傳進(jìn)來),這些參數(shù)依次存在于這個(gè)數(shù)組中。現(xiàn)在只有一個(gè)參數(shù),所以只要寫個(gè)params[0]取出對應(yīng)的URL即可。 2. 定義一個(gè)Bitmap,也就是我們所要獲取的Bitmap。 3. 定義一個(gè)訪問網(wǎng)絡(luò)的URLconnection,也就是一個(gè)網(wǎng)絡(luò)連接對象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. 對輸入流進(jìn)行包裝:BufferedInputStream bis = new BufferedInputStream(is); 8. 通過decodeStream()將輸入流解析成 Bitmap:bitmap = BitmapFactory.decodeStream(bis); 9. 關(guān)閉輸入流、返回 bitmap。
?
?
1 //Asynctask加載網(wǎng)絡(luò)圖片 2 //使用ProgressBar 和ProgressDialog提示下載的進(jìn)度 3 4 public class ImageTest extends Activity { 5 private ImageView imageView; 6 private ProgressBar progressBar;// 方式一:對話框提示進(jìn)度 7 String URL = "http://p4.so.qhimgs1.com/sdr/1228_768_/t01f7ed810efbfe800a.jpg"; 8 ProgressDialog dialog;// 方式二:對話框提示進(jìn)度 9 MyAsynctask1 task; 10 11 @Override 12 protected void onCreate(Bundle savedInstanceState) { 13 // TODO Auto-generated method stub 14 super.onCreate(savedInstanceState); 15 setContentView(R.layout.image); 16 imageView = (ImageView) findViewById(R.id.image); 17 progressBar = (ProgressBar) findViewById(R.id.bar); 18 19 dialog = new ProgressDialog(this); 20 dialog.setTitle("提示信息:"); 21 dialog.setMessage("laoding...."); 22 dialog.setProgressStyle(dialog.STYLE_HORIZONTAL); 23 24 MyAsynctask1 task = new MyAsynctask1(); 25 task.execute(URL); 26 27 } 28 29 // 不等進(jìn)度條滿就后退再執(zhí)行,會發(fā)現(xiàn)后面執(zhí)行的進(jìn)度條遲遲沒有響應(yīng), 30 // 令A(yù)syncTask的生命周期和Activity或者Fragment的生命周期保持一致就可以了。 31 @Override 32 protected void onPause() { 33 // TODO Auto-generated method stub 34 super.onPause(); 35 if (task != null && task.getStatus() == AsyncTask.Status.RUNNING) { 36 task.cancel(true); 37 // cancel()只是將對應(yīng)的task標(biāo)記為cancel狀態(tài),并不是真正取消線程執(zhí)行 38 } 39 } 40 41 // params:啟動任務(wù)時(shí)輸入?yún)?shù)的類型。 42 // progress:后臺任務(wù)執(zhí)行中,返回進(jìn)度值的類型。 43 // Result:后臺執(zhí)行任務(wù)完成后,返回結(jié)果的類型。 44 45 // 2. 執(zhí)行順序:onPrRreExecute() --> doInBackground() --> onProgressUpdate() --> 46 // onPostExecute()。 47 class MyAsynctask1 extends AsyncTask<String, Integer, Bitmap> { 48 @Override 49 // 1.執(zhí)行后臺耗時(shí)操作之前被調(diào)用,通常是用戶完成一些初始化操作。 50 protected void onPreExecute() { 51 // TODO Auto-generated method stub 52 super.onPreExecute(); 53 // 顯示進(jìn)度條 54 progressBar.setVisibility(View.VISIBLE); 55 dialog.show(); 56 } 57 58 // 4.當(dāng)doInBackground()完成后,系統(tǒng)會自動調(diào)用此方法,并將doInBackground()返回的值傳給該方法,也就是展示處理完成的結(jié)果。 59 @Override 60 protected void onPostExecute(Bitmap result) { 61 // TODO Auto-generated method stub/ 62 super.onPostExecute(result); 63 progressBar.setVisibility(View.GONE);// 消失進(jìn)度條 64 dialog.dismiss(); 65 imageView.setImageBitmap(result); 66 67 } 68 69 // 2. 70 // doInBackground:這是AsyncTask子類所必須要重寫的方法,異步執(zhí)行后臺線程將要完成的任務(wù)。我們所有的耗時(shí)操作都將在這個(gè)方法中進(jìn)行操作。 71 @Override 72 protected Bitmap doInBackground(String... params) { 73 // TODO Auto-generated method stub 74 75 // 從params中取出參數(shù)值,傳給url 76 String url = params[0]; 77 // 初始化參數(shù) 78 Bitmap bitmap = null; 79 URLConnection connection; 80 InputStream inputStream; 81 82 try { 83 connection = new URL(url).openConnection(); 84 inputStream = connection.getInputStream();// 獲取輸入流 85 BufferedInputStream bis = new BufferedInputStream(inputStream); 86 Thread.sleep(5000);// 睡3秒 87 // 通過decodeStream()解析輸入流 88 bitmap = BitmapFactory.decodeStream(bis); 89 inputStream.close(); 90 bis.close(); 91 92 } catch (IOException e) { 93 // TODO Auto-generated catch block 94 e.printStackTrace(); 95 } catch (InterruptedException e) { 96 // TODO Auto-generated catch block 97 e.printStackTrace(); 98 } 99 // 模擬進(jìn)度更新 100 for (int i = 0; i < 100; i++) { 101 if (isCancelled()) { 102 break; 103 } 104 publishProgress(i); 105 106 } 107 return bitmap; 108 } 109 110 // 3.在doInBackground()方法中調(diào)用publishProgrsss()更新任務(wù)的執(zhí)行進(jìn)度后,就會觸發(fā)該方法(必須先調(diào)用publishProgrsss()),就可以知道當(dāng)前耗時(shí)操作的完成進(jìn)度。 111 @Override 112 protected void onProgressUpdate(Integer... values) { 113 // TODO Auto-generated method stub 114 super.onProgressUpdate(values); 115 if (isCancelled()) { 116 return; 117 118 } 119 dialog.setProgress(values[0]); 120 progressBar.setProgress(values[0]); 121 } 122 123 } 124 125 }?
反復(fù)執(zhí)行上一節(jié)課的異步加載,而且是不等進(jìn)度條滿就后退再執(zhí)行,會發(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é)束后才會執(zhí)行下一個(gè)Task。 --------- 那么,如何去解決這樣的問題呢? 很簡單,令A(yù)syncTask的生命周期和Activity或者Fragment的生命周期保持一致就可以了。 回到ProgressBar,重寫onPause(),在Activity執(zhí)行onPause()的時(shí)候,對AsyncTask進(jìn)行判斷: 如果AsyncTask不為空且處于Running狀態(tài),我們就要取消該線程:protected void onPause() {super.onPause();if(mTask!=null && mTask.getStatus()==AsyncTask.Status.RUNNING){mTask.cancel(true);}} cancle()方法只是將對應(yīng)的AsyncTask標(biāo)記為cancel狀態(tài),并不是真正地取消線程的執(zhí)行。 另外,我們在Java中也是沒辦法直接粗暴地停止一個(gè)線程,我們必須要等一個(gè)線程執(zhí)行完畢之后才能繼續(xù)其他線程的操作。 -------------- 那要如何快速停止線程呢? 1. 在onPause()中標(biāo)記取消狀態(tài):mTask.cancel(true); 既然我們已經(jīng)標(biāo)記了cancel狀態(tài),那么可以在AsyncTask中監(jiān)測這樣的改變,一旦當(dāng)前狀態(tài)改為cancelled,我們就要跳出循環(huán),立刻結(jié)束當(dāng)前操作,從而結(jié)束整個(gè)線程邏輯。 2. 在doInBackground()方法的for()循環(huán)內(nèi)添加isCancelled()對線程的狀態(tài)進(jìn)行判斷: if(isCancelled())break; 3. 同理,在onProgressUpdate()方法中也做類似的處理: if(isCancelled())return; 通過如上操作,我們就能快速停止當(dāng)前線程,將處理權(quán)交給下一個(gè)AsyncTask。 1 public class ProgressBarTest extends Activity { 2 3 ProgressBar progressBar; 4 MyAsycnTask2 task; 5 @Override 6 protected void onCreate(Bundle savedInstanceState) { 7 // TODO Auto-generated method stub 8 super.onCreate(savedInstanceState); 9 setContentView(R.layout.progressbar); 10 progressBar = (ProgressBar) findViewById(R.id.progressBar1); 11 12 task = new MyAsycnTask2(); 13 task.execute(); 14 } 15 16 @Override 17 protected void onPause() { 18 // TODO Auto-generated method stub 19 super.onPause(); 20 if (task!=null&&task.getStatus()==AsyncTask.Status.RUNNING) { 21 task.cancel(true);//cancel()只是將對應(yīng)的task標(biāo)記為cancel狀態(tài),并不是真正取消線程執(zhí)行 22 } 23 } 24 25 class MyAsycnTask2 extends AsyncTask<Void, Integer, Void> { 26 27 @Override 28 protected void onProgressUpdate(Integer... values) { 29 // TODO Auto-generated method stub 30 // 獲取進(jìn)度更新值 31 super.onProgressUpdate(values); 32 if (isCancelled()) { 33 return; 34 } 35 progressBar.setProgress(values[0]); 36 } 37 38 @Override 39 protected Void doInBackground(Void... params) { 40 // TODO Auto-generated method stub 41 42 // 模擬進(jìn)度更新 43 for (int i = 0; i < 100; i++) { 44 if (isCancelled()) { 45 break; 46 } 47 publishProgress(i); 48 try { 49 Thread.sleep(300); 50 } catch (InterruptedException e) { 51 // TODO Auto-generated catch block 52 e.printStackTrace(); 53 } 54 } 55 return null; 56 } 57 } 58 }
?
轉(zhuǎn)載于:https://www.cnblogs.com/my334420/p/6724539.html
總結(jié)
以上是生活随笔為你收集整理的Android攻城狮AsyncTask的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python批量请求url_python
- 下一篇: Android攻城狮认识ContextM