导航:首页 > 操作系统 > androidasynctask使用

androidasynctask使用

发布时间:2023-07-01 14:59:39

android 中的“子线程”解析

Android 中线程可分为 主线程 和 子线程 两类,其中主线程也就是 UI线程 ,它的主要这作用就是运行四大组件、处理界面交互。子线程则主要是处理耗时任务,也是我们要重点分析的。

首先 Java 中的各种线程在 Android 里是通用的,Android 特有的线程形态也是基于 Java 的实现的,所以有必要先简单的了解下 Java 中的线程,本文主要包括以下内容:

在 Java 中要创建子线程可以直接继承 Thread 类,重写 run() 方法:

或者实现 Runnable 接口,然后用Thread执行Runnable,这种方式比较常用:

简单的总结下:

Callable 和 Runnable 类似,都可以用来处理具体的耗时任务逻辑的,但是但具体的差别在哪里呢?看一个小例子:

定义 MyCallable 实现了 Callable 接口,和之前 Runnable 的 run() 方法对比下, call() 方法是有返回值的哦,泛型就是返回值的类型:

一般会通过线程池来执行 Callable (线程池相关内容后边会讲到),执行结果就是一个 Future 对象:

可以看到,通过线程池执行 MyCallable 对象返回了一个 Future 对象,取出执行结果。

Future 是一个接口,从其内部的方法可以看出它提供了取消任务(有坑!!!)、判断任务是否完成、获取任务结果的功能:

Future 接口有一个 FutureTask 实现类,同时 FutureTask 也实现了 Runnable 接口,并提供了两个构造函数:

用 FutureTask 一个参数的构造函数来改造下上边的例子:

FutureTask 内部有一个 done() 方法,代表 Callable 中的任务已经结束,可以用来获取执行结果:

所以 Future + Callable 的组合可以更方便的获取子线程任务的执行结果,更好的控制任务的执行,主要的用法先说这么多了,其实 AsyncTask 内部也是类似的实现!

注意, Future 并不能取消掉运行中的任务,这点在后边的 AsyncTask 解析中有提到。

Java 中线程池的具体的实现类是 ThreadPoolExecutor ,继承了 Executor 接口,这些线程池在 Android 中也是通用的。使用线程池的好处:

常用的构造函数如下:

一个常规线程池可以按照如下方式来实现:

执行任务:

基于 ThreadPoolExecutor ,系统扩展了几类具有新特性的线程池:

线程池可以通过 execute() 、 submit() 方法开始执行任务,主要差别从方法的声明就可以看出,由于 submit() 有返回值,可以方便得到任务的执行结果:

要关闭线程池可以使用如下方法:

IntentService 是 Android 中一种特殊的 Service,可用于执行后台耗时任务,任务结束时会自动停止,由于属于系统的四大组件之一,相比一般线程具有较高的优先级,不容易被杀死。用法和普通 Service 基本一致,只需要在 onHandleIntent() 中处理耗时任务即可:

至于 HandlerThread,它是 IntentService 内部实现的重要部分,细节内容会在 IntentService 源码中说到。

IntentService 首次创建被启动的时候其生命周期方法 onCreate() 会先被调用,所以我们从这个方法开始分析:

这里出现了 HandlerThread 和 ServiceHandler 两个类,先搞明白它们的作用,以便后续的分析。

首先看 HandlerThread 的核心实现:

首先它继承了 Thread 类,可以当做子线程来使用,并在 run() 方法中创建了一个消息循环系统、开启消息循环。

ServiceHandler 是 IntentService 的内部类,继承了 Handler,具体内容后续分析:

现在回过头来看 onCreate() 方法主要是一些初始化的操作, 首先创建了一个 thread 对象,并启动线程,然后用其内部的 Looper 对象 创建一个 mServiceHandler 对象,将子线程的 Looper 和 ServiceHandler 建立了绑定关系,这样就可以使用 mServiceHandler 将消息发送到子线程去处理了。

生命周期方法 onStartCommand() 方法会在 IntentService 每次被启动时调用,一般会这里处理启动 IntentService 传递 Intent 解析携带的数据:

