J'ai un thread de travail qui crée un objet exécutable et appelle runOnUiThread dessus, car il traite des vues et des contrôles. J'aimerais utiliser le résultat du travail de l'objet exécutable tout de suite. Comment attendre qu'il se termine ? Ça ne me dérange pas si ça bloque.
Réponses
Trop de publicités?La réponse d'Andrew est bonne, je crée une classe pour une utilisation plus facile.
Implémentation de l'interface :
/**
* Events for blocking runnable executing on UI thread
*
* @author
*
*/
public interface BlockingOnUIRunnableListener
{
/**
* Code to execute on UI thread
*/
public void onRunOnUIThread();
}
Implémentation de classe :
/**
* 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();
}
}
}
}
En l'utilisant :
// Execute an action from non-gui thread
BlockingOnUIRunnable actionRunnable = new BlockingOnUIRunnable( yourActivity, new BlockingOnUIRunnableListener()
{
public void onRunOnUIThread()
{
// Execute your activity code here
}
} );
actionRunnable.startOnUiAndWait();
Une solution pourrait consister à tirer parti de Java FutureTask<T>
qui présente l'avantage que quelqu'un d'autre a déjà traité tous les problèmes de simultanéité potentiels pour vous :
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
}
Vous pouvez même renvoyer un résultat du thread principal en remplaçant Void
par autre chose.
Je pense que le moyen le plus simple d'y parvenir est d'utiliser 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
(Je crois que cette question est un doublon de " Comment faire en sorte que la tâche du minuteur attende la fin de runOnUiThread ")