主UI和AsyncTask是否在同一个线程上运行?

时间:2016-01-25 10:40:09

标签: java android multithreading android-asynctask

我在尝试显示加载消息时发现此消息,或者您可以在我的活动中说明进度条。

我尝试在UI线程和AsyncTask中使用Thread.currentThread.getId()打印线程ID。两者都打印1。

如果两者都在同一个线程上运行,那么我们如何在运行复杂任务时更改UI(建议在onPreExecute中执行)(建议在doInBackground中执行)。

请解释

3 个答案:

答案 0 :(得分:1)

doInBackground()在后​​台线程上运行,然后才会正确使用AsyncTask

doInBackground()无法直接更改UI,因为它在后台线程上运行。如果您在doInBackground()运行时需要进行更改,请致电publishProgress()。这会触发对onProgressUpdate()的调用,并且将在主应用程序线程上调用。

例如,这个保留的片段有一个AsyncTask,可以通过ListViewArrayAdapter添加单词,因为单词可用(使用Thread.sleep()进行模拟来自网络I / O的延迟):

/***
  Copyright (c) 2008-2014 CommonsWare, LLC
  Licensed under the Apache License, Version 2.0 (the "License"); you may not
  use this file except in compliance with the License. You may obtain   a copy
  of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless required
  by applicable law or agreed to in writing, software distributed under the
  License is distributed on an "AS IS" BASIS,   WITHOUT WARRANTIES OR CONDITIONS
  OF ANY KIND, either express or implied. See the License for the specific
  language governing permissions and limitations under the License.

  From _The Busy Coder's Guide to Android Development_
    https://commonsware.com/Android
 */

package com.commonsware.android.async;

import android.app.ListFragment;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Toast;
import java.util.ArrayList;

public class AsyncDemoFragment extends ListFragment {
  private static final String[] items= { "lorem", "ipsum", "dolor",
      "sit", "amet", "consectetuer", "adipiscing", "elit", "morbi",
      "vel", "ligula", "vitae", "arcu", "aliquet", "mollis", "etiam",
      "vel", "erat", "placerat", "ante", "porttitor", "sodales",
      "pellentesque", "augue", "purus" };
  private ArrayList<String> model=new ArrayList<String>();
  private ArrayAdapter<String> adapter=null;
  private AddStringTask task=null;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setRetainInstance(true);

    task=new AddStringTask();
    task.execute();

    adapter=
        new ArrayAdapter<String>(getActivity(),
                                 android.R.layout.simple_list_item_1,
                                 model);
  }

  @Override
  public void onViewCreated(View v, Bundle savedInstanceState) {
    super.onViewCreated(v, savedInstanceState);

    getListView().setScrollbarFadingEnabled(false);
    setListAdapter(adapter);
  }

  @Override
  public void onDestroy() {
    if (task != null) {
      task.cancel(false);
    }

    super.onDestroy();
  }

  class AddStringTask extends AsyncTask<Void, String, Void> {
    @Override
    protected Void doInBackground(Void... unused) {
      for (String item : items) {
        if (isCancelled())
          break;

        publishProgress(item);
        SystemClock.sleep(400);
      }

      return(null);
    }

    @Override
    protected void onProgressUpdate(String... item) {
      if (!isCancelled()) {
        adapter.add(item[0]);
      }
    }

    @Override
    protected void onPostExecute(Void unused) {
      Toast.makeText(getActivity(), R.string.done, Toast.LENGTH_SHORT)
           .show();

      task=null;
    }
  }
}

(来自this sample project中描述的this book

答案 1 :(得分:0)

AsyncTask执行命令在Main UiThread上运行但doInBackgroundworker thread上运行,这意味着Thread.currentThread.getId()中的doInBackground()将返回不同的号码

希望这会有所帮助。

答案 2 :(得分:0)

在幕后,Async Task实际上使用HaMeR框架在doInBackground()中创建了一个新线程。所以它真的取决于你在哪里打印线程ID。