平时我们在开发Android程序时遇到较耗时任务的处理,如I/O访问的数据库操作、网络访问等情况时造成UI假死等问题,通过 AsyncTask可以很好的解决这个问题,就今天以在Android中执行Downloader.downloadFile(url),可能会堵塞整个界面。显然这会影响用户体验,我们如何解决这个问题呢?
方法一、
创建一个新的线程执行我们的任务,使用Thread类,在 run(){}中写入任务代码,比如:
new Thread(new Runnable() {
public void run() {
Downloader.downloadFile(url);
}
}).start();
但使用Thread会产生一些意想不到的问题,需要程序员用更多的代码手动的维护它。
方法二: Android SDK为我们提供了一个后台任务的处理工具AsyncTask。AsyncTask就是一个封装过的后台任务类顾名思义就是异步任务,方便我们维护,Android开发网提示这样的好处可以解决一些线程安全问题,AsyncTask直接继承于Object类,位置为 android.os.AsyncTask。要使用AsyncTask工作我们要提供三个泛型参数,并重载四个方法(至少重载一个)。
三个泛型:
Param ,任务执行器需要的数据类型
Progress 后台计算中使用的进度单位数据类型
Result 后台计算返回结果的数据类型
有些参数是可以设置为不使用的,只要传递为Void型即可,比如AsyncTask
四个步骤:
onPreExecute(),执行预处理,它运行于UI线程,可以为后台任务做一些准备工作,比如绘制一个进度条控件。
doInBackground(Params...),后台进程执行的具体计算在这里实现,doInBackground(Params...)是AsyncTask的关键,此方法必须重载。在这个方法内可以使用 publishProgress(Progress...)改变当前的进度值。
onProgressUpdate(Progress...),运行于UI线程。如果在doInBackground(Params...)中使用了publishProgress(Progress...),就会触发这个方法。在这里可以对进度条控件根据进度值做出具体的响应。
onPostExecute(Result),运行于UI线程,可以对后台任务的结果做出处理,结果就是doInBackground(Params...)的返回值。此方法也要经常重载,如果Result为null表明后台任务没有完成(被取消或者出现异常)。
- public class main extends Activity {
- ImageView imageView01;
- TextView textView;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super .onCreate(savedInstanceState);
- setContentView(R.layout.main);
- textView = (TextView) this .findViewById(R.id.TextView01);
- imageView01 = (ImageView) this .findViewById(R.id.ImageView01);
- GetImage getImage = new GetImage();
- getImage.execute( "http://hi.csdn.net/attachment/201010/27/0_1288149117Yk8W.gif" );
- }
- private class GetImage extends AsyncTask {
- public GetImage() {
- super ();
- // TODO Auto-generated constructor stub
- }
- @Override
- protected void onCancelled() {
- Log.i( "czb" , "onCancelled is running..." );
- super .onCancelled();
- }
- @Override
- protected void onPostExecute(Object result) {
- /*
- * 此方法在主线程执行,任务执行的结果作为此方法的参数返回
- */
- Log.i( "czb" , "onPostExecute is running..." );
- Log.i( "czb" , "result == null ? " + (result == null ));
- imageView01.setImageBitmap((Bitmap)result);
- super .onPostExecute(result);
- }
- @Override
- protected void onPreExecute() {
- /*
- * 执行预处理,它运行于UI线程,可以为后台任务做一些准备工作,比如绘制一个进度条控件
- */
- Log.i( "czb" , "onPreExecute is running..." );
- super .onPreExecute();
- }
- @Override
- protected void onProgressUpdate(Object... values) {
- /*
- * 此方法在主线程执行,用于显示任务执行的进度。
- */
- Log.i( "czb" , "onProgressUpdate is running..." );
- // 由publishProgress传递的值
- Log.i( "czb" , "values " + values[ 0 ]);
- super .onProgressUpdate(values);
- }
- @Override
- protected Object doInBackground(Object... params) {
- /*
- * 此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。
- * 在执行过程中可以调用publicProgress(Progress…)来更新任务的进度。
- */
- Log.i( "czb" , "doInBackground is running..." );
- try {
- Bitmap bitmap;
- HttpClient client = new DefaultHttpClient();
- // params[0]代表连接的url
- URI uri = URI.create((String) params[ 0 ]);
- HttpGet get = new HttpGet(uri);
- HttpResponse response = client.execute(get);
- HttpEntity entity = response.getEntity();
- long length = entity.getContentLength();
- Log.i( "czb" , " " + length);
- InputStream in = entity.getContent();
- if (in != null ) {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- /*byte[] buf = new byte[128];
- int ch = -1;
- int count = 0;
- while ((ch = in.read(buf)) != -1) {
- baos.write(buf, 0, ch);
- count += ch;
- if (length > 0) {
- // 如果知道响应的长度,调用publishProgress()更新进度
- // onProgressUpdate读取进度
- publishProgress((int) ((count / (float) length) * 100));
- }
- // 为了在模拟器中清楚地看到进度,让线程休眠100ms
- //Thread.sleep(100);
- }*/
- bitmap = BitmapFactory.decodeStream(in);
- in.close();
- baos.close();
- return bitmap;
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null ;
- }
- }
- }