为什么我们应该使用AsyncTask返回,而是在UI线程中运行?

时间:2014-11-07 20:12:45

标签: android asynchronous

我在填充ListView时遇到了麻烦1,因为我的经验说在UI线程上运行的方法具有最高优先级,因此运行速度比在backGround中运行的方法快很多但差异是UI线程不会等待它们完成所以我们不觉得它有任何滞后。

但是当我们使用AsyncTask结果时,像这样:

 Class async extends AsyncTasl<Void,Void,Bitmap>{

 @Override
 public Bitmap doInBackGround(Void...Params){
 .
 .
 .
  return new bitMap;
  }
}

因为它返回了一些东西,所以MainThread必须等待它完成,这否定了在backGround中运行的主要目的,所以我理解了一些错误的东西,或者没有理由在BackGround中做这些事情而他们在UI线程上运行速度更快?

更新:

我的观点是当我们使用async.execute()。get()

3 个答案:

答案 0 :(得分:0)

AsyncTasks是在后台执行操作而不阻塞主UI线程的好方法。

当你调用asyncTask.execute()时,

  • onPreExecute(..)回调在UI线程上发布
  • 在后台线程上调用doInBackground(..)(如果我正确理解你的问题,主线程不在这里等待)。当您从此方法中的服务器(例如)获取数据时,您将返回数据,以便Android系统将在UI线程上使用此数据调用onPostExecute
  • onPostExecute(..)在UI线程上发布,您在doInBackground(..)中返回的数据作为参数。

答案 1 :(得分:0)

不,主线程不等待任务完成,该返回值将传递给onPostExecute(...)方法。此方法将在主线程上运行,并将该返回值作为自己的输入参数。

Class async extends AsyncTasl<Void,Void,Bitmap>{

    @Override
    public Bitmap doInBackGround(Void...Params){
        /* Here is background thread */
        return new Bitmap(); ----+
    }                            |
                                 | //this object will be passed here
    @Override                    V
    public void onPostExecute(Bitmap result){
        /* Here is main thread */
    }
}

答案 2 :(得分:0)

UI线程的行为与执行代码的任何其他线程一样,但正如您所指出的,主要区别在于它是用户与之交互的线程。

想象一下这个场景: 您需要加载附有图标的列表项,并且该图标位于URL处,必须通过网络请求进行检索。

这里有一些示例代码,只要列表项出现在屏幕上,它就会获取位于URL的图像:

public View getView(int position) {
    final URL imageURL = getURL(position);
    final Bitmap image = getImage(imageURL); //this will take a while
    ...
    view.setIcon(imageIcon);
    return view;
}

在Android上使用列表视图时,只要用户在列表中滑动,就会发生对getView的调用,因为每个列表项都出现在屏幕上。

如果这一切都在UI线程上完成,则用户将看到一个列表,该列表需要花费很长时间才能加载每个列表项。主线程不够智能,无法将长时间运行的任务缩短(如果长时间运行的任务恰好将重要的用户数据保存到某个外部数据库?),所以必须让它们完全完成。同样重要的是要注意UI线程与系统角度的任何其他线程没有太大区别。这很重要,因为它是用户体验发生的地方。

这就是为什么在任何平台上编写任何应用程序时的最佳实践是将长时间运行的任务卸载到后台线程。操作系统可以处理线程之间的切换,从而产生对用户操作非常敏感的UI(如滑动列表)。

正如ABFORCE所示,您应该在Android上使用AsyncTask获取图像。在后台,将对图像的URL进行请求,并且只有当准备好在页面上显示最终图像时,才会调用UI线程来显示它。用户将看到他们可以快速浏览的列表,并且图像将在获取时弹出到每个列表项中。我们不希望用户做某事,因此我们希望确保他们可以根据需要快速浏览列表。

更新: 如果您要执行新的AsyncTask()。execute.get(),那么该方法确实会在UI线程上阻塞,从而否定后台线程的好处。您在扩展AsyncTask的类中可能需要做的是保持对您希望图像成为其中一部分的视图的引用(我假设每个列表项有一个新的AsyncTask),并在onPostExecute中设置需要的任何字段在该视图上设置。

示例:

class async extends AsyncTask<Void,Void,Bitmap>{

    private View view;

    @Override
    public Bitmap doInBackGround(Void...Params) {
        /* Here is background thread */
        return new Bitmap(); ----+
    }                            |
                                 | //this object will be passed here
    @Override                    V
    public void onPostExecute(Bitmap result) {
        /* Here is main thread */
        view.setIcon(result);
    }
}

...别处

public View getView(int position) {
    new async(view).execute();

    return view; //View will return now, and the image will populate later
}

显然有很多方法可以做到这一点,这是我的头脑之一。