看了一下AsyncTask实现,现在总结一下,好有更深刻的印象,将自己的理解写出来也能有温故知新的收获。
在android的多线程通信中,handler、message的处理方式应该是最基础的,虽然没有看过各种通信方式的源码,但是网上的多数博客客观的说明了这一点,以后可以带着这个问题阅读源码。这样各种多线程的通信机制应该能弄得很透彻。在这里只是回顾一下自己在理解AsyncTask的具体应用是遇到的理解上应注意的地方,以便以后回过头来查看自己的理解的偏颇到底有多少,从而更好的把握自己思路。
AsyncTask的实现在于用户拥有的四个接口:
onPreExecute()
doInBackground(Params...)
onProgressUpdate(Progress...)
onPostExecute(Result)
以及asyncTask最终结束的方法onCancelled ()。
大多数资料只讲解了前面四个函数,第五个函数也确实好理解,和类的析构函数很类似。在这五个函数中,onPreExecute()、onProgressUpdate(Progress...)、onPostExecute(Result)、onCancelled()方法是在UI主线程中调用的,关于UI单线程的操作前面已经提到了,所以要实现多线程的通信,最为要紧的应该在唯一脱离UI主线程工作的后台执行的donInBackground(Params...)函数。
先简单看一下AsyncTask类的新建和实例生成及执行:
class Get优快云LogoTask extends AsyncTask<String, Integer, Bitmap> {} // 模板参数依次对应Params、Progress、Result
Get优快云LogoTask task = new Get优快云LogoTask();
task.execute("http://csdnimg.cn/www/images/csdnindex_logo.gif");
在这三行代码中,第一行是新建一个满足用户需求的异步事物的类,这里面需要设定自己的三个模板参数,这里设定成了String,Inreger,Bitmap。第一个参数是用户传入AsyncTask的具体参数类型,该参数类型的值在第三行代码以函数语句的形式传入了,第二个是asyncTask内部使用的参数类型,暂时不提,第三个参数是经过asyncTask后台处理之后得到的返回值类型。可以简单的将一、三两个参数看成一个函数的输入参数类型和返回值类型。然而asyncTask却为用户考虑的更多,用户不是要实现UI线程与子线程的通信吗,那我索性好人做到底,对于你的通信结果也一并送佛到西。第三个参数类型的值是返回值,这个返回值是从什么地方返回的呢,这个值是后台处理函数doInBackgroung(Params...)的返回值,是其return的结果,asyncTask的第三个模板参数也就是为这个返回值设定的类型。asyncTask在得到后台(也可以理解成子线程)的返回值后很仁义的又提供了另外一个函数:onPostExecute(Result)来将后台处理的结果result(其类型就是第三个模板参数,这里是Bitmap)在UI主线程中展示出来,这算是送佛送到西了。第二个参数设定的类型是asyncTask在后台运行时需要与UI主线程通信传送的值的类型。单个从这几个函数的实现并不能真的体会asyncTask的线程间通信。然而android对这几个函数的相互调用和参数传递的机制确实体现了多线程的通信。下面用例图解释。
通过图形可以看出,UI主线程启动asyncTask,首先是与后台无关的准备工作,即onPreExecute()函数的执行,理所当然的在给函数中执行UI更新是可以的。在准备工作完成后,系统就会自动的将paras类型的参数传递给doInBackground(Params...),从而启动了后台处理程序。在后台处理期间,如果后台需要和UI主线程完成通信,可以通过publishProgress(Progress)函数传递数据,此时系统会通过调用onProgressUpdate(Progress)函数响应后台。当doInBackground(Params...)执行外最后的return语句后,系统就会调用onPostExecut(result)函数,此时result就是doInBackground(Params...)函数的返回值。在onPostExecut(result)完成对UI界面的更新等内容,最后执行onCanclled()方法。
下面给出代码示例,该实例在网上也可找到,也运行通过了。
AsyncTaskActivity.javapackage com.zhuozhuo;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.Toast;
public class AsyncTaskActivity extends Activity {
private ImageView mImageView;
private Button mButton;
private ProgressBar mProgressBar;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mImageView= (ImageView) findViewById(R.id.imageView);
mButton = (Button) findViewById(R.id.button);
mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
mButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Get优快云LogoTask task = new Get优快云LogoTask();
task.execute("http://csdnimg.cn/www/images/csdnindex_logo.gif");
}
});
}
class Get优快云LogoTask extends AsyncTask<String,Integer,Bitmap> {//继承AsyncTask
@Override
protected Bitmap doInBackground(String... params) {//处理后台执行的任务,在后台线程执行
publishProgress(0);//将会调用onProgressUpdate(Integer... progress)方法
HttpClient hc = new DefaultHttpClient();
publishProgress(30);
HttpGet hg = new HttpGet(params[0]);//获取csdn的logo
final Bitmap bm;
try {
HttpResponse hr = hc.execute(hg);
bm = BitmapFactory.decodeStream(hr.getEntity().getContent());
} catch (Exception e) {
return null;
}
publishProgress(100);
//mImageView.setImageBitmap(result); 不能在后台线程操作ui
return bm;
}
protected void onProgressUpdate(Integer... progress) {//在调用publishProgress之后被调用,在ui线程执行
mProgressBar.setProgress(progress[0]);//更新进度条的进度
}
protected void onPostExecute(Bitmap result) {//后台任务执行完之后被调用,在ui线程执行
if(result != null) {
Toast.makeText(AsyncTaskActivity.this, "成功获取图片", Toast.LENGTH_LONG).show();
mImageView.setImageBitmap(result);
}else {
Toast.makeText(AsyncTaskActivity.this, "获取图片失败", Toast.LENGTH_LONG).show();
}
}
protected void onPreExecute () {//在 doInBackground(Params...)之前被调用,在ui线程执行
mImageView.setImageBitmap(null);
mProgressBar.setProgress(0);//进度条复位
}
protected void onCancelled () {//在ui线程执行
mProgressBar.setProgress(0);//进度条复位
}
}
}
main.xml<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ProgressBar android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/progressBar" style="?android:attr/progressBarStyleHorizontal"></ProgressBar>
<Button android:id="@+id/button" android:text="下载图片" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
<ImageView android:id="@+id/imageView" android:layout_height="wrap_content"
android:layout_width="wrap_content" />
</LinearLayout>
manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.zhuozhuo"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="10" />
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".AsyncTaskActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>