編輯:關於android開發
安卓異步任務 ---AsyncTask
為什麼要異步任務:
1.Android單線程模型
2.耗時操作放在非主線程中執行
AsyncTask為何而生
1.子線程中更新UI
2.封裝,簡化異步操作
構造AsyncTask子類的參數
AsyncTask
Params: 啟動任務時輸入的參數的類型,也就是execute()方法中,傳入的參數
Progress: 後台任務執行中返回進度值的類型,進度更新時用到
Result 後台執行任務完成後返回結果的類型,如果後台是從網絡上獲取一張圖片,那麼就返回Bitmap類型
構建AsyncTask子類的回調方法
(插入知識:什麼是回調函數)你到一個商店買東西,剛好你要的東西沒有貨,於是你在店員那裡留下了你的電話,過了幾天店裡有貨了,店員就打了你的電話,然後你接到電話後就到店裡去取了貨。在這個例子裡,你的電話號碼就叫回調函數,你把電話留給店員就叫登記回調函數,店裡後來有貨了叫做觸發了回調關聯的事件,店員給你打電話叫做調用回調函數,你到店裡去取貨叫做響應回調事件。(轉自知乎作者:常溪玲)
doInBackground 必須重寫,異步執行後台線程將要完成的任務
onPreExecute 執行後台耗時操作前被調用,通常用戶完成一些初始化操作
onPostExecute 當doInBackground()完成後,系統會自動調用,並將doInBackground方法返回的值傳給該方法。
onProgressUpdate 在doInBackground()方法中調用publishProgress()方法更新任務的執行進度後,就會觸發該方法。可以很清楚的了解耗時操作的完成進度
函數執行順序演示代碼:
MyAsynTask.java
package com.example.app; import android.os.AsyncTask; import android.util.Log; public class MyAsynTask extends AsyncTask{ @Override protected Void doInBackground(Void... arg0) { // TODO Auto-generated method stub Log.d("sr", "doInBackground"); publishProgress(); return null; } @Override protected void onPostExecute(Void result) { // TODO Auto-generated method stub super.onPostExecute(result); Log.d("sr", "onPostExecute"); } @Override protected void onPreExecute() { // TODO Auto-generated method stub super.onPreExecute(); Log.d("sr", "onPreExecute"); } @Override protected void onProgressUpdate(Void... values) { // TODO Auto-generated method stub super.onProgressUpdate(values); Log.d("sr", "onProgressUpdate"); } }
package com.example.app; import android.os.Bundle; import android.app.Activity; import android.app.TaskStackBuilder; import android.view.Menu; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); MyAsynTask task = new MyAsynTask(); task.execute(); } }
輸出結果:
下面是實例演示(加載一張網絡圖片):
異步線程:下載圖像
UI線程:設置圖像
還是在原來的工程中:
新建ImageTest.java類,繼承Activity,創建OnCreate()方法。新建布局文件image.xml,裡面有一個imageView顯示圖片 和一個進度條
image.xml
package com.example.app; import android.app.Activity; import android.os.Bundle; import android.widget.ImageView; import android.widget.ProgressBar; public class ImageTest extends Activity { private ImageView mImageView; private ProgressBar mProgressBar; private static String URL = "http://image.zhaiba.com/2015/7/1/201507011732462088603781.jpg";//網路圖片地址 @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.image); mImageView = (ImageView) findViewById(R.id.image); mProgressBar = (ProgressBar)findViewById(R.id.progressbar); } }
接下來創建AsynTask異步處理
在ImageTest.java中創建內部類MyAsyncTask 繼承AsyncTask
ImageTest.java
package com.example.app; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.AsyncTask; import android.os.Bundle; import android.view.View; import android.widget.ImageView; import android.widget.ProgressBar; public class ImageTest extends Activity { private ImageView mImageView; private ProgressBar mProgressBar; private static String URL = "http://image.zhaiba.com/2015/7/1/201507011732462088603781.jpg";//網路圖片地址 @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.image); mImageView = (ImageView) findViewById(R.id.image); mProgressBar = (ProgressBar)findViewById(R.id.progressbar); //設置傳遞進去的參數 new MyAsyncTask().execute(URL);//可以傳入一個,或多個參數 } class MyAsyncTask extends AsyncTask配置AndroidManifest增加網絡權限,聲明activity//第一個參數傳入URL,所以是String,第二個參數不需要返回加載的進度,所以設置為Void,第三個值為返回值類型,這裡是圖片,所以設置為Bitmap { @Override protected void onPreExecute() { // TODO Auto-generated method stub super.onPreExecute(); //將隱藏的進度條顯示出來,提示用戶等待 mProgressBar.setVisibility(View.VISIBLE);//顯示進度條 } @Override protected void onPostExecute(Bitmap result) { // TODO Auto-generated method stub super.onPostExecute(result); //操作UI 設置圖像 mProgressBar.setVisibility(View.GONE); mImageView.setImageBitmap(result); } @Override protected Bitmap doInBackground(String... params) {//參數為不定長的數組,這是從execute()方法中傳入的參數 // TODO Auto-generated method stub //獲取傳遞進來的參數 String url = params[0];//上面execute方法中傳入的參數第一個參數為URL Bitmap bitmap = null; URLConnection connection; InputStream is; try { connection = new URL(url).openConnection(); is = connection.getInputStream();//獲取輸入流 BufferedInputStream bis = new BufferedInputStream(is); //通過decodeStream方法解析輸入流 bitmap = BitmapFactory.decodeStream(bis);//將輸入流解析為圖像 is.close(); bis.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } //將bitmap作為返回值返回後面調用的方法 return bitmap;//返回圖像 } } }
在主頁上添加一個按鈕,點擊,進入ImageTest那個activity
Activity_main.xml
MainActivity.java
package com.example.app; import android.os.Bundle; import android.app.Activity; import android.app.TaskStackBuilder; import android.content.Intent; import android.view.Menu; import android.view.View; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); MyAsynTask task = new MyAsynTask(); task.execute(); } public void loadImage(View view) { startActivity(new Intent(this, ImageTest.class)); } }
下面的例子就是模擬進度條的更新。
進度條布局progressbar.xml
package com.example.app; import android.app.Activity; import android.os.AsyncTask; import android.os.Bundle; import android.widget.ProgressBar; public class ProgressBarTest extends Activity { private ProgressBar mProgressBar; private MyAsyncTask mTask; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.progressbar); mProgressBar = (ProgressBar)findViewById(R.id.pg); mTask = new MyAsyncTask(); mTask.execute(); } class MyAsyncTask extends AsyncTask//第二個參數因為要實時的返回進度條的狀態,所以要Integer參數 { @Override protected Void doInBackground(Void... arg0) { // TODO Auto-generated method stub //模擬進度更新 for(int i = 0; i < 100; i ++){ publishProgress(i); //去調用下面那個onProgressUpdate方法 try { Thread.sleep(300); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return null; } @Override protected void onProgressUpdate(Integer... values) { // TODO Auto-generated method stub super.onProgressUpdate(values); //獲取進度更新值 mProgressBar.setProgress(values[0]);//當前進度值 } } }
為主頁添加一個測試進度條按鈕,設置點擊方法後,運行:
可以看到進度條在動態的更新
但是這樣存在一個問題,返回後重新加載,再返回後重新加載,發現進度條不發生變化,因為每次返回加載都啟動了一個異步任務,當前需要加載時有可能上次的任務還沒有執行完,所以當前的進度條不更新。
把任務的生命周期設置為activity一樣
在ProgressBarTest.java 中重寫onPause()方法
@Override protected void onPause() { // TODO Auto-generated method stub super.onPause(); if(mTask != null && mTask.getStatus() == AsyncTask.Status.RUNNING){//任務不為空切正在運行 mTask.cancel(true); //cancel方法只是將對應的AsyncTask標記為cancel狀態,並不是真正的取消線程的執行 } }
將當前任務設置為cancel狀態,然後在doInBackground方法和onProgressUpdate方法中中判斷一下
protected Void doInBackground(Void... arg0) { // TODO Auto-generated method stub //模擬進度更新 for(int i = 0; i < 100; i ++){ if(isCancelled()) break; publishProgress(i); //去調用下面那個onProgressUpdate方法 try { Thread.sleep(300); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return null; } @Override protected void onProgressUpdate(Integer... values) { // TODO Auto-generated method stub super.onProgressUpdate(values); if(isCancelled()) return ; //獲取進度更新值 mProgressBar.setProgress(values[0]);//當前進度值 }
使用AsyncTask注意事項
必須在UI線程中創建AsyncTask的實例
必須在UI線程中調用AsyncTask的execute()方法
重寫的四個方法時系統調用的,不能手動調用
每個AsyncTask只能被調用(execute())一次,多次調用將會引發異常(它的四個方法只有doInBackground是異步處理,不能直接更新UI,其他三個方法可以更新UI。
源代碼下載:AsyncTask加載網路圖片,模擬進度條的更新
附上網友寫的一篇筆記:http://www.cnblogs.com/caobotao/p/5020857.html
Android如何自學----轉自lavor從segmentfault,如何自學Android 1. Java知識儲備 本知識點不做重點講解: 對於有基礎的
讓ImageView可以使用gif的方法,imageviewgif在自己的包中添加MyGifView.java(直接復制,粘貼),讀取gif資源在MyGifView中第2
FFmpeg使用手冊 - MP4的格式解析視頻文件轉MP4在互聯網中常見的格式中,跨平台最好的,應該是MP4文件,因為MP4文件既可以在PC平台的Flashplayer中
linux2.4.18----25.文件系統的構建一. 文件系統的構建1.busybox的編譯方法: 用虛擬機的redhat9.0進行編譯版本: busybox-1.00
Android動畫效果生動有趣的通知NiftyNotification(