Android异步处理特性之AsyncTask

2011-07-19 15:43:41|分类:android|字号订阅

虽然使用线程能适用大部分异步的场景,但是代码看起来还是不够简练,在android平台,还有另外一种解决方案----AsyncTask。

首先直接上代码:

private class getRemoteDataTask extends AsyncTask<String, Integer, ArrayList<Hashtable<String, String>>> {
protected void onPostExecute(ArrayList<Hashtable<String, String>> dataList) {

this.cancel(false);
}

@Override
protected ArrayList<Hashtable<String, String>> doInBackground(String... params) {
ArrayList<Hashtable<String, String>> dataList = new ArrayList<Hashtable<String, String>>();

return dataList;
}
}

下面来解释一下,doInBackground方法类似于在线程中的run方法,这个方法是另一个后台线程中执行,然后执行完会通过回调机制执行 onPostExecute,神奇之处就在于,onPostExecute这个方法的执行权限又交回给activity的主进程中执行,也就是说 onPostExecute这个方法里面可以操作UI。于是就能实现异步读取数据,并且操作UI,是不是比起自己写线程方便很多?

然后我们来剖析一下,这种方案的几个不太容易理解的地方。

一、AsyncTask<String, Integer, ArrayList<Hashtable<String, String>>> 注意这里几个泛型的定义和意义,第一个代表该方法被调用时传递的参数类型,注意是参数的类型,而不是参数的个数,也就是说如果定义为String,那么, 该方法被调用时所传递的参数只能是String类型;然后第二个Integer,资料上说是线程后台执行的百分比,不过我没彻底弄清楚这个的含义,欢迎大 家指教,然后泛型里的第三个ArrayList<Hashtable<String, String>,这个和该类的两个方法都有密切联系,该泛型是指后台执行返回的结果的类型。

二、doInBackground这个方法是在后台执行的,然后它的返回结果将提供给onPostExecute,所 以,doInBackground的返回值必须和AsyncTask类的第三个泛型定义一致,然后onPostExecute的参数类型必须和 doInBackground的返回类型一致。

三、前边我们都一直在解释AsyncTask这个类,但是怎么调用呢?其实很简单

newgetRemoteDataTask().execute(String...params);

注意,execute方法里传递的参数的类型必须和AsyncTask第一个泛型的类型一致,然后这个方法传递的参数将在

doInBackground(String...params)

这里面起作用。

第四,AsyncTask还有很多方法,我们仅仅分析了其中两个,它被继承后,必须要重写的一个方法是doInBackground,因为doInBackground的返回值将在onPostExecute中被用来更新UI,所以我们姑且认为这两个方法是最重要。

第五、AsyncTask的实例必须在UI线程中被调用、execute(String...params)必须在UI线程中调用、不要手动调用onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...)等方法、AsyncTask只执行一次。

一个小例子

Android异步处理特性之AsyncTask_第1张图片

有一个ListView的小例子,一开始List中没有内容,通过一个AsyncTask逐步在List中加入条目。

1)XML文件:简单的ListView布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout ... ...>

<ListView android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>

2)例子代码

public class Chapter15Test3 extends ListActivity{
//这里是List Item内容,在这个例子中,将在后台任务中逐个加入
private static String[] items={"lorem", "ipsum", "dolor","sit", "amet", "consectetuer","adipiscing", "elit", "morbi","vel", "ligula", "vitae","arcu", "aliquet", "mollis","etiam", "vel", "erat","placerat", "ante","porttitor", "sodales","pellentesque", "augue","purus"};

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.chapter_8_test2);

//在这个例子中,我们一开始并没有导入items的数据,注意item数据为新建的ArrayList,即无内容
setListAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,new ArrayList<String>()));
//步骤5:创建后台任务的对象,并通过execute()启动后台线程,调用doInBackground()的代码,execute中的参数类型为参数1,这里我们不需要传递任何内容
new AddStringTask().execute();
}

//步骤1:创建AsyncTask子类,参数1是Void的范式类型,参数2是String的范式类型,参数3是Void其中参数1:向后台任务的执行方法传递参数的类型;参数2:在后台任务执行过程中,要求主UI线程处理中间状态,通常是一些UI处理中传递的参数类型;参数3:后台任务执行完返回时的参数类型
private class AddStringTask extends AsyncTask<Void, String,Void>{
//我们加入一个检测信息的方法,打印当前在哪个线程执行的信息
private void printInfo(String info){
Log.d("WEI", info + " : Tread is " + Thread.currentThread().getName());
}


//步骤2:实现抽象方法doInBackground(),代码将在后台线程中执行,由execute()触发,由于这个例子并不需要传递参数,使用Void...,具体书写方式为范式书写
protected Void/*参数3*/ doInBackground(Void...params/*参数1*/) {
for(String item : items){
//步骤3:通知UI主线程执行相关的操作(在onProgressUpdate中定义)
publishProgress(item/*参数2*/);
printInfo("doInBackgound " + item);
SystemClock.sleep(200);
}
return null;

}

//步骤3:定义收到pushProgress()触发后,在UI主线程执行的内容,在本例,将item加入list中。方法中的参数为范式方式,实质为数组,由于我们只传递了item一个String,要获取,为values[0]
protected void onProgressUpdate(String... values/*参数2*/) {
printInfo("onProgressUpdate get param " + values[0]);
((ArrayAdapter<String>)getListAdapter()).add(values[0]);

}

//步骤4:定义后台进程执行完后的处理,本例,采用Toast

protected void onPostExecute(Void result/*参数3*/) {
printInfo("onPostExecute");
Toast.makeText(Chapter15Test3.this, "Done!", Toast.LENGTH_SHORT).show();
}
}
}

我们根据printInfo跟踪各部分代码在哪里执行:doInBackground在后台线程执行,onProgressUpdate()和onPostExecute()在UI主线程执行。main就是UI主线程,而AsyncTask #1为后台线程,名字不一样。

Android异步处理特性之AsyncTask_第2张图片

需要注意

虽然Android提供后台任务方便我们处理,是否使用后台任务,以及如何使用后台任务,我们要注意下面的内容:

可能在执行后台线程处理中,用户和UI之间存在交互,这些交换可能会对后台任务有重要的影响,因此需要通知后台线程,Android提供很多的类来处理,封装在java.util.concurrent包中,帮助与后台线程的安全通信。可能在执行后台线程处理中,我们的Activity就已经被kill了,例如有一个电话过来,然后发给短信,查看号码本。这时系统可能将你的activity踢走,接着后面我们会学习Activity的生命周期,了解相关的情况。在编程中,出现这种情况,只要有可能,需要将后台进程关闭。可能在执行后台线程处理中,出现某种错误,例如后台在下载URL,而网络连接中断了。这种情况下关闭后台进程可能是最好的处理。此外后台任务是消耗CPU和内存,是有代价的,我们应该确保它处理的时候更为有效。

更多相关文章

  1. Android 实现联网——在线程中联网
  2. Android 后台保活,这里有你需要的所有姿势。2019,最新版本。
  3. android animation中的参数interpolator详解
  4. android UI线程安全问题
  5. android 的Handler处理UI主线程外的耗时操作

随机推荐

  1. android事件处理
  2. Android(安卓)Shape详解
  3. android 设置Button为圆形按钮
  4. android布局实例代码
  5. 相对布局控制控件居右显示
  6. QR Codes Made Easy In Android
  7. Google Android(安卓)文档笔记-Training-
  8. Android之自定义适配器
  9. SlidingUpPanel
  10. Android版本和API对应关系