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
}
});
}
Ответы
Ответ 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();
}
});
}