Android中AsyncTask(异步任务)详解

来源:互联网 发布:python入门要多久 编辑:程序博客网 时间:2024/05/17 01:06

1、   Android中的单线程模型

当一个程序第一次启动时,Android会同时启动一个对应的主线程(Main Thread),主线程主要负责处理与UI相关的事件,如:用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。所以主线程通常又被叫做UI线程。

在开发Android应用时必须遵守单线程模型的原则: Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。

如 果在非UI线程中直接操作UI线程,会抛出异常android.view.ViewRoot$CalledFromWrongThreadException: Only the original threadthat created a view hierarchy can touch its views,这与普通的java程序不同。

由于UI线程负责事件的监听和绘图,因此,必须保证UI线程能够随时响应用户的需求,UI线程里的操作应该向中断事件那样短小,费时的操作(如网络连接)需要另开线程,否则,如果UI线程超过5s没有响应用户请求,会弹出对话框提醒用户终止应用程序。

备注:从4.0开始,网络连接的操作必须放在子线程中,如果放在主线程中会直接抛出异常。

主线程成不能执行耗时操作,子线程不能修改UI,如何解决这个问题?很荣幸,android共提供了5种解决方案供我们选择:

1)        使用Handler消息机制。子线程负责耗时操作,当需要修改UI时,发送Message让主线程帮组修改UI。(后面重点学习)

2)        在子线程中调用任何的View对象的post(Runnable)或postDelay(Runnable, tlong)方法,则Runnable中run方法的代码会在主线程中运行。(非主流,实际开发中使用不多)

3)        在子线程中调用Activity的runOnUiThread(Runnalbe)方法,则Runnable对象的run()方法内的代码会嵌入到主线程运行。(非主流,实际开发中使用不多)

4)        使用AsyncTask异步任务。(重点)

5)        使用Loader(重点)

        今天我们重点研究异步任务!

2、      什么是AsynTask

AsyncTask:异步任务,从字面上来说,就是在我们的UI主线程运行的时候,异步的完成一些操作。AsyncTask允许我们的执行一个异步的任务在后台。我们可以将耗时的操作放在异步任务当中来执行,并随时将任务执行的结果返回给我们的UI线程来更新我们的UI控件。通过AsyncTask我们可以轻松的解决多线程之间的通信问题。

怎么来理解AsyncTask呢?通俗一点来说,AsyncTask就相当于Android给我们提供了一个多线程编程的一个框架,其介于 Thread和Handler之间,我们如果要定义一个AsyncTask,就需要定义一个类来继承AsyncTask这个抽象类,并实现其唯一的一个 doInBackgroud 抽象方法,在此方法中来执行各种耗时操作。

3、      AsynTask使用步骤

要掌握AsyncTask,总结起来就是理解: 3个泛型,4个步骤。

3.1       三个泛型

3个泛型指的是什么呢?我们来看看AsyncTask这个抽象类的定义,当我们定义一个类来继承AsyncTask这个类的时候,我们需要为其指定3个泛型参数:

AsyncTask <Params,Progress, Result>

1)        Params: 这个泛型指定的是我们传递给异步任务执行时的参数的类型。

2)        Progress: 这个泛型指定的是我们的异步任务在执行的时候将执行的进度返回给UI线程的参数的类型。

3)        Result: 这个泛型指定的异步任务执行完后返回给UI线程的结果的类型

 我们在定义一个类继承AsyncTask类的时候,必须要指定好这三个泛型的类型,如果任何一个不想指定或者都不指定的话,则可将其写成Void,例如:

AsyncTask<Void, Void, Void>

注意:Void首字母必须大写,这个Void和java中空返回值void是不一样的。

3.2     四个步骤

当我们执行一个异步任务的时候,其需要按照下面的4个步骤分别执行。

步骤一:

        onPreExecute(): 这个方法是在执行异步任务之前的时候执行,并且是在UI Thread当中执行的,通常我们在这个方法里做一些UI控件的初始化的操作,例如弹出要给用户提示的ProgressDialog。

步骤二:

       doInBackground(Params... params): 在onPreExecute()方法执行完之后,会马上执行这个方法,这个方法就是来处理异步任务的方法,Android操作系统会在后台的线程池当中开启一个worker thread(子线程)来执行我们的这个方法,所以这个方法是在worker thread当中执行的,在这个方法里,我们可以从网络当中获取数据等一些耗时的操作。这个方法执行完之后就可以将我们的执行结果发送给我们的最后一个 onPostExecute 方法。注意:此方法不是 UI线程中执行。

步骤三:

onProgressUpdate(Progess... values):这个方法也是在UI Thread当中执行的,我们在异步任务执行的时候,有时候需要将正在执行的进度返回给我们的UI界面,例如下载一张网络图片,我们需要时刻显示其下载的进 度,就可以使用这个方法来更新我们的进度。这个方法在调用之前,我们需要在doInBackground 方法中调用一个publishProgress(Progress)的方法来将我们的进度时时刻刻传递给 onProgressUpdate 方法来更新。

步骤四:

        onPostExecute(Result... result):当我们的异步任务执行完之后,就会将结果返回给这个方法,这个方法也是在UIThread当中调用的,我们可以将返回的结果显示在UI控件上。

 

总结:以上4个方法中doInBackground是在workThread线程中执行,其余3个方法均是在UI(main)线程中执行。为什么我们的AsyncTask抽象类只有一个 doInBackground 的抽象方法呢??原因是,我们如果要做一个异步任务,我们必须要为其开辟一个新的Thread,让其完成一些操作,而在完成这个异步任务时,我可能并不需要弹出要给用户提示的ProgressDialog,我们可能并不需要随时更新我的ProgressDialog的进度条,我也可能并不需要将结果更新给我们的UI界面,所以除了 doInBackground 方法之外的三个方法,都不是必须有的,因此我们必须要实现的方法是 doInBackground 方法。


4     启动异步任务

     在主线程中执行如下代码开始执行异步任务:

new MyAsyncTask().execute(Params…ps);//其中的ps参数就是传递给doInBackgrount方法的。

5      停止异步任务

a:自然结束。当doInBackground方法执行完毕,异步任务自行结束

b:手动取消。我们可以在任何时刻来取消我们的异步任务的执行,通过调用 cancel(boolean)方法,调用完这个方法后系统会随后调用 isCancelled() 方法并且返回true。如果调用了这个方法,那么在 doInBackgroud() 方法执行完之后,就不会调用 onPostExecute() 方法了,取而代之的是调用 onCancelled() 方法。为了确保Task已经被取消了,我们需要经常调用isCancelled() 方法来判断,如果有必要的话。

6      使用异步任务的一些线程规则

   The AsyncTask class must be loaded on the UI thread. This is doneautomatically as of JELLY_BEAN.

   The task instance must be created on the UI thread.

   execute(Params...) must be invoked on the UI thread.

   Do not call onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...) manually.

   The task can be executed onlyonce (an exception will be thrown if a second execution is attempted.)






0 0