又调用了 start() 方法:

就是用 mServiceHandler 发送了一条包含 startId 和 intent 的消息,消息的发送还是在主线程进行的,接下来消息的接收、处理就是在子线程进行的:

当接收到消息时,通过 onHandleIntent() 方法在子线程处理 intent 对象, onHandleIntent() 方法执行结束后,通过 stopSelf(msg.arg1) 等待所有消息处理完毕后终止服务。

为什么消息的处理是在子线程呢?这里涉及到 Handler 的内部消息机制,简单的说,因为 ServiceHandler 使用的 Looper 对象就是在 HandlerThread 这个子线程类里创建的,并通过 Looper.loop() 开启消息循环,不断从消息队列(单链表)中取出消息,并执行,截取 loop() 的部分源码:

dispatchMessage() 方法间接会调用 handleMessage() 方法,所以最终 onHandleIntent() 就在子线程中划线执行了,即 HandlerThread 的 run() 方法。

这就是 IntentService 实现的核心,通过 HandlerThread + Hanlder 把启动 IntentService 的 Intent 从主线程切换到子线程,实现让 Service 可以处理耗时任务的功能!

AsyncTask 是 Android 中轻量级的异步任务抽象类,它的内部主要由线程池以及 Handler 实现,在线程池中执行耗时任务并把结果通过 Handler 机制中转到主线程以实现UI操作。典型的用法如下:

从 Android3.0 开始,AsyncTask 默认是串行执行的:

如果需要并行执行可以这么做:

AsyncTask 的源码不多,还是比较容易理解的。根据上边的用法,可以从 execute() 方法开始我们的分析:

看到 @MainThread 注解了吗?所以 execute() 方法需要在主线程执行哦!

进而又调用了 executeOnExecutor() :

可以看到,当任务正在执行或者已经完成,如果又被执行会抛出异常!回调方法 onPreExecute() 最先被执行了。

传入的 sDefaultExecutor 参数,是一个自定义的串行线程池对象,所有任务在该线程池中排队执行:

可以看到 SerialExecutor 线程池仅用于任务的排队, THREAD_POOL_EXECUTOR 线程池才是用于执行真正的任务,就是我们线程池部分讲到的 ThreadPoolExecutor :

再回到 executeOnExecutor() 方法中,那么 exec.execute(mFuture) 就是触发线程池开始执行任务的操作了。

那 executeOnExecutor() 方法中的 mWorker 是什么? mFuture 是什么?答案在 AsyncTask 的构造函数中:

原来 mWorker 是一个 Callable 对象, mFuture 是一个 FutureTask 对象,继承了 Runnable 接口。所以 mWorker 的 call() 方法会在 mFuture 的 run() 方法中执行,所以 mWorker 的 call() 方法在线程池得到执行!

同时 doInBackground() 方法就在 call() 中方法,所以我们自定义的耗时任务逻辑得到执行,不就是我们第二部分讲的那一套吗!

doInBackground() 的返回值会传递给 postResult() 方法:

就是通过 Handler 将最终的耗时任务结果从子线程发送到主线程,具体的过程是这样的, getHandler() 得到的就是 AsyncTask 构造函数中初始化的 mHandler , mHander 又是通过 getMainHandler() 赋值的:

可以在看到 sHandler 是一个 InternalHandler 类对象:

所以 getHandler() 就是在得到在主线程创建的 InternalHandler 对象,所以
就可以完成耗时任务结果从子线程到主线程的切换,进而可以进行相关UI操作了。
当消息是 MESSAGE_POST_RESULT 时,代表任务执行完成, finish() 方法被调用:

如果任务没有被取消的话执行 onPostExecute() ,否则执行 onCancelled() 。

如果消息是 MESSAGE_POST_PROGRESS , onProgressUpdate() 方法被执行,根据之前的用法可以 onProgressUpdate() 的执行需要我们手动调用 publishProgress() 方法,就是通过 Handler 来发送进度数据:

进行中的任务如何取消呢?AsyncTask 提供了一个 cancel(boolean mayInterruptIfRunning) ,参数代表是否中断正在执行的线程任务,但是呢并不靠谱, cancel() 的方法注释中有这么一段:

