3

我在这里看到了一些问题,提出了类似的问题,但我还没有看到合适的答案。很多人都问过如何从线程更新 UI,但他们几乎总是与 UI 在同一个类中。

我想要做的是从另一个类中创建的线程更新 UI。我已经看到了所有的建议,例如异步、处理程序、可运行等......但我在单独的类中实现它们时遇到了真正的麻烦。

我试图让我的 UI 类最小化,并且只处理与 GUI 的交互,例如当用户按下按钮时。现在,我在一个新类中创建了一个新线程,它连接到蓝牙设备,但是我想将 UI 线程中的一个按钮从“连接”按钮更改为“断开”按钮(即更改从创建蓝牙套接字到关闭它的按钮)。

这样做的一般方法是什么?我是否认为这一切都错了,应该把所有东西都放在一个班级里?“主” UI 类与其他类/线程之间交互的正确方法是什么?

理想情况下,我希望能够进行其他 UI 交互,因此一些允许 UI 类之外的其他 UI 更改的解决方案会很棒!

4

3 回答 3

8

我想要做的是从另一个类中创建的线程更新 UI。我已经看到了所有的建议,例如异步、处理程序、可运行等......但我在单独的类中实现它们时遇到了真正的麻烦。

一般来说,为了您的目标,我建议您使用:

我不认为它太棘手。绝对不。如果您将其作为单独的类而不是某些Activity类中的内部类,那么我建议使用构造函数,您将在其中传递上下文、小部件,通常是您想要的任何内容,然后使用正确的方法(允许 UI 更新)更新你的UI.

我这样做是因为我喜欢当我有干净的类时(所以 UI 类只有 UI 实现并且逻辑是分开定位的)。

例子:

public class TaskExample extends AsyncTask<Void, Integer, Void> {

   private Context c;
   private Button b;

   public TaskExample(Context c, Button b) {
      this.c = c;
      this.b = b;
   }

   protected Void doInBackground(Void... params) {
      // some work
      if (isSomethingConnected) {
         publishProgress(Constants.IS_CONNECTED);
      }
      return null;
   }

   public void onProgressUpdate(Integer... params) {
       switch (params[0]) {
          case Constants.IS_CONNECTED:
             b.setText("Connected");
          break;
          case Constants.ANOTHER_CONSTANT:
             // another work
          break;
       }
   }  
}

用法:

public class Main extends Activity implements View.OnClickListener {

   private Button b;

   public void onCreate(Bundle b) {
      super.onCreate(b);
      // initialise widgets and set listeners to appropriate widgets
   }

   public void onClick(View v) {
      switch(v.getId()) {
         case R.id.connectBtn:
            startWorker();
         break;
      }
   }

   private void startWorker() {
      TaskExample te = new TaskExample(this, b);
      te.execute();
   }
}
于 2013-02-20T17:34:25.857 回答
2

有几个选项。如果您有权访问要更改的视图并且只需要强制刷新,则可以View.postInvalidate()从任何线程使用。如果您需要更复杂的操作,例如更改按钮的文本,您应该使用runOnUIThread,这需要访问Activity上下文。这应该很容易获得 - 只需将其添加为自定义对象构造函数的参数即可。在这种情况下,您可以执行以下操作:

activityContext.runOnUiThread(new Runnable(){
    @Override
    public void run() {
        myButton.setText("disconnect");
    }
});
于 2013-02-20T18:02:43.357 回答
0

使用该runOnUiThread(Runnable)方法在主线程上运行某些东西并调用该ClassName.View.invalidate()方法,如果它是一个视图,或者只是 public在您的目标类中创建一个方法来处理 UI 的刷新。

于 2013-02-20T17:34:04.297 回答