Android:UI更新方法五:利用AsyncTask更新UI
来源:互联网 发布:网络电视不清楚怎么办 编辑:程序博客网 时间:2024/05/20 07:50
关于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;@Overrideprotected 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(){@Overridepublic void onClick(View arg0){// 必须在UI线程创建实例和调用executenew 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 blocke.printStackTrace();}return url.hashCode();// 随便返回的值}}private class DownloadFileTask extends AsyncTask<String, Integer, Long>{// 在UI线程执行@Overrideprotected void onPreExecute(){// 第一个执行方法Log.i(TAG, "onPreExecute");mTextView.setText("Starting...");super.onPreExecute();}// 在工作线程执行@Overrideprotected 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 calledif (isCancelled()){break;}}return totalSize;}// 在UI线程执行@Overrideprotected 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线程执行@Overrideprotected void onPostExecute(Long result){// doInBackground返回时触发,// 这里的result就是上面doInBackground执行后的返回值Log.i(TAG, "onPostExecute");Log.i(TAG, "result:" + result);mTextView.setText("Downloaded " + result + " bytes");// setProgress(10000-1);//如果不想进度条消失,可以设置9999setProgress(10000);// 设置为10000进度条将自动消失super.onPostExecute(result);}}}
Logcat:
01-12 09:06:05.661: I/MainActivity(868): onPreExecute01-12 09:06:05.681: I/MainActivity(868): doInBackground01-12 09:06:05.681: I/MainActivity(868): url:http://avatar.csdn.net/F/4/B/1_annkie.jpg01-12 09:06:06.726: I/MainActivity(868): publishProgress01-12 09:06:06.726: I/MainActivity(868): url:http://static.blog.csdn.net/images/medal/holdon_s.gif01-12 09:06:06.726: I/MainActivity(868): onProgressUpdate01-12 09:06:06.731: I/MainActivity(868): progress:001-12 09:06:07.737: I/MainActivity(868): publishProgress01-12 09:06:07.737: I/MainActivity(868): url:http://avatar.csdn.net/F/4/B/1_annkie.jpg01-12 09:06:07.737: I/MainActivity(868): onProgressUpdate01-12 09:06:07.737: I/MainActivity(868): progress:1601-12 09:06:08.792: I/MainActivity(868): publishProgress01-12 09:06:08.792: I/MainActivity(868): url:http://static.blog.csdn.net/images/medal/holdon_s.gif01-12 09:06:08.792: I/MainActivity(868): onProgressUpdate01-12 09:06:08.792: I/MainActivity(868): progress:3301-12 09:06:09.795: I/MainActivity(868): publishProgress01-12 09:06:09.795: I/MainActivity(868): url:http://avatar.csdn.net/F/4/B/1_annkie.jpg01-12 09:06:09.795: I/MainActivity(868): onProgressUpdate01-12 09:06:09.795: I/MainActivity(868): progress:5001-12 09:06:10.860: I/MainActivity(868): onProgressUpdate01-12 09:06:10.860: I/MainActivity(868): progress:6601-12 09:06:10.881: I/MainActivity(868): publishProgress01-12 09:06:10.881: I/MainActivity(868): url:http://static.blog.csdn.net/images/medal/holdon_s.gif01-12 09:06:11.924: I/MainActivity(868): onProgressUpdate01-12 09:06:11.924: I/MainActivity(868): progress:8301-12 09:06:11.943: I/MainActivity(868): publishProgress01-12 09:06:11.952: I/MainActivity(868): onPostExecute01-12 09:06:11.952: I/MainActivity(868): result:8475395646
- Android:UI更新方法五:利用AsyncTask更新UI
- Android 异步更新UI----AsyncTask
- Android 异步更新UI----AsyncTask
- Android 异步更新UI----AsyncTask
- AsyncTask更新UI
- android AsyncTask介绍 异步更新UI
- Android AsyncTask(异步耗时 更新UI)
- Android更新UI的方法
- android更新UI的方法
- Android更新ui的方法
- 总结五种更新UI的方法
- Android更新UI的五种方式
- Android更新UI的五种解决方案
- 利用Handler来更新android的UI
- 利用Handler来更新android的UI
- 利用Handler来更新android的UI
- 利用Handler来更新android的UI
- 利用Handler来更新android的UI
- CountDownLatch和CyclicBarrier的简单应用1
- 轉換 Ext.data.record 為 json 格式
- oracle ORA-01000:maximum open cursors exceeded
- Servlet与struts的Action的关系
- java基础---->泛型
- Android:UI更新方法五:利用AsyncTask更新UI
- struts action-mapping中的input的作用
- C#锁定EXCEL工作表
- struts笔记
- 今天是13年的第一个周末
- 运用加密技术保护Java源代码
- Java的ThreadPoolExecutor(二)
- Linux/MIPS启动分析
- 系统区域为非中文(比如英文)的情况下,执行MultiByteToWideChar失败