Android:UI更新方法五:利用AsyncTask更新UI
關於AsyncTask的用法:
主要翻譯自:http://developer.android.com/reference/android/os/AsyncTask.html
3個範型引數:
Params
啟動任務執行的輸入引數
Progress
後臺任務執行的百分比
Result
,後臺計算的結果型別
在一個非同步任務裡,不是所有的型別總被用。假如一個型別不被使用,可以簡單地使用Void型別:
private class MyTask extends AsyncTask<Void,Void,Void> {... }
4個重寫介面:
onPreExecute
:
執行在
UI
執行緒。
初始化task,比如顯示一個進度條。
doInBackground
,:
執行在後臺執行緒。
主要用來進行邏輯處理。時間可以較長,可以避免在UI執行緒ANR。耗時操作在這個方法中進行。
在onPreExecute
之
後立刻執行。Execute的引數傳入到這個介面。
正常情況,計算結果將被返回給onPostExecute
。如果 cancel(boolean)
呼叫,則返回結果給
onCancelled(Object)
在這個步驟也可以publishProgress(Progress...)釋出進度結果到UI執行緒,由onProgressUpdate(Progress...)
來處理。
onProgressUpdate
:
執行在
UI
執行緒。
呼叫publishProgress(Progress...)之後執行。這部分主要用來與使用者互動,比如顯示進度百分比給使用者。
onPostExecute
.
執行在
UI
執行緒。
doInBackground
執行完以後將結果返回給這個介面。
AsyncTask是個抽象類,必須子類化才能使用。
至少重寫一個方法:doInBackground(Params...),大多數時候也會重寫:onPostExecute(Result)
為了儘快知道Cancel的結果,可以在 doInBackground(Object[])
中測試
isCancelled()。
protected abstract Result doInBackground(Params... params);//抽象方法必須實現
執行緒規則
有一些執行緒規則必須去遵守,這個類才會正確的工作:
· AsyncTask類必須在UI執行緒載入。在JELLY_BEAN 中將自動完成這步。
·任務例項必須建立在 UI執行緒 。
· execute(Params...)必須在 UI執行緒上呼叫
· 不要手動呼叫onPreExecute(),onPostExecute(Result),doInBackground(Params...),onProgressUpdate(Progress...)
· 這個任務只執行一次(如果執行第二次將會丟擲異常)
使用限制:
1. 多工併發時可能存在問題
由於AsyncTask被設計成最大10個工作佇列(static),如果同時需要下載超過10個小圖片,就可能導致工作佇列溢位(建立超過10個例項)。
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(10);
從 HONEYCOMB
開始
,任務被設計成單執行緒,以避免複雜的並行處理產生的問題。
解決方法:
自己使用執行緒池來實現(ThreadPoolExecutor ),並設定一個較大的工作佇列。如果需要一個可變的佇列,可以使用LinkedBlockingQueue 。
2. AsyncTask將導致Activity無法重建自己,即使設定onRetainNonConfigurationState引數。
如果是自己建立的執行緒,則可以。不過,如果自己建立執行緒,一旦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,如 Executor
, ThreadPoolExecutor
and FutureTask
.
長時間的背景操作一般使用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
相關文章
- Cube-UI 最近做的更新UI
- React UI 庫: React Suite 3.8.0 版本更新ReactUI
- Flutter 熱更新及動態UI生成FlutterUI
- WPF頻繁更新UI卡頓問題UI
- 如何在子執行緒中更新UI執行緒UI
- 為何要在主執行緒上更新UI執行緒UI
- IntelliJ IDEA 2023 mac主要更新了什麼?IntelliJ IDEA 新版 UI 更新盤點IntelliJIdeaMacUI
- android ios UIAndroidiOSUI
- winform中更新UI控制元件的方案介紹ORMUI控制元件
- Flutter 資料監聽Widget 自動更新你的UIFlutterUI
- Element-ui(更新中表單最詳細的解釋)UI
- Salesforce Integration 概覽(六) UI Update Based on Data Changes(UI自動更新基於資料變更)SalesforceUI
- 聊一聊 React 中更新 ui 檢視的幾種方式ReactUI
- 【更新】Kendo UI for jQuery釋出R2 2018|附下載UIjQuery
- 檢視更新科技釋出 View UI 元件庫(即 iView 4.0),超過50項更新ViewUI元件
- Android效能UI卡頓AndroidUI
- Android 自定義UI元件AndroidUI元件
- android sdk更新代理。Android
- Android AsyncTask 詳解Android
- Android UI——SpannableString詳細解析AndroidUI
- Android通用UI元件之DialogAndroidUI元件
- Android UI 驗收好幫手AndroidUI
- [譯]Flutter for Android Developers - Async UIFlutterAndroidDeveloperUI
- 用廣播 BroadcastReceiver 更新 UI 介面真的好嗎?全方位解析廣播ASTUI
- 使用更新補丁對Android Studio進行更新。Android
- 整裝待發 QTA UI自動化測試框架迎來大更新QTUI框架
- Android UI 測試指南之 EspressoAndroidUIEspresso
- Android UI繪製流程及原理AndroidUI
- 利用SkyWalking UI的api介面學習GraphQLUIAPI
- Android UI 顯示原理分析小結AndroidUI
- Android熱更新實現方式Android
- Android P 安全性更新Android
- SAP UI5 sap.ui.Device.media 公有方法介紹UIdev
- AngularJS學習日記(五)UI-RouteAngularJSUI
- 五個Svelte UI介面庫包推薦UI
- 利用Swagger UI介面文件同步本地Mock資料SwaggerUIMock
- 有效解決Android SDK Manager無法更新下載的方法Android
- Ubantu 更新時間方法
- Android API相容,其他API,UI適配(2)AndroidAPIUI