大致意思就是调用 cancel() 方法后, onCancelled(Object) 回调方法会在 doInBackground() 之后被执行而 onPostExecute() 将不会被执行,同时你应该 doInBackground() 回调方法中通过 isCancelled() 来检查任务是否已取消,进而去终止任务的执行!

所以只能自己动手了:

AsyncTask 整体的实现流程就这些了,源码是最好的老师,自己跟着源码走一遍有些问题可能就豁然开朗了!

Ⅱ android中asynctask和thread的区别

Android平台很多应用使用的都是AsyncTask,而并非Thread和Handler去更新UI,这里Android123给大家说下他们到底有什么区别,我们平时应该使用哪种解决方案。从Android 1.5开始系统将AsyncTask引入到android.os包中,过去在很早1.1和1.0 SDK时其实官方将其命名为UserTask,其内部是jdk 1.5开始新增的concurrent库,做过j2ee的网友可能明白并发库效率和强大性,比Java原始的Thread更灵活和强大,但对于轻量级的使用更为占用系统资源。Thread是Java早期为实现多线程而设计的,比较简单不支持concurrent中很多特性在同步和线程池类中需要自己去实现很多的东西,对于分布式应用来说更需要自己写调度代码,而为了Android UI的刷新google引入了Handler和Looper机制,它们均基于消息实现,有事可能消息队列阻塞或其他原因无法准确的使用。 Android开发网推荐大家使用AsyncTask代替Thread+Handler的方式,不仅调用上更为简单,经过实测更可靠一些,Google在Browser中大量使用了异步任务作为处理耗时的I/O操作,比如下载文件、读写数据库等等,它们在本质上都离不开消息,但是 AsyncTask相比Thread加Handler更为可靠,更易于维护,但AsyncTask缺点也是有的比如一旦线程开启即 dobackground方法执行后无法给线程发送消息,仅能通过预先设置好的标记来控制逻辑,当然可以通过线程的挂起等待标志位的改变来通讯,对于某些应用Thread和Handler以及Looper可能更灵活。

Ⅲ 在Android中什么是异步执行

我来给你讲解一下异步的使用吧,
如果你不是开发人员,直接跳到第三,异步的概念 和 同步的区别:
一、在你的Activity中写一个内部类:
private class TestAsyncTask extends AsyncTask<String, Void, Boolean>
{
@Override
protected void onPreExecute()
{
//最先执行的就是这个。
}

@Override
protected Boolean doInBackground(String... params)
{
//这个是在后台执行的东西,就是说,它自动另外开了个线程运行,不影响你现在做的东西。
}

@Override
protected void onPostExecute(Boolean result)
{
if (result)
{
//后台执行的完毕后,它会用Result通知这里,就是执行这里了。
}
else
{
//所以最好判断一下result,写个else,判断后台执行的东西是不是出问题了。
}
}
}

二,在你的onCreate的时候启动这个异步,启动代码如下:
new TestAsyncTask().execute("");

三,异步 和 同步的区别
异步的好处,就是把一些东西,特别是耗时间的东西扔到后台去运行了,doInBackground,程序可以继续做自己的事情,防止程序卡在那里失去响应。
同步执行的话,就是程序会呆板地从头执行到尾,耗时间的东西不执行完,程序不会继续往下走,等待时间长的话,有时候就会造成失去响应了。

我就是搞开发的,呵呵。我的代码你直接贴进去就能用的。打字贴代码辛苦啊~~望采纳。也欢迎追问

Ⅳ android AsyncTask 中的几个方法比如doInBackground 中后面几个参数中间的几个点是什么意思

String... params表示的是可变参数列表,也就是说,这样的方法能够接受的参数个数是可变的,但不论多少,必须都是String类型的。比如
doInBackground("param1","param2","param3") ,或是doInBackground() 。实际上,在处理可变参数列表的时候,Java是转化为数组来处理的,比如前面的例子,doInBackground传进来三个参数,此时params实际上是一个String[3],可以通过params[0]来引用传进来的实参"param1"。当doInBackground()没有提供实参时params就为null。另外,对于可变参数列表的方法,我们可以直接传递一个数组代替,比如doInBackground(new String[]{"param1", "param2", "param3"}),效果和doInBackground("param1","param2","param3")是一样的。

