2011-10-13 27 views
21

Necesito actualizar algunos UI y hacerlo dentro del hilo de la interfaz de usuario usando runOnUiThread
Ahora los datos para la interfaz de usuario provienen del otro hilo, representado por data aquí.
Android: ¿cómo pasar datos a Runnable en runOnUiThread?

¿Cómo puedo pasar los datos al Runnable, para que se puedan usar para actualizar la UI? 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 fue la creación de un fioeld private Data sensordata dentro del ejecutable, y la asignación de datos a la misma. Esto solo funciona, si el Data data original es final.

public void OnNewSensorData(final Data data) { 

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

Respuesta

35

El problema que encontramos es que

Las clases internas en la captura de Java ("cierran sobre") el léxico alcance en el cual están definidos. Pero solo capturan las variables que se declaran "finales".

Si esto es claro como el barro, hay una buena discusión de los detalles aquí: Cannot refer to a non-final variable inside an inner class defined in a different method

Pero su solución parece estar bien.Además, siempre que data es definitiva, se puede simplificar el código para esto:

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

Tendrá que actualizar cada vez que su programa tiene nueva Data se quiere mostrar. Su segunda lista de códigos aquí es la forma estándar de lograr esto. Puede haber algunas capturas si continúa actualizando 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 a otro objeto Data.

Lo que sucede internamente es que la JVM está copiando la referencia al objeto Data para cuando se ejecutará la clase anónima. Data almacenado en el interior todavía se puede cambiar. Si su método requiere cambios adicionales en Data, simplemente use otra variable (referencia de objeto) como: final Data finalData = data;. También puede eliminar la línea private Data sensordata = data; y usar datos directamente en su método de ejecución.

Puede que no se vea elegante, pero esta es la forma en que Java pasa las variables de objeto a las clases anónimas. No es más nueva sintaxis del lenguaje Java en la versión 7, pero Android es compatible con la versión del lenguaje Java 5 y 6.

20

Si desea evitar el uso de una variable intermedio final (como se describe por Dan S), puede implementar Ejecutable con un método adicional al conjunto de 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 como este:

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

que también podría hacer que el constructor de MyRunnable tomar en el Dat una instancia como un argumento:

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

    public void run() { 
    ... 
    } 
} 

y luego acaba de decir runOnUiThread (nueva MyRunnable (datos));

0
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(); 
     } 
    }); 
} 
5

Tuve un problema similar en el que quería pasar información al hilo. Para solucionarlo con el sistema androide, que la modificación de la respuesta de corsiKa en: Runnable with a parameter?

Se 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)); 
} 
1

Aquí es un caso típico en el servicio se llama a la devolución de llamada para actualizar una cadena de estado de IU (TextView textStatus). El servicio puede estar enhebrado.

La muestra combina comprobar si se necesita redirección hilo 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(); 
    } 

Véase también How to check if running on UI thread in Android?

Cuestiones relacionadas