【问题标题】:Accessing views from other thread (Android)从其他线程访问视图(Android)
【发布时间】:2011-11-18 13:25:41
【问题描述】:

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

【问题讨论】:

  • 你检查过AsyncTask 课程吗?它是一个实用程序类,可帮助您轻松创建不同的线程并相应地更新 UI 元素。在这种情况下,您可以使用它的 publishProgress()onProgressUpdate() 方法。

标签: java android multithreading


【解决方案1】:

您可以通过多种方式处理它,

  1. 尝试使用AsyncTask,你的后台工作在doInBackGround()方法中完成,你的UI不会阻塞,你也可以访问Activity的视图您通过 publishProgress() 和 onProgressUpdate() 的上下文调用 AsyncTask。

  2. 如果您使用的是简单线程,那么使用Handler 或消息或runOnUiThread,您可以更新主线程的视图。

但是,按照你的方式,我认为 AsyncTask 最适合你。

【讨论】:

    【解决方案2】:

    您可以使用android.os.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: 只有创建视图层次结构的原始线程才能触摸其视图。
      【解决方案4】:

      将活动传递给您的线程,并从内部使用它来访问您的视图。

      // 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 以及其他好处)。我不知道它是否适用于您的情况,但您应该检查一下。

      【讨论】:

        【解决方案5】:

        您必须将要显示的数据存储到公共变量中,并让您的线程通过 Handler.post(runnable) 调用 Runnable Runnable的run()方法中的代码可以访问Textview

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-07-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多