【Android】Android中的线程(AsyncTask)

以下内容部分摘自:
http://www.cnblogs.com/xiaoluo501395377/p/3430542.html

关于Android的知识详见上方链接,其中特别要注意的是,由于线程不安全的,所以不能在主线程(UI Thread)之外的线程当中对UI控件进行操作。因此在Android的多线程编程当中,有2条非常重要的原则必须要遵守:
  • 绝对不能在UI Thread当中进行耗时的操作阻塞UI Thread
  • 不能在UI Thread之外的线程当中操纵UI元素
Android中有两种方式实现线程:一是AsyncTask,一是Thread+Handler。这篇文章先总结AsyncTask,之后再总结Thread+Handler+,博主更推荐用AsyncTask,具体原因在总结了Thread+Handler之后会对比说明。

AsyncTask
要掌握AsyncTask,必须了解3个泛型和4个步骤。首先看看AsyncTask这个抽象类的定义,定义一个类来继承AsyncTask时,需要为其指定3个泛型参数:AsyncTask<Params, Progress, Result>
  • Params:这个泛型指定的是我们传递给异步任务执行时的参数的类型
  • Progress:这个泛型指定的是我们的异步任务在执行的时候将执行的进度返回给UI线程的参数的类型
  • Result:这个泛型指定的异步任务执行完后返回给UI线程的结果的类型

在定义一个类继承AsyncTask类的时候,必须要指定好这三个泛型的类型,如果都不指定的话,则都将其写成void:AsyncTask<void, void, void>。

执行一个AsyncTask异步任务是按照下面的4个步骤分别执行的:

  • onPreExecute():在执行异步任务之前的时候执行,并且是在UI Thread当中执行的。通常在这个方法里,做一些UI控件的初始化的操作,例如弹出ProgressDialog。
  • doInBackground(Params... params):在onPreExecute方法执行完之后,马上执行这个方法,这个方法就是处理异步任务的方法。Android操作系统会在后台的线程池当中开启一个Worker Thread来执行,执行完之后就可以将执行结果发送给最后一个 onPostExecute方法。通常在这个方法里,做一些从网络当中获取数据等耗时操作。
  • onProgressUpdate(Progess... values):这个方法也是在UI Thread当中执行的,有时候需要将执行的进度返回给UI界面,例如下载一张网络图片,需要时刻显示其下载的进度,就可以使用这个方法来更新我们的进度。这个方法在调用之前,我们需要在 doInBackground 方法中调用publishProgress(Progress) 方法来将进度时时刻刻传递给 onProgressUpdate方法更新。
  • onPostExecute(Result... result):异步任务执行完之后,会将结果返回给这个方法,这个方法也是在UI Thread当中调用的,可以将返回的结果显示在UI控件上。

有的时候只有一个 doInBackground 的抽象方法,其他三个方法都没有实现。这是因为如果要做一个异步任务,必须得为其开辟一个新的Thread,让其完成一些操作,而在完成这个异步任务时,可能并不需要不需要随时更新我的ProgressDialog的进度条,也并不需要将结果更新给UI界面,所以除了 doInBackground 方法之外的三个方法,都不是必须有的,必须要实现的方法是 doInBackground 方法


使用AsyncTask时的其他有关知识
1. 关闭AsyncTask异步任务

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

在java的线程中,没有办法停止一个正在运行中的线程。在Android的AsyncTask中也是一样如果必须要停止一个线程,可以采用这个线程中设置一个标志位,在doInBackground()方法中的关键步骤判断这个标志位以决定是否继续执行(对于Thread+Handler就在run()中判断标志位),然后在需要终止此线程的地方改变这个标志位以达到停止线程的目的。这只是一种办法,在android 如何结束一个线程?这篇文章里有更好的办法,博主没有用到,先mark一下~

2. 必须要遵循的原则

  • AsyncTask的对象必须在UI Thread当中实例化,execute方法必须在UI Thread当中调用。
  • 不要手动调用AsyncTask的onPreExecute、doInBackground、onProgressUpdate、onPostExecute,这些方法都是由Android系统自动调用的。
  • AsyncTask任务只能被执行一次。
下面以博主最近自己在写的一个程序为例,po一下使用AsyncTask的代码,博主的代码中实现了onPreExecute、doInBackground、onPostExecute三种方法,在文章最上方的链接里给出了实现onProgressUpdate的例子。

=====================================华丽丽的分割线===================================

功能描述:

博主最近在写的App中,某个Activity需要解析xml文件,并将解析结果展示在界面上,解析xml的工作比较耗时,需要在Worker Thread中执行。

具体分析:
  • onPreExecute():将界面上“加载更多”按钮的文字修改为“正在加载,请稍后...”。
  • doInBackground(Params... params):解析xml文件,解析出的数据保存在一个List中,该List通过一个SimpleAdapter与UI组件联系在一起。
  • onPostExecute(Result... result):根据解析是否成功,在界面上给出提示信息;通过SimpleAdapter通知UI组件修改内容,以展示解析结果;恢复“加载更多”按钮的文字。

根据以上分析,在Activity中增加一个继承AsyncTask的类。

/**
 * 解析xml文件
 */
private class LoadPaperAsyncTask extends AsyncTask

要使用这个类先要在Activity中声明一个变量

private LoadPaperAsyncTask asyncTask;

根据上面说到的“AsyncTask任务只能被执行一次”原则,每次需要解析xml文件时,博主都会将asyncTask重新new一下,例如:

asyncTask=new LoadPaperAsyncTask(auth+".xml");
asyncTask.execute(numOfPaper,true);

其中,execute的参数要与doInBackground中统一,在上面的代码中规定params[0]为int型,表示解析的起始序号,params[1]为boolean型,表示是否是第一次解析,这里execute与doInBackground统一了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章