Android 后台任务(三)AsyncTask

Android 后台任务(三)AsyncTask

翻译自:http://blog.stylingandroid.com/archives/833

转载请注明:http://blog.csdn.net/liaoqianchuan00/article/details/23949649


前面我们使用了线程来让耗时操作脱离UI线程执行,也介绍了一些在工作线程中如何再去更新主线程的方法。但是当我们为了频繁的在UI线程和工作线程之间切换加了很多Runnables时,我们的代码变得越来越难看。这篇文章,我们来看看AsyncTask怎么来提供一个更清晰的更新UI的机制。

 

AsyncTask为我们提供了开一个后台线程的框架。我们实现一个AsyncTask的子类,重写他的不同life-cycle点的一些方法,一些方法运行在UI线程,一些运行在后台工作线程。

 

你必须重写的一个方法是doInBackground方法,这个方法运行在后台工作线程,这个地方你需要添加你需要做得一些耗时操作的代码。其他3个可选的UI线程的方法:

 

1.      onPreExecute:在doInBackground之前执行,你可以在这里写上一些出事后的代码。

2.      onProgressUpdate:在doInBackground执行的同时执行的一些方法,你的耗时操作在进行的时候,你可以在这里更新UI来显示进度。

3.      onPostExecute:在doInBackground之后执行,你可以在这里写上耗时操作完成之后更新UI的代码。

 

有个评判的标准就是,当你只需要重写doInBackground方法的时候,你其实可以直接使用一个简单的Thread来实现。

 

AsyncTask是一个泛型类, 在定义一个AsyncTask的时候,你需要定义三个类型对象,分别是传入Task的对象类型(doInBackground传入的类型),代表进度的对象类型,工作线程返回的类型(doInBackground返回的类型。比如我们有一个任务是需要从网络上下载东西,同时基于一个整形数值来更新进度条,最后返回一个String值:

class MyAsyncTask extends AsyncTask<URL, Integer,String>

{

    private final Activityactivity;

     

    private ProgressBar progress;

    private int count = 0;

         

    public MyAsyncTask( Activityactivity )

    {

        this.activity= activity;

    }

     

    @Override

    protected void onPreExecute()

    {

        progress= (ProgressBar)

            activity.findViewById(R.id.progress );

    }

 

    @Override

    protected StringdoInBackground( URL... params )

    {

        Stringret = null;

        count= params.length;

        for(int i = 0; i < count; i++ )

        {

            publishProgress(i );

            //Do something which

            //populates "ret"

        }

        returnret;

    }

         

    @Override

    protected voidonProgressUpdate( Integer... values )

    {

        progress.setMax(count );

        progress.setProgress(values[0] );

    }

         

    @Override  

    protected void onPostExecute(String result )

    {

        Toast.makeText(activity, result,

            Toast.LENGTH_SHORT).show();

    }

         

}

 

这样做我们就不需要考虑手动的在UI线程和工作线程之间切换来更新UI了,它都为我们自动的处理了。

 

要使用它,我们需要创建一个MyAsyncTask的实力,并且调用execute的时候传入一个或者多个URL参数:

 

public class MyActivity extends Activity

{

    @Override

    public void onCreate( BundlesavedInstanceState )

    {

        super.onCreate(savedInstanceState );

        setContentView(R.layout.main );

 

        //Get some urls

 

        newMyAsyncTask( this ).execute( url1, url2, url3 );

    }

 

使用AsyncTask的一个问题就是,除非开发人员很清楚每个方法在哪个线程上执行,会很容易发生问题。比如,我发现一些人在onPreExecute方法中放入了网络请求的代码,这看起来没有什么问题,因为网络请求已经在AsyncTask中实现了啊,但是其实这个网络请求仍然在UI线程中执行的。

 

上面例子中还有一个问题就是AsyncTask保存了一个Activity的实例,由于AsyncTask线程池的机制,他的工作线程的生命周期是不确定的,应用程序无法控制的,所以这个时候如果AsyncTask作为Activity的内部类的话很容易出现内存泄露。而我们直接使用线程的方式要好点,只有在run函数不结束时,才出现这种内存泄露问题。以后将会单独用一篇文章来分析。

 

Activityfinish掉了,但是AsyncTask还在执行,会有问题吗?(需要验证)

 

在Honeycomb上引入了Loaders,这是另外一个机制来处理耗时操作,他更清晰的区分了那些是在UI线程上执行的,那些是在工作线程上执行的。同时他不需要在任务结束后保持对Context的引用。下一章我们将介绍Loaders。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值