Подтвердить что ты не робот

Android - howto передает данные в Runnable в runOnUiThread?

Мне нужно обновить некоторый интерфейс и сделать его внутри потока пользовательского интерфейса, используя runOnUiThread
Теперь данные для пользовательского интерфейса поступают из другого потока, представленного data здесь.

Как я могу передать данные в Runnable, так что они могут быть использованы для обновления пользовательского интерфейса? Android, похоже, не позволяет напрямую использовать данные. Есть ли элегантный способ сделать это?

public void OnNewSensorData(Data data) {

    runOnUiThread(new Runnable() {
        public void run() {
            //use data
        }
    });
}

Мое решение создавало fioeld private Data sensordata внутри исполняемого файла и назначало ему данные. Это работает только, если исходный Data data является окончательным.

public void OnNewSensorData(final Data data) {

    runOnUiThread(new Runnable() {
        private Data sensordata = data;
        public void run() {
            //use sensordata which is equal to data
        }
    });
}
4b9b3361

Ответ 1

Вы обнаружили, что

Внутренние классы в захвате Java ( "закрыть" ) лексический охват, в котором они определены. Но они захватывают только переменные, объявленные "окончательными".

Если это ясно, как грязь, там хорошее обсуждение деталей здесь: Нельзя ссылаться на не конечную переменную внутри внутреннего класса, определенного другим способом

Но ваше решение выглядит отлично. Кроме того, при условии, что data является окончательным, вы можете упростить код:

public void OnNewSensorData(final Data data) {
    runOnUiThread(new Runnable() {
        public void run() {
            // use data here
            data.doSomething();
        }
    });
}

Ответ 2

Если вы хотите избежать использования промежуточной конечной переменной (как описано Dan S), вы можете реализовать Runnable с дополнительным методом для установки Data:

public class MyRunnable implements Runnable {
  private Data data;
  public void setData(Data _data) {
    this.data = _data;
  }

  public void run() {
    // do whatever you want with data
  }
}

Затем вы можете вызвать метод следующим образом:

public void OnNewSensorData(Data data) {
  MyRunnable runnable = new MyRunnable();
  runnable.setData(data);
  runOnUiThread(runnable);
}

вы также можете сделать конструктор MyRunnable в экземпляре Data в качестве аргумента:

public class MyRunnable implements Runnable {
  private Data data;
  public MyRunnable(Data _data) {
    this.data = _data;
  }

  public void run() {
    ...
  }
}

а затем просто скажите runOnUiThread (новый MyRunnable (данные));

Ответ 3

У меня была аналогичная проблема, когда я хотел передать информацию в поток. Чтобы решить эту проблему с помощью системы Android, я изменяю ответ corsiKa в: Runnable с параметром?

Вы можете объявить право класса в методе и передать параметр, как показано ниже:

void Foo(String str) {
    class OneShotTask implements Runnable {
        String str;
        OneShotTask(String s) { str = s; }
        public void run() {
            someFunc(str);
        }
    }
    runOnUiThread(new OneShotTask(str));
}

Ответ 4

Вам нужно будет обновлять каждый раз, когда ваша программа имеет новый Data, который она хочет показать. Ваш второй список кодов здесь является стандартным способом для этого. Могут быть некоторые уловы, если вы продолжаете обновлять Data в потоке. Если это так, подумайте о блокировке потока, пока пользовательский интерфейс не завершит обновление или копирование данных другому объекту Data.

Что происходит внутри, так это то, что JVM копирует ссылку на объект Data для запуска анонимного класса. Data, хранящийся внутри, все еще можно изменить. Если ваш метод требует дополнительных изменений в Data, просто используйте другую переменную (ссылку на объект), например: final Data finalData = data;. Вы также можете удалить строку private Data sensordata = data; и использовать данные непосредственно в своем методе выполнения.

Он может выглядеть не изящно, но это то, как Java передает объектные переменные анонимным классам. В Java Language версии 7 существует более новый синтаксис, но Android совместим с языковыми версиями Java версии 5 и 6.

Ответ 5

Вот типичный случай, когда вызывающий вызов службы вызывается для обновления строки состояния пользовательского интерфейса (TextView textStatus). Услуга может быть выполнена с резьбой.

В примере сочетается проверка необходимости перенаправления потоков и фактического перенаправления:

   // service callbacks
    public void service_StatusTextChanged(final String s) {
        if( isOnUiThread() ) {
            textStatus.setText(s);
        } else {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    textStatus.setText(s);
                }
            });
        }
    }

    static public boolean isOnUiThread() {
       return Thread.currentThread() == Looper.getMainLooper().getThread();
    }

См. также Как проверить, работает ли в потоке пользовательского интерфейса в Android?

Ответ 6

public static Activity globalContext = null;    
CommonSetting.globalContext = this;// put this in MainACtivity.onCreate()   
public void createToastShort(final String message) {
    runOnUiThread(new Runnable() {
        public void run() {
         Toast.makeText(CommonSetting.globalContext, message, Toast.LENGTH_SHORT).show();
        }
    });
}