Android:UI更新方法五:利用AsyncTask更新UI
關於AsyncTask的用法:
3個範型引數:
Params
啟動任務執行的輸入引數
Progress
後臺任務執行的百分比
Result
,後臺計算的結果型別
在一個非同步任務裡,不是所有的型別總被用。假如一個型別不被使用,可以簡單地使用Void型別:
private class MyTask extends AsyncTask<Void,Void,Void> {... }
4個重寫介面:
onPreExecute
:
執行在
UI
執行緒。
初始化task,比如顯示一個進度條。
doInBackground
,:
執行在後臺執行緒。
主要用來進行邏輯處理。時間可以較長,可以避免在
在onPreExecute
之
後立刻執行。Execute的引數傳入到這個介面。
onProgressUpdate
:
執行在
UI
執行緒。
onPostExecute
.
執行在
UI
執行緒。
doInBackground
執行完以後將結果返回給這個介面。
AsyncTask是個抽象類,必須子類化才能使用。
protected abstract Result doInBackground(Params... params);//抽象方法必須實現
執行緒規則
有一些執行緒規則必須去遵守,這個類才會正確的工作:
· AsyncTask類必須在UI執行緒載入。
·任務例項必須建立在 UI執行緒 。
· 這個任務只執行一次(如果執行第二次將會丟擲異常)
使用限制:
1. 多工併發時可能存在問題
由於AsyncTask被設計成最大10個工作佇列(static),如果同時需要下載超過10個小圖片,就可能導致工作佇列溢位(建立超過10個例項)。
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(10);
從
開始
,任務被設計成單執行緒,以避免複雜的並行處理產生的問題。
解決方法:
如果是自己建立的執行緒,則可以。不過,如果自己建立執行緒,一旦Activity finish時就需要及時釋放。
3. 無法改變後臺執行緒的優先順序,因為設計是已經寫死。
4. 異常也無法很好的支援。
5. 執行緒池設計:5個核心執行緒和最大能支援128個執行緒,一旦超過5個執行緒存在,並空閒超過一定時間,空閒執行緒將被殺死。
private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
6. AsyncTask設計對於短時間(幾秒)的後臺操作表現優秀,但是如果是長時間的操作,則推薦使用java.util.concurrent
的API,如, and .
長時間的背景操作一般使用Service+Thread來實現,加上執行緒池,實現多執行緒的操作。
程式碼示例:
Activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:background="#ff999999"
android:text="@string/hello_world" />
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
</LinearLayout>
MainActivity.java
package com.example.updateui;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity
{
private static final String TAG = MainActivity.class.getSimpleName();
private static final int REFRESH_ACTION = 1;
private Button mButton;
private TextView mTextView;
private int mCount = 0;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// 在標題欄顯示進度條
requestWindowFeature(Window.FEATURE_PROGRESS);
setContentView(R.layout.activity_main);
final String[] urls = { "http://avatar.csdn.net/F/4/B/1_annkie.jpg",
"http://static.blog.csdn.net/images/medal/holdon_s.gif",
"http://avatar.csdn.net/F/4/B/1_annkie.jpg",
"http://static.blog.csdn.net/images/medal/holdon_s.gif",
"http://avatar.csdn.net/F/4/B/1_annkie.jpg",
"http://static.blog.csdn.net/images/medal/holdon_s.gif" };
mTextView = (TextView) findViewById(R.id.textView1);
mTextView.setText("Click Button to start");
mButton = (Button) findViewById(R.id.button1);
mButton.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View arg0)
{
// 必須在UI執行緒建立例項和呼叫execute
new DownloadFileTask().execute(urls);
}
});
}
// 模擬下載程式碼
static class Downloader
{
static long downloadFile(String url)
{
Log.i(TAG, "url:" + url);
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return url.hashCode();// 隨便返回的值
}
}
private class DownloadFileTask extends AsyncTask<String, Integer, Long>
{
// 在UI執行緒執行
@Override
protected void onPreExecute()
{
// 第一個執行方法
Log.i(TAG, "onPreExecute");
mTextView.setText("Starting...");
super.onPreExecute();
}
// 在工作執行緒執行
@Override
protected Long doInBackground(String... urls)
{
// 第二個執行方法,onPreExecute()執行完後執行
Log.i(TAG, "doInBackground");
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++)
{
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));// 更新進度條
Log.i(TAG, "publishProgress");
// Escape early if cancel() is called
if (isCancelled())
{
break;
}
}
return totalSize;
}
// 在UI執行緒執行
@Override
protected void onProgressUpdate(Integer... progress)
{
// 這個函式在doInBackground呼叫publishProgress時觸發,雖然呼叫時只有一個引數
// 但是這裡取到的是一個數組,所以要用progress[0]來取值
// 第n個引數就用progress[n]來取值
Log.i(TAG, "onProgressUpdate");
Log.i(TAG, "progress:" + progress[0]);
// 重新整理UI介面
mTextView.setText("Percent:" + progress[0] + "/100");
setProgress(progress[0] * 100);
super.onProgressUpdate(progress);
}
// 在UI執行緒執行
@Override
protected void onPostExecute(Long result)
{
// doInBackground返回時觸發,
// 這裡的result就是上面doInBackground執行後的返回值
Log.i(TAG, "onPostExecute");
Log.i(TAG, "result:" + result);
mTextView.setText("Downloaded " + result + " bytes");
// setProgress(10000-1);//如果不想進度條消失,可以設定9999
setProgress(10000);// 設定為10000進度條將自動消失
super.onPostExecute(result);
}
}
}
Logcat:
01-12 09:06:05.661: I/MainActivity(868): onPreExecute
01-12 09:06:05.681: I/MainActivity(868): doInBackground
01-12 09:06:05.681: I/MainActivity(868): url:http://avatar.csdn.net/F/4/B/1_annkie.jpg
01-12 09:06:06.726: I/MainActivity(868): publishProgress
01-12 09:06:06.726: I/MainActivity(868): url:http://static.blog.csdn.net/images/medal/holdon_s.gif
01-12 09:06:06.726: I/MainActivity(868): onProgressUpdate
01-12 09:06:06.731: I/MainActivity(868): progress:0
01-12 09:06:07.737: I/MainActivity(868): publishProgress
01-12 09:06:07.737: I/MainActivity(868): url:http://avatar.csdn.net/F/4/B/1_annkie.jpg
01-12 09:06:07.737: I/MainActivity(868): onProgressUpdate
01-12 09:06:07.737: I/MainActivity(868): progress:16
01-12 09:06:08.792: I/MainActivity(868): publishProgress
01-12 09:06:08.792: I/MainActivity(868): url:http://static.blog.csdn.net/images/medal/holdon_s.gif
01-12 09:06:08.792: I/MainActivity(868): onProgressUpdate
01-12 09:06:08.792: I/MainActivity(868): progress:33
01-12 09:06:09.795: I/MainActivity(868): publishProgress
01-12 09:06:09.795: I/MainActivity(868): url:http://avatar.csdn.net/F/4/B/1_annkie.jpg
01-12 09:06:09.795: I/MainActivity(868): onProgressUpdate
01-12 09:06:09.795: I/MainActivity(868): progress:50
01-12 09:06:10.860: I/MainActivity(868): onProgressUpdate
01-12 09:06:10.860: I/MainActivity(868): progress:66
01-12 09:06:10.881: I/MainActivity(868): publishProgress
01-12 09:06:10.881: I/MainActivity(868): url:http://static.blog.csdn.net/images/medal/holdon_s.gif
01-12 09:06:11.924: I/MainActivity(868): onProgressUpdate
01-12 09:06:11.924: I/MainActivity(868): progress:83
01-12 09:06:11.943: I/MainActivity(868): publishProgress
01-12 09:06:11.952: I/MainActivity(868): onPostExecute
01-12 09:06:11.952: I/MainActivity(868): result:8475395646