標籤:inpu 無法 串連 擷取資料 close imageview 自動調用 匯入 undle
構建AsyncTack子類的參數AsyncTask<Params,Progress,Result>是一個抽象類別,通常用於被繼承,繼承AsyncTask需要指定如下三個泛型參數:params:啟動任務時輸入參數的類型。progress:背景工作執行中,返回進度值的類型。Result:後台執行任務完成後,返回結果的類型。------------------------如何構建AsyncTask子類的回調方法?一個完整的AsyncTask通常需要指定如下幾個方法:1. doInBackground:這是AsyncTask子類所必須要重寫的方法,非同步執行後台線程將要完成的任務。我們所有的耗時操作都將在這個方法中進行操作。2. onPreExecute:執行後台耗時操作之前被調用,通常是使用者完成一些初始化操作。3. onPostExecute:當doInBackground()完成後,系統會自動調用此方法,並將doInBackground()返回的值傳給該方法,也就是展示處理完成的結果。4. onProgressUpdate:在doInBackground()方法中調用publishProgrsss()更新任務的執行進度後,就會觸發該方法(必須先調用publishProgrsss()),就可以知道當前耗時操作的完成進度。----------------------------------額外補充:1. 注意這裡的例子繼承的是 AsyncTask<Void,Void,Void>,需要帶上三個泛型,定義Void泛型要注意V是大寫。。。2. 執行順序:onPrRreExecute() --> doInBackground() --> onProgressUpdate() --> onPostExecute()。
AsyncTask<String,Void,Bitmap>三個參數分別為:url類型,進度實值型別,傳回值類型。這裡的例子暫時不設定進度值,url設定為String類型,又因為我們載入的是一張Bitmap,所以返回的參數類型設定為 Bitmap。1. doInBackground(String...params)傳進來的是一個可變長數組,也就是說,我們可以傳進不止一個參數(通過execute()傳進來),這些參數依次存在於這個數組中。現在只有一個參數,所以只要寫個params[0]取出對應的URL即可。2. 定義一個Bitmap,也就是我們所要擷取的Bitmap。3. 定義一個訪問網路的URLconnection,也就是一個網路連接對象connection。4. 定義一個InputStream,用於擷取資料的輸入資料流。5. 初始化connection:connection = new URL(url).openConnection();這裡需要自行匯入jar包:import java.net.URL; 另外需要try-catch包圍。6. 擷取輸入資料流:is = connection.getInputStream();7. 對輸入資料流進行封裝:BufferedInputStream bis = new BufferedInputStream(is);8. 通過decodeStream()將輸入資料流解析成 Bitmap:bitmap = BitmapFactory.decodeStream(bis);9. 關閉輸入資料流、返回 bitmap。
1 public class ImageTest extends Activity { 2 private ImageView imageView; 3 private ProgressBar progressBar; 4 String URL = "http://p4.so.qhimgs1.com/sdr/1228_768_/t01f7ed810efbfe800a.jpg"; 5 6 @Override 7 protected void onCreate(Bundle savedInstanceState) { 8 // TODO Auto-generated method stub 9 super.onCreate(savedInstanceState);10 setContentView(R.layout.image);11 imageView = (ImageView) findViewById(R.id.image);12 progressBar = (ProgressBar) findViewById(R.id.bar);13 14 MyAsynctask1 task = new MyAsynctask1();15 task.execute(URL);16 17 }18 19 // params:啟動任務時輸入參數的類型。20 // progress:背景工作執行中,返回進度值的類型。21 // Result:後台執行任務完成後,返回結果的類型。22 class MyAsynctask1 extends AsyncTask<String, Void, Bitmap> {23 @Override24 // 非同步初始化25 protected void onPreExecute() {26 // TODO Auto-generated method stub27 super.onPreExecute();28 // 顯示進度條29 progressBar.setVisibility(View.VISIBLE);30 }31 32 @Override33 protected void onPostExecute(Bitmap result) {34 // TODO Auto-generated method stub35 super.onPostExecute(result);36 progressBar.setVisibility(View.GONE);37 imageView.setImageBitmap(result);38 39 }40 41 @Override42 protected Bitmap doInBackground(String... params) {43 // TODO Auto-generated method stub44 45 // 從params中取出參數值,傳給url46 String url = params[0];47 // 初始化參數48 Bitmap bitmap = null;49 URLConnection connection;50 InputStream inputStream;51 52 try {53 connection = new URL(url).openConnection();54 inputStream = connection.getInputStream();// 擷取輸入資料流55 BufferedInputStream bis = new BufferedInputStream(inputStream);56 Thread.sleep(3000);// 睡3秒57 // 通過decodeStream()解析輸入資料流58 bitmap = BitmapFactory.decodeStream(bis);59 inputStream.close();60 bis.close();61 62 } catch (IOException e) {63 // TODO Auto-generated catch block64 e.printStackTrace();65 } catch (InterruptedException e) {66 // TODO Auto-generated catch block67 e.printStackTrace();68 }69 return bitmap;70 }71 72 }73 74 }
反覆執行上一節課的非同步載入,而且是不等進度條滿就後退再執行,會發現後面執行的進度條遲遲沒有響應,為什麼呢?這並非bug,而是 AsyncTask 所實行的一種機制。AsyncTask的底層是通過線程池去作用的。當一個線程沒有完成的時候,後面的線程就無法開始。我們上一節課用了for()迴圈去執行進度條 的更新操作,必須等到for()迴圈結束後才會執行下一個Task。---------那麼,如何去解決這樣的問題呢?很簡單,令AsyncTask的生命週期和Activity或者Fragment的生命週期保持一致就可以了。回到ProgressBar,重寫onPause(),在Activity執行onPause()的時候,對AsyncTask進行判斷:如果AsyncTask不為空白且處於Running狀態,我們就要取消該線程: protected void onPause() { super.onPause(); if(mTask!=null && mTask.getStatus()==AsyncTask.Status.RUNNING){ mTask.cancel(true); } }cancle()方法只是將對應的AsyncTask標記為cancel狀態,並不是真正地取消線程的執行。另外,我們在Java中也是沒辦法直接粗暴地停止一個線程,我們必須要等一個線程執行完畢之後才能繼續其他線程的操作。--------------那要如何快速停止線程呢?1. 在onPause()中標記取消狀態:mTask.cancel(true);既然我們已經標記了cancel狀態,那麼可以在AsyncTask中監測這樣的改變,一旦目前狀態改為cancelled,我們就要跳出迴圈,立刻結束當前操作,從而結束整個線程邏輯。2. 在doInBackground()方法的for()迴圈內添加isCancelled()對線程的狀態進行判斷:if(isCancelled())break;3. 同理,在onProgressUpdate()方法中也做類似的處理:if(isCancelled())return;通過如上操作,我們就能快速停止當前線程,將處理權交給下一個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 @Override17 protected void onPause() {18 // TODO Auto-generated method stub19 super.onPause();20 if (task!=null&&task.getStatus()==AsyncTask.Status.RUNNING) {21 task.cancel(true);//cancel()只是將對應的task標記為cancel狀態,並不是真正取消線程執行22 }23 }24 25 class MyAsycnTask2 extends AsyncTask<Void, Integer, Void> {26 27 @Override28 protected void onProgressUpdate(Integer... values) {29 // TODO Auto-generated method stub30 // 擷取進度更新值31 super.onProgressUpdate(values);32 if (isCancelled()) {33 return;34 }35 progressBar.setProgress(values[0]);36 }37 38 @Override39 protected Void doInBackground(Void... params) {40 // TODO Auto-generated method stub41 42 // 類比進度更新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 block52 e.printStackTrace();53 }54 }55 return null;56 }57 }58 }
Android攻城獅AsyncTask