从其他线程访问视图(Android)

7
我正在开发一个安卓应用程序,其中有一个按钮可以启动/暂停某个模拟过程。在此过程运行时,我需要实时输出一些数据。但是当我为模拟创建一个新线程时,我无法从该线程访问视图(例如TextView),因为它们只能从创建它们的线程中访问。另一方面,新线程是必要的,否则用户将无法在模拟运行时执行任何操作(例如按下其他按钮)。在这种情况下,创建新服务也需要创建新线程。我该如何解决这个问题?

你是否了解过AsyncTask类?它是一个实用的类,可以帮助你轻松创建一个新线程,并相应地更新UI元素。在这种情况下,你可以使用它的publishProgress()onProgressUpdate()方法。 - user658042
5个回答

7
您可以用多种方法来处理它:
  1. 尝试在AsyncTask中使用,在这个过程中你的后台工作done in doInBackGround()方法,你的UI将不会阻塞,你也可以通过它的上下文通过publishProgress()和onProgressUpdate()访问调用AsyncTask的Activity的视图。
  2. 如果您正在使用一个简单的线程,那么使用Handler或message或runOnUiThread,您可以更新主线程的视图。
但是,在您的方式中,我认为AsyncTask最适合您。

5

您可以使用android.os.Handler来解决问题。Handler实例绑定到创建它的线程,您可以将Runnables发布到其中,它会在绑定的线程中执行它们。例如:

import android.os.Handler;
import android.widget.TextView;

public class MyActivity extends Activity {
  private Handler uiHandler;
  private TextView simulationStatus;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    ...
    uiHandler = new Handler();
    ...
    simulationStatus = (TextView) findViewById(R.id.simulationStatus);
    ...
  }

  // This method is to be executed on the simulation thread.
  public void simulate() {
    ...
    final String simulationStatusText = ...;
    ...
    uiHandler.post(new Runnable() {
      @Override
      public void run() {
        // This is run on the UI thread.
        simulationStatus.setText(simulationStatusText);
        ...
      }
    });
  }

  ...
}

您也可以使用 AsyncTask。请参考链接中的示例。

3

它们可以被访问,但只能以只读方式访问。你的意思是想要从线程上触发视图的更改。从工作线程(非UI线程)无法触发这些更改,你需要使用.runOnUiThread()或使用Handlers。在你想要显示某些内容的地方使用它们,例如在.runOnUiThread()中更新文本视图。

示例:

myThread = new Thread()
        {

            @Override
            public void run() {
                //yourOperation
                MyActivity.this.runOnUiThread(new Runnable(){

                    @Override
                    public void run() {
                        if(e!=null)
                        {
                            myTextView.setText("something");
                        }

                    }});
                super.run();
            }
        };
        myThread.start();

你提到的在非UI线程中只读取一个视图是否真的可能?我对使用Bitmap drawingCache = view.getDrawingCache()从视图中读取位图很感兴趣,但是我一直遇到异常:CalledFromWrongThreadException: 只有创建视图层次结构的原始线程才能触摸其视图。 - Giorgio

2
将活动传递给您的线程,并从中访问您的视图。
// from your activity:
myExternalThread = new MyCustomCode(this); // <-- activity passed

// your "simulation process" constructor:
public MyCustomCode(Activity parent) {
    this.parent = parent;
}

// and when you want to access views:
parent.runOnUiThread(new Runnable() {
    @Override
    public void run() {
        parent.findViewById(R.id.text_view);
        ... do something to your UI ...
    }
});

我喜欢使用AsyncTask来创建这些外部任务(这样你就不必担心runOnUiThread,还有其他一些好处)。我不知道它是否适用于您的情况,但您应该检查一下。


1

你需要将要显示的数据存储在公共变量中,并且让你的线程通过Handler.post(runnable)调用一个Runnable。 Runnable的run()方法中的代码能够访问TextView。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接