zoukankan      html  css  js  c++  java
  • 具体解释Android中AsyncTask的使用

    在Android中实现异步任务机制有两种方式,Handler和AsyncTask。

    Handler模式须要为每个任务创建一个新的线程,任务完毕后通过Handler实例向UI线程发送消息,完毕界面的更新,这样的方式对于整个过程的控制比較精细,但也是有缺点的,比如代码相对臃肿,在多个任务同一时候运行时,不易对线程进行精确的控制。关于Handler的相关知识,前面也有所介绍,不清楚的朋友们能够參照一下。

    为了简化操作,Android1.5提供了工具类android.os.AsyncTask,它使创建异步任务变得更加简单,不再须要编写任务线程和Handler实例就可以完毕同样的任务。

    先来看看AsyncTask的定义:

    三种泛型类型分别代表“启动任务运行的输入參数”、“后台任务运行的进度”、“后台计算结果的类型”。在特定场合下,并非全部类型都被使用,假设没有被使用,能够用java.lang.Void类型取代。

    一个异步任务的运行一般包含下面几个步骤:

    1.execute(Params... params),运行一个异步任务,须要我们在代码中调用此方法,触发异步任务的运行。

    2.onPreExecute(),在execute(Params... params)被调用后马上运行,一般用来在运行后台任务前对UI做一些标记。

    3.doInBackground(Params... params),在onPreExecute()完毕后马上运行,用于运行较为费时的操作,此方法将接收输入參数和返回计算结果。在运行过程中能够调用publishProgress(Progress... values)来更新进度信息。

    4.onProgressUpdate(Progress... values),在调用publishProgress(Progress... values)时,此方法被运行,直接将进度信息更新到UI组件上。

    5.onPostExecute(Result result),当后台操作结束时,此方法将会被调用,计算结果将做为參数传递到此方法中,直接将结果显示到UI组件上。

    在使用的时候,有几点须要格外注意:

    1.异步任务的实例必须在UI线程中创建。

    2.execute(Params... params)方法必须在UI线程中调用。

    3.不要手动调用onPreExecute(),doInBackground(Params... params),onProgressUpdate(Progress... values),onPostExecute(Result result)这几个方法。

    4.不能在doInBackground(Params... params)中更改UI组件的信息。

    5.一个任务实例仅仅能运行一次,假设运行第二次将会抛出异常。

    接下来,我们来看看怎样使用AsyncTask运行异步任务操作,我们先建立一个项目,结构例如以下:

    结构相对简单一些,让我们先看看MainActivity.java的代码:

    布局文件main.xml代码例如以下:

    由于须要訪问网络,所以我们还须要在AndroidManifest.xml中增加訪问网络的权限:

    我们来看一下执行时的界面:

    以上几个截图各自是初始界面、运行异步任务时界面、运行成功后界面、取消任务后界面。运行成功后,整个过程日志打印例如以下:

    假设我们在运行任务时按下了“cancel”button,日志打印例如以下:

    能够看到onCancelled()方法将会被调用,onPostExecute(Result result)方法将不再被调用。

    上面介绍了AsyncTask的基本应用,有些朋友或许会有疑惑,AsyncTask内部是怎么运行的呢,它运行的过程跟我们使用Handler又有什么差别呢?答案是:AsyncTask是对Thread+Handler良好的封装,在android.os.AsyncTask代码里仍然能够看到Thread和Handler的踪迹。以下就向大家具体介绍一下AsyncTask的运行原理。

    我们先看一下AsyncTask的大纲视图:

    我们能够看到关键几个步骤的方法都在当中,doInBackground(Params... params)是一个抽象方法,我们继承AsyncTask时必须覆写此方法;onPreExecute()、onProgressUpdate(Progress... values)、onPostExecute(Result result)、onCancelled()这几个方法体都是空的,我们须要的时候能够选择性的覆写它们;publishProgress(Progress... values)是final修饰的,不能覆写,仅仅能去调用,我们通常会在doInBackground(Params... params)中调用此方法;另外,我们能够看到有一个Status的枚举类和getStatus()方法,Status枚举类代码段例如以下:

    能够看到,AsyncTask的初始状态为PENDING,代表待定状态,RUNNING代表运行状态,FINISHED代表结束状态,这几种状态在AsyncTask一次生命周期内的非常多地方被使用,非常重要。

    介绍完大纲视图相关内容之后,接下来,我们会从execute(Params... params)作为入口,重点分析一下AsyncTask的运行流程,我们来看一下execute(Params... params)方法的代码段:

    代码中涉及到三个陌生的变量:mWorker、sExecutor、mFuture,我们也会看一下他们的庐山真面目:

    关于sExecutor,它是java.util.concurrent.ThreadPoolExecutor的实例,用于管理线程的运行。代码例如以下:

    mWorker实际上是AsyncTask的一个的抽象内部类的实现对象实例,它实现了Callable<Result>接口中的call()方法,代码例如以下:

    而mFuture实际上是java.util.concurrent.FutureTask的实例,以下是它的FutureTask类的相关信息:

    能够看到FutureTask是一个能够中途取消的用于异步计算的类。

    以下是mWorker和mFuture实例在AsyncTask中的体现:

     我们看到上面的代码中,mFuture实例对象的done()方法中,假设捕捉到了CancellationException类型的异常,则发送一条“MESSAGE_POST_CANCEL”的消息;假设顺利运行,则发送一条“MESSAGE_POST_RESULT”的消息,而消息都与一个sHandler对象关联。这个sHandler实例实际上是AsyncTask内部类InternalHandler的实例,而InternalHandler正是继承了Handler,以下我们来分析一下它的代码:

    我们看到,在处理消息时,遇到“MESSAGE_POST_RESULT”时,它会调用AsyncTask中的finish()方法,我们来看一下finish()方法的定义:

    原来finish()方法是负责调用onPostExecute(Result result)方法显示结果并改变任务状态的啊。

    另外,在mFuture对象的done()方法里,构建一个消息时,这个消息包括了一个AsyncTaskResult类型的对象,然后在sHandler实例对象的handleMessage(Message msg)方法里,使用以下这样的方式取得消息中附带的对象:

    这个AsyncTaskResult到底是什么呢,它又包括什么内容呢?事实上它也是AsyncTask的一个内部类,是用来包装运行结果的一个类,让我们来看一下它的代码结构:

    看以看到这个AsyncTaskResult封装了一个AsyncTask的实例和某种类型的数据集,我们再来看一下构建消息时的代码:

    在处理消息时是怎样使用这个对象呢,我们再来看一下:

    概括来说,当我们调用execute(Params... params)方法后,execute方法会调用onPreExecute()方法,然后由ThreadPoolExecutor实例sExecutor运行一个FutureTask任务,这个过程中doInBackground(Params... params)将被调用,假设被开发人员覆写的doInBackground(Params... params)方法中调用了publishProgress(Progress... values)方法,则通过InternalHandler实例sHandler发送一条MESSAGE_POST_PROGRESS消息,更新进度,sHandler处理消息时onProgressUpdate(Progress... values)方法将被调用;假设遇到异常,则发送一条MESSAGE_POST_CANCEL的消息,取消任务,sHandler处理消息时onCancelled()方法将被调用;假设运行成功,则发送一条MESSAGE_POST_RESULT的消息,显示结果,sHandler处理消息时onPostExecute(Result result)方法被调用。

    经过上面的介绍,相信朋友们都已经认识到AsyncTask的本质了,它对Thread+Handler的良好封装,降低了开发人员处理问题的复杂度,提高了开发效率,希望朋友们能多多体会一下。

  • 相关阅读:
    LVS基于DR模式负载均衡的配置
    Linux源码安装mysql 5.6.12 (cmake编译)
    HOSt ip is not allowed to connect to this MySql server
    zoj 3229 Shoot the Bullet(无源汇上下界最大流)
    hdu 3987 Harry Potter and the Forbidden Forest 求割边最少的最小割
    poj 2391 Ombrophobic Bovines(最大流+floyd+二分)
    URAL 1430 Crime and Punishment
    hdu 2048 神、上帝以及老天爷(错排)
    hdu 3367 Pseudoforest(最大生成树)
    FOJ 1683 纪念SlingShot(矩阵快速幂)
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/4034831.html
Copyright © 2011-2022 走看看