not - Android: ¿cómo pasar datos a Runnable en runOnUiThread?
runonuithread(() (6)
El problema que encontraste es que
Las clases internas en Java capturan ("de cerca") el ámbito léxico en el que están definidas. Pero solo capturan variables que son declaradas "finales".
Si esto está claro como barro, hay una buena discusión de los detalles aquí: No se puede referir a una variable no final dentro de una clase interna definida en un método diferente
Pero tu solución se ve bien. Además, siempre que los data
sean definitivos, podría simplificar el código a esto:
public void OnNewSensorData(final Data data) {
runOnUiThread(new Runnable() {
public void run() {
// use data here
data.doSomething();
}
});
}
Necesito actualizar alguna interfaz de usuario y hacerlo dentro del hilo de la interfaz de usuario mediante el uso de runOnUiThread
Ahora los datos para la interfaz de usuario provienen del otro subproceso, representado por los data
aquí.
¿Cómo puedo pasar los datos a Runnable, para que puedan usarse para actualizar la interfaz de usuario? Android no parece permitir el uso de datos directamente. ¿Hay una manera elegante de hacer esto?
public void OnNewSensorData(Data data) {
runOnUiThread(new Runnable() {
public void run() {
//use data
}
});
}
Mi solución consistía en crear una información private Data sensordata
dentro del ejecutable y asignarle datos. Esto funciona solo si los Data data
originales son definitivos.
public void OnNewSensorData(final Data data) {
runOnUiThread(new Runnable() {
private Data sensordata = data;
public void run() {
//use sensordata which is equal to data
}
});
}
Este es un caso típico en el que se llama al servicio de devolución de llamada para actualizar una cadena de estado de IU (TextView textStatus). El servicio puede ser roscado.
La muestra combina la verificación de si es necesaria la redirección de hilos y la redirección real:
// 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();
}
Consulte también ¿Cómo comprobar si se está ejecutando en el hilo de la interfaz de usuario en Android?
Si desea evitar el uso de una variable final intermedia (como lo describe Dan S), puede implementar Runnable con un método adicional para establecer Datos:
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
}
}
A continuación, puede llamar al método de esta manera:
public void OnNewSensorData(Data data) {
MyRunnable runnable = new MyRunnable();
runnable.setData(data);
runOnUiThread(runnable);
}
también podría hacer que el constructor de MyRunnable tome la instancia de Data como un argumento:
public class MyRunnable implements Runnable {
private Data data;
public MyRunnable(Data _data) {
this.data = _data;
}
public void run() {
...
}
}
y luego diga runOnUiThread (nuevo MyRunnable (data));
Tendrá que actualizar cada vez que su programa tenga nuevos Data
que quiera mostrar. Su segundo código de lista aquí es la forma estándar de lograr esto. Puede haber algunos errores si continúa actualizando los Data
en el hilo. Si este es el caso, considere bloquear el hilo hasta que la interfaz de usuario termine de actualizar o copiar los datos en otro objeto de Data
.
Lo que está sucediendo internamente es que la JVM está copiando la referencia al objeto de Data
para cuando se ejecutará la clase anónima. Data
almacenados en el interior todavía se pueden cambiar. Si su método requiere cambios adicionales a los Data
use otra variable (referencia de objeto) como: final Data finalData = data;
. También puede eliminar la línea private Data sensordata = data;
y usa los datos directamente en tu método de ejecución.
Puede que no parezca elegante, pero esta es la forma en que Java pasa las variables de objeto a clases anónimas. Hay una sintaxis más nueva en Java Language versión 7, pero Android es compatible con Java Language versión 5 y 6.
Tuve un problema similar en el que quería pasar información al hilo. Para resolverlo con el sistema Android, modifico la respuesta de corsiKa en: ¿Se puede ejecutar con un parámetro?
Puede declarar un derecho de clase en el método y pasar el parámetro como se muestra a continuación:
void Foo(String str) {
class OneShotTask implements Runnable {
String str;
OneShotTask(String s) { str = s; }
public void run() {
someFunc(str);
}
}
runOnUiThread(new OneShotTask(str));
}
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();
}
});
}