AsyncTask与Thread+Handler的分析"/>
Android AsyncTask与Thread+Handler的分析
Android AsyncTask与Thread+Handler的分析
基本概念
public abstract class AsyncTask
extends Object
java.lang.Object | |
---|---|
↳ | android.os.AsyncTask<Params, Progress, Result> |
通过AsyncTask,可以正确,轻松地使用UI线程。 此类允许您执行后台操作并在UI线程上发布结果,无需操纵threads and/or handlers。
AsyncTask被设计为围绕Thread和Handler的帮助类(其实就是对Thread和Handler的一种封装),并且不构成通用的线程框架。 理想情况下,应将AsyncTasks用于较短的操作(最多几秒钟)。如果需要使线程长时间运行,则强烈建议您使用java.util.concurrent包提供的各种API,例如 Executor,ThreadPoolExecutor和FutureTask。
异步任务由在后台线程上运行的计算定义,并且其结果发布在UI线程上。 异步任务由3个通用类型(Params,Progress和Result)以及4个步骤(四个按顺序执行的方法)(onPreExecute,doInBackground,onProgressUpdate和onPostExecute)。
用法
必须将AsyncTask子类化才能使用。 子类将覆盖至少一个方法(doInBackground(Params …)),并且通常将覆盖第二个方法(onPostExecute(Result)。)
示例如下:
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {protected Long doInBackground(URL... urls) {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));// Escape early if cancel() is calledif (isCancelled()) break;}return totalSize;}protected void onProgressUpdate(Integer... progress) {setProgressPercent(progress[0]);}protected void onPostExecute(Long result) {showDialog("Downloaded " + result + " bytes");}}
创建实例与运行:
new DownloadFilesTask().execute(url1, url2, url3);
通用参数解释
一个异步任务(AsyncTask)使用的三种通用参数如下:
-
Params
执行时发送给任务的参数类型
-
Progress
后台计算期间的进度单位类型
-
Result
后台计算结果类型
四个步骤(四个实现方法)
当执行异步任务时,该任务将顺序执行四个方法
-
onPreExecute()
在执行任务(异步任务)之前在UI线程上调用。此步骤通常用于设置任务,例如,通过在用户界面中显示进度栏。
-
doInBackground(Params…)
在执行任务之前在UI线程上调用。此步骤通常用于设置任务,例如,通过在用户界面中显示进度栏。
doInBackground(Params …),在onPreExecute()完成执行后立即在后台线程上调用。此步骤用于执行可能需要很长时间的后台计算。异步任务的参数将传递到此步骤。计算结果必须通过此步骤返回,并将传递回最后一步。此步骤还可以使用publishProgress(Progress …)发布一个或多个进度单位。这些值在onProgressUpdate(Progress …)步骤中发布在UI线程上。 -
onProgressUpdate(Progress…)
在调用publishProgress(Progress …)之后在UI线程上调用。执行的时间是不确定的。此方法用于在后台计算仍在执行时在用户界面中显示任何形式的进度。例如,它可用于为进度栏设置动画或在文本字段中显示日志。
-
onPostExecute(Result)
在后台计算完成后在UI线程上调用。后台计算的结果作为参数传递到此方法。
缺陷
Android中提供了AsyncTask作为异步调用,并且Android强制规定如果有耗时操作(例如数据库交互,网络请求等)就必须在子线程中运行以免阻塞UI线程太久导致程序超时关闭同时也加强了用户体验。
但是我在使用AsyncTask的时候用于网络请求与服务器进行数据交互,发现了AsyncTask的缺点:
使用AsyncTask如果在doInBackground方法中调用网络请求但是请求一旦发送不会等请求执行完毕就会继续往下执行onPostExecute这样不能完成我想要的等待网络操作完成后再继续执行下一步。
此时我转用Thread+Handler进行网络交互。
使用方法:
- 在UI线程中写一个继承(extends)Handler的内部类并重写handleMessage方法用于处理子线程返回的数据
// 先写n个Handler处理N个数据
class HomeHandler extends Handler{@Overridepublic void handleMessage(@NonNull Message msg) {Bundle msgBundle;switch (msg.what){case Constant.GET_CRITERIA_MESSAGE:Log.e("msg","GET_CRITERIA_MESSAGE");msgBundle = msg.getData();// 处理返回数据更新UIbreak;case Constant.SAVE_MS_MESSAGE:Log.e("msg","SAVE_MS_MESSAGE");msgBundle = msg.getData();// 处理返回数据更新UIbreak;case Constant.CALCULATE_MESSAGE:Log.e("msg","CALCULATE_MESSAGE");msgBundle = msg.getData();// 处理返回数据更新UIbreak;}}
}
- 创建子线程实现Runnable,需要Handler作为成员函数并且构造函数初始化时务必需要传递handler。在子线程中通过UI线程传过来的Handler在处理完耗时操作后进行消息返回
/*** Date: 2019/10/17* Author:Satsuki* Description:*/
public class GetCriteriaThread implements Runnable {private Handler handler;public GetCriteriaThread() {}public GetCriteriaThread(Handler handler) {this.handler = handler;}@Overridepublic void run() {Log.e("GetCriteriaThread","1");String url = “”;Message message = new Message();Bundle msgBundle = new Bundle();Log.e("url",url);// 把json字符串发回主线程,交给UI线程解决msgBundle.putString("criteriaResponse","网络请求获取的数据");// 设置从什么线程发送的Messagemessage.what = Constant.GET_CRITERIA_MESSAGE;message.setData(msgBundle);handler.sendMessage(message);
// Log.e("criteriaList",criteriaList.toString());}
}
- 在主线程中创建执行
// 初始化Handler必须要在执行任务之前
HomeHandler homeHandler= new HomeHandler()
GetCriteriaThread getCriteriaThread = new GetCriteriaThread(homeHandler);
Thread asyncThread = new Thread(getCriteriaThread);
asyncThread.start();
执行后子线程发送的数据交给UI线程中的Handler处理
更多推荐
Android AsyncTask与Thread+Handler的分析
发布评论