AsyncTask的用法及注意点
来源:互联网 发布:南阳网络推广哪家好 编辑:程序博客网 时间:2024/06/05 01:09
AsyncTask是什么
AsyncTask
是用来让我们在UI线程中调用以进行一些异步任务的类,通常要求这个异步任务的持续时间很短,最多持续几秒钟,在完成后台任务时,会将结果通知到主线程进行处理。
说的更本质一些,AsyncTask
=Thread
+Handler
,Thread
用来进行后台任务,Handler
用于处理UI线程的消息,例如任务完成后更新视图操作等。
AsyncTask类从apiLevel=3开始才有。
AsyncTask基本用法
Step 1
实现一个自己的类继承自:class AsyncTask<Params, Progress, Result>
三个泛型分别表示:
Params
:表示执行任务的参数,可以传入多个Progress
:包含耗时操作的进度信息,用于界面的显示更新Result
:耗时任务的执行结果
对于不需要的内容可以使用Void
类型。
Step 2
实现其中的抽象方法:protected abstract Result doInBackground(Params... params)
方法,该方法中就是我们需要进行的耗时任务,如网络查询操作等,然后将操作的结果进行返回。
该方法可以理解为Thread
类中的run
方法。
Step 3
Step 2执行完成后,AsyncTask
将会调用protected void onPostExecute(Result result)
方法,参数就是我们返回的Result,该方法在UI线程中执行,用于更新界面显示,不强制要求实现。
Step 4
实例化我们自定义的任务类,并执行。
MyAsyncTask task = new MyAsyncTask();task.execute(param1, param2, ...);
通过以上代码可以实现我们的需求,但是有一点不好的是,调用execute
方法在不同的Android版本上的表现不太一样:
switch(apiLevel) apiLevel = 3 : 单线程执行 apiLevel > 3 and apiLevel < 11 : 多线程执行 apiLevel >= 11 : 单线程执行
所以应该尽量避免这种有歧义的代码,在执行时我们需要指定任务的执行方式,单线程和多线程的执行代码示例如下(apiLevel>=11):
task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, param1, param2, ...);task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, param1, param2, ...);
这里的单线程表示在当前APP进程中,所有的异步任务都将串行执行,即执行完一个再执行后一个,而多线程就是指我们可以同时运行多个异步任务的后台操作。大家都知道多线程的好处就是可以提高运行效率,但是却也带来了同步的问题,因此这两种方法都有存在的必要。
变长参数列表param1, param2, ...
在调用时没有需求可以不写,其本质就是一个数组。
PS
完整的一次异步任务中方法的执行顺序是:
1. onPreExecute
:UI线程
2. doInBackground
:子线程
3. onPostExecute
:UI线程
还有一个关于进度显示的方法protected void onProgressUpdate(Progress... values)
,该方法运行在UI线程,可以在任意时机被调用,而何时被调用则是取决于我们调用protected final void publishProgress(Progress... values)
的时机。
我们可以在任意时间,任意线程中publishProgress
,不过在主线程中调用似乎没有什么必要,onPreExecute
表示任务还没开始,此时进度为0,onPostExecute
此时任务已经完成,进度为已满的状态。
AsyncTask用对了吗~?
1. 任务只给执行一次~
我们的每个任务示例只可以被execute一次,如果多次调用被抛出IllegalStateException
异常,因此任务执行完成后请及时赋值null
。
AsyncTask共有3种状态:
PENDING
每个实例构造完成的初始值RUNNING
表示使用者调用了executeOnExecutor或execute,此时会立刻调用onPreExecute方法,但是不会立即执行doInBackground方法FINISHED
表示onPostExecute方法执行完成
在任务执行时需要判断当前Task是否是PENDING
状态,不是的话将抛出异常,每个Task类只可以被执行一次。
2. 不要在子线程中操作主线程中的数据
在子线程中(doInBackground
方法)更新视图应该没人会做,但是却会有很多情况下在子线程中更新视图中的数据。
比较常见的情况是修改ListView
中的数据,例如下面的这种代码:
// doInBackground方法中// TODO 获取数据操作...// mDataList表示ListView加载用到的数据mDataList.removeAll();mDataList.addAll(新获取的数据);
写出这样的代码可能会造成在滑动列表时产生异常:IndexOutOfBoundsException
,而且即使没有抛异常也不代表加载显示的数据正确的。在这种情况下的推荐做法是,将后台进行的耗时操作的结果数据返回(泛型Result
,在本例中可以定义为ArrayList<String>
),并在onPostExecute
方法中对该数据进行展示,保证所有和UI更新的代码都在UI线程中执行。
3. 适当并及时地终止任务
AsyncTask
主要用途就是异步获取数据,并用于页面加载,所以当页面不存在时,就应该适当地终止任务以节约资源。
例如在一个Activity
调用onStart
时,我们需要从服务端获取最新数据用于界面显示,此时我们需要execute一个AsyncTask
,在onPostExecute
方法中我们会写一些关于页面更新的逻辑。
但是当Activity
调用了onStop
方法,此时页面已经变得不可见,我们也并不希望有网络数据返回时再去更新界面显示,因此在此时我们就需要调用AsyncTask
的cancel
方法去取消任务。
如果当前任务还处于运行
RUNNING
状态,调用cancel
方法后将不会执行onPostExecute
方法,并且在doInBackground
方法中也可以通过函数isCancelled
来随时获取当前任务的状态,如果返回true
,我们可以不进行接下来的操作(例如执行多个网络请求,在每个请求执行之前判断来决定是否要继续执行)。
举个栗子
通过一个简单的例子来了解一下AsyncTask
类的具体使用方法:
public class TaskActivity extends Activity { AsyncTask<Void, Integer, ArrayList<String>> mTask; @Override protected void onStart() { super.onStart(); startTask(); } @Override protected void onStop() { super.onStop(); cancelTask(); } // 开始任务 private void startTask() { if (mTask != null) { mTask.cancel(true); } mTask = new MyAsyncTask(); mTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } // 取消任务 private void cancelTask() { if (mTask != null) { mTask.cancel(true); mTask = null; } } /** * 自定义异步任务类 */ private class MyAsyncTask extends AsyncTask<Void, Integer, ArrayList<String>> { @Override protected void onPreExecute() { // TODO 在这里可以加载LoadingView提示用户 } @Override protected ArrayList<String> doInBackground(Void... voids) { // TODO 在这里执行耗时的操作,如网络请求,大量的计算等等 ArrayList<String> result = new ArrayList<String>(); for (int i = 0; i < 100; i++) { try { Thread.sleep(100); publishProgress(i); result.add("" + i); } catch (InterruptedException e) { e.printStackTrace(); } } return result; } @Override protected void onPostExecute(ArrayList<String> result) { mTask = null; // TODO 在这里进行相应的界面更新逻辑 // 例如将result加载到ListView中进行显示 } @Override protected void onProgressUpdate(Integer... progress) { // TODO 将进度更新到界面,本例用用整数表示百分比 } }}
以上的代码实现了一个自定义的异步任务类MyAsyncTask
,该类的主要功能是每隔100ms更新一下进度,最后将所有的进度值加到链表中作为耗时操作的执行结果返回,用于界面显示,是不是很简单呢~!
- AsyncTask的用法及注意点
- setTimeout的用法及注意点
- group_concat的用法 及注意点
- java this的用法及注意点
- AsyncTask使用注意点
- 数组,ArrayList,HashSet的用法及注意点。
- strcpy的用法、c语言实现、及注意点
- double及long float(lf)的用法注意点:
- 关于br和p的用法及注意点
- PHP static关键字的用法及注意点
- Android SharedPreferences用法及注意点详解
- sizeof() 的用法以及注意点
- s:select的用法以及注意点
- swich 的一些用法,注意点
- spark rdd checkpoint的用法注意点
- spark rdd checkpoint的用法注意点
- ArrayList 的用法和注意点
- z-index的用法和注意点
- oracle数据库 视图相关的语句
- 1036. 跟奥巴马一起编程(15)
- python基础(一)
- mariadb数据库入门
- Spring Boot JPA 连接数据库
- AsyncTask的用法及注意点
- 【C++】指针1
- Spring Boot MyBatis 连接数据库
- PHP内存优化生成无限极分类(生成树结构)
- 团队管理随想之项目外包
- 1038. 统计同成绩学生(20)
- Spring Boot 多数据源
- python 多进程模块 multiprocessing
- Spring Boot Shiro 权限管理