Ⅳ android AsyncTask 怎么返回值给UI线程

可以看下以下几点即可:
1.把AsyncTask单独写成类,不是其他Activity的子类。(这个显然可以,记住,虽然AsyncTask不是某个Activity的子类,它依然只能在主线程中创建,其四大方法中的三个依然运行在主线程中,详情见后面。)2.UI线程 通过AsyncTask和服务器交互,需要根据结果 打开不同的新的activity,可以onPostExecute() 中返回值给主线程吗?(这个问句就是错的,onPostExecute()就是在主线程中执行的,不需要返回值给主线程,只需要在此方法中将结果存储在某个变量中,就可以在主线程中获取此值。例如,在AsyncTask中增加一个getResult方法)3.另外一个问题, 可以传参数给AsyncTask,然后在onPostExecute 使用其他activity的 finish() 吗?(Yes of course。这句问话依然来自你对onPostExecute 的误解,再说一次,它就在主线程中执行。而Activity的finish方法在主线程中调用显然没问题。)简单说AsyncTask,正好把上一个回答的部分结果拷贝过来给参考:
AsyncTask是一个辅助类,就是为了将Handler、Thread等封装为一个异步执行框架,供Android Coder可以方便的使用。其主要目的是为了“在其他线程中执行一个耗时操作,并随时报告执行进度给UI线程,执行完成后将结果报告给UI线程”。
AsyncTask的使用方法其实Android developer中已经说得非常清楚了,因此择重点翻译一次:
AsyncTask使用时必须作为基类被扩展,子类至少重载一个方法doInBackground,另一个方法onPostExecute也经常被重载,代码例子如下:
6private 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 called
if (isCancelled()) break;
}
return totalSize;
}

protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}

protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}

AsyncTask含有三个泛型参数: Params, 异步任务执行所需的参数类型; Progress, 异步任务执行进度的类型; Result, 异步任务执行结果的类型。 这三个参数不必全部使用,不使用的参数置为Void即可,例如:
private class MyTask extends AsyncTask<Void, Void, Void> { ... }

AsyncTask的四个重要方法。当一个异步任务被执行时,要经历四步: onPreExecute(),在UI线程中执行,它会在异步任务开始前执行,一般用来设置任务参数; doInBackground, 最重要的方法,在子线程中执行(事实上,只有它在子线程中执行,其他方法都在UI线程中执行)。当onPreExecute结束后,本方法立刻执行,它用来进行后台的耗时计算,异步任务的参数会被传给它,执行完成的结果会被送给第四步;执行途中,它还可以调用publishProgress 方法来通知UI线程当前执行的进度; onProgressUpdate, 当publishProgress 被调用后,它在UI线程中执行,刷新任务进度,一般用来刷新进度条等UI部件; onPostExecute, 当后台的异步任务完成后,会在UI线程中被调用,并获取异步任务执行完成的结果。

阅读全文

与androidasynctask使用相关的资料

热点内容
私有云主要服务器 浏览:939
为什么主题解压那么慢 浏览:860
怎么下载扫描二维码的手机app 浏览:727
云服务器创建私有镜像的时候一定要关机吗 浏览:115
php开发学习门户 浏览:385
传奇游戏服务器怎么设置 浏览:823
敲击东西解压完整版 浏览:401
刺络学pdf 浏览:868
怎么给手机文件夹设置封面 浏览:931
汽车保养app怎么用 浏览:62
线程javalock 浏览:896
c语言编译运行结果查看器 浏览:112
androidpx转dip 浏览:841
西藏编译局是什么级别 浏览:1001
php提交代码 浏览:597
如何用命令查找并删除代码块 浏览:582
python初学路线图 浏览:534
matlab遗传算法旅行商问题 浏览:304
将办公软件加入加密软件的进程 浏览:724
联想小新pro14编译器 浏览:462