线程的改进--------AsyncTask 介绍

当android应用程序启动的时候,android为应用程序开启了一个线程,称为主线程也称UI线程.这个线程负责分发用户响应并与用户进行交互.

如果在应用程序中只有主线程一个线程运行,在有些情况下会出现问题:比如请求网络数据,与数据库进行交互等一些比较耗时的操作进行时,此时,主线程被阻塞,任何消息都不能发送出去.从用户的角度上来看,应用程序被挂起了.更糟糕的是,如果UI线程被阻塞5秒以上就会出现ANR现象.

在这种情况下,我们可以考虑开启额外的线程,在线程里面处理耗时操作.考虑下面的代码:

public void onClick(View v) {
 
new Thread(new Runnable() {
   
public void run() {
     
Bitmap b = loadImageFromNetwork();
      mImageView
.setImageBitmap(b);
   
}
 
}).start();
}

 在onClick方法里面下载网络图片,并设置到本地的ImageView.

这看起来是一个不错的处理方案,并没有阻塞UI线程,但是由于在UI线程里面修改主线程里面的资源,这是线程不安全的.

android提供了以下几种方法在其他线程中访问主线程:

Activity.runOnUiThread(Runnable)

View.post(Runnable)

View.postDelayed(Runnable, long)

Handler

以上代码可以修改成:

public void onClick(View v) {
 
new Thread(new Runnable() {
   
public void run() {
     
final Bitmap b = loadImageFromNetwork();
      mImageView
.post(new Runnable() {
       
public void run() {
          mImageView
.setImageBitmap(b);
       
}
     
});
   
}
 
}).start();
}

但不幸的是,这些方法和类会降低代码的可读性.并且当我们需要进行复杂的操作和频繁进行UI更新时,这样的方法会变得更糟糕.

为了弥补这样的缺陷,android1.5版本之后,提供了AsyncTask类,这个类提供了一个长时间运行的任务并,其中提供了与用户进行交互的接口.

AsyncTask 可以替你进行线程管理.我们可以把上面的例子进行以下改写:

public void onClick(View v) {
 
new DownloadImageTask().execute("http://example.com/image.png");
}

private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
     
protected Bitmap doInBackground(String... urls) {
         
return loadImageFromNetwork(urls[0]);
     
}

     
protected void onPostExecute(Bitmap result) {
         mImageView
.setImageBitmap(result);
     
}
 
}

AsyncTask 必须要通过继承后才能使用.以下几点需要注意

1.一个AsyncTask实例必须要创建在UI线程上,并仅仅只执行一次,

2.doInBackground方法是自动在用户线程被执行的,而onPreExecute(), onPostExecute()和 onProgressUpdate() 回调方法被 UI 线程调用.

3.doInBackground()的返回值被发送到 onPostExecute()

4.任意时刻在doInBackground()里,我们可以通过调用所有的publishProgress() 使UI线程执行onProgressUpdate()方法

5.你可以在任意时间任意线程结束任务

一个小例子:

首先定义类DownloadFilesTask 继承自AsyncTask,AsyncTask中传入的三个参数类型URL, Integer, Long分别与三个回调方法的参数类型对应.

 private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
     
protected Long doInBackground(URL... urls) {
         
int count = urls.length;
         
long totalSize = 0;
         
for (int i = 0; i < count; i++) {
             totalSize
+= Downloader.downloadFile(urls[i]);
             publishProgress
((int) ((i / (float) count) * 100));
         
}
         
return totalSize;
     
}

     
protected void onProgressUpdate(Integer... progress) {
         setProgressPercent
(progress[0]);
     
}

     
protected void onPostExecute(Long result) {
         showDialog
("Downloaded " + result + " bytes");
     
}
 
}

在主线程中执行任务(必须在主线程中执行):
new DownloadFilesTask().execute(url1, url2, url3);

此时传入的三个参数被doInBackground获取到,它会调用publishProgress,这个方法里面可以传多个参数,publishProgress会触发onProgressUpdate,该方法取出了第一个参数.doInBackground方法会返回一个Long 类型的totalSize,这个作为参数传入onPostExecute.

1.任务执行后,onPreExecute()方法马上被主线程唤醒,

2.onPreExecute()方法执行完后,doInBackground(Params...)方法马上被其所在的线程唤醒,

3.在后台线程计算结束后,onPostExecute(Result)方法立即被主线程唤醒.

4. cancel(boolean)方法可以在任意时间结束任务,该方法可以导致 isCancelled() 返回true.此时,doInBackground(Object[])调用结束后会调用onCancelled(Object)方法,为了保证任务尽快的结束,需要周期性的在doInBackground内部检查isCancelled()的返回值,如果可能的话,使用looper

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值