java - method - cómo esperar a que se complete Android runOnUiThread?
runonuithread(() (6)
Tengo un hilo de trabajo que crea un objeto ejecutable y ejecuta runOnUiThread en él, porque trata con vistas y controles. Me gustaría usar el resultado del trabajo del objeto ejecutable de inmediato. ¿Cómo espero a que termine? No me molesta si está bloqueando.
Creo que la forma más sencilla de lograr esto es usar un "CountDownLatch".
final CountDownLatch latch = new CountDownLatch(1);
runOnUiThread(new Runnable() {
@Override
public void run() {
// Do something on the UI thread
latch.countDown();
}
});
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
// Now do something on the original thread
(Creo que esta pregunta es un duplicado de " Cómo hacer que la tarea del temporizador espere hasta que finalice runOnUiThread ")
La respuesta de Andrew es buena, creo una clase para un uso más fácil.
Implementación de interfaz:
/**
* Events for blocking runnable executing on UI thread
*
* @author
*
*/
public interface BlockingOnUIRunnableListener
{
/**
* Code to execute on UI thread
*/
public void onRunOnUIThread();
}
Implementación de clase:
/**
* Blocking Runnable executing on UI thread
*
* @author
*
*/
public class BlockingOnUIRunnable
{
// Activity
private Activity activity;
// Event Listener
private BlockingOnUIRunnableListener listener;
// UI runnable
private Runnable uiRunnable;
/**
* Class initialization
* @param activity Activity
* @param listener Event listener
*/
public BlockingOnUIRunnable( Activity activity, BlockingOnUIRunnableListener listener )
{
this.activity = activity;
this.listener = listener;
uiRunnable = new Runnable()
{
public void run()
{
// Execute custom code
if ( BlockingOnUIRunnable.this.listener != null ) BlockingOnUIRunnable.this.listener.onRunOnUIThread();
synchronized ( this )
{
this.notify();
}
}
};
}
/**
* Start runnable on UI thread and wait until finished
*/
public void startOnUiAndWait()
{
synchronized ( uiRunnable )
{
// Execute code on UI thread
activity.runOnUiThread( uiRunnable );
// Wait until runnable finished
try
{
uiRunnable.wait();
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
}
}
}
Utilizándolo:
// Execute an action from non-gui thread
BlockingOnUIRunnable actionRunnable = new BlockingOnUIRunnable( yourActivity, new BlockingOnUIRunnableListener()
{
public void onRunOnUIThread()
{
// Execute your activity code here
}
} );
actionRunnable.startOnUiAndWait();
Solo arañar los aspectos más destacados
synchronized( myRunnable ) {
activity.runOnUiThread(myRunnable) ;
myRunnable.wait() ; // unlocks myRunable while waiting
}
Mientras tanto ... en myRunnable ...
void run()
{
// do stuff
synchronized(this)
{
this.notify();
}
}
Tal vez un poco simplista, pero un mutex hará el trabajo:
final Semaphore mutex = new Semaphore(0);
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
// YOUR CODE HERE
mutex.release();
}
});
try {
mutex.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
Una solución podría ser aprovechar FutureTask<T>
Java, que tiene el beneficio de que otra persona ya ha tratado con todos los posibles problemas de concurrencia:
public void sample(Activity activity) throws ExecutionException, InterruptedException {
Callable<Void> callable = new Callable<Void>() {
@Override
public Void call() throws Exception {
// Your task here
return null;
}
};
FutureTask<Void> task = new FutureTask<>(callable);
activity.runOnUiThread(task);
task.get(); // Blocks
}
Incluso puede devolver un resultado del hilo principal al reemplazar el Void
con algo más.
Utilice la clase AsyncTask, sus métodos onPostExecure y onProgressUpdate se ejecutan mediante el subproceso MAIN (el subproceso UI).
http://developer.android.com/reference/android/os/AsyncTask.html
Es la mejor manera para tu caso!
Espero que esto le pueda ayudar.