J'utilise progress dialog.i dois arrêter le fil de discussion lorsque l'utilisateur ferme le progressdialog. Malheureusement, il doit m'aider à obtenir une exception.
En classe intérieure
class UpdateThread extends Thread{
public void run() {
while (true){
count=adapter.getCount();
try {
mHandler.post( new Runnable() {
public void run() {
Log.i(TAG,count+"count");
progressDialog.setMessage(count + "Device found");
}
});
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Oncreate
updateThread=new UpdateThread();
progressDialog= new ProgressDialog(GroupListActivity.this);
synchronized (this) {
updateThread.start();
}
ondismissal
progressDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
try {
synchronized (this) {
updateThread.wait(300);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i(TAG,"Thread is stopped");
}
});
C'est faux:
synchronized(foo) {
foo.wait();
}
Le problème est, qu'est-ce qui va réveiller ce fil? C'est-à-dire, comment pouvez-vous garantir que l'autre thread n'appelle pas foo.notify()
avant le premier thread appelle foo.wait()
? C'est important car l'objet foo ne se souviendra pas qu'il a été averti si l'appel de notification a lieu en premier. S'il n'y a qu'un seul notify (), et si cela se produit avant wait (), alors wait () ne retournera jamais.
Voici comment attendre et notifier étaient censés être utilisés:
private Queue<Product> q = ...;
private Object lock = new Object();
void produceSomething(...) {
Product p = reallyProduceSomething();
synchronized(lock) {
q.add(p);
lock.notify();
}
}
void consumeSomething(...) {
Product p = null;
synchronized(lock) {
while (q.peek() == null) {
lock.wait();
}
p = q.remove();
}
reallyConsume(p);
}
Les éléments les plus importants à noter dans cet exemple sont qu’il existe un test explicite pour la condition (par exemple, q.peek ()! = Null) et que personne ne modifie la condition sans verrouiller le verrou.
Si le consommateur est appelé en premier, il trouvera la file vide et attendra. Il n'y a pas de moment où le producteur peut se glisser dans, ajouter un produit à la file d'attente, puis notifier le verrouillage jusqu'à ce que le consommateur soit prêt à recevoir cette notification.
Par ailleurs, si le producteur est appelé en premier, il est garanti au consommateur de ne pas appeler wait ().
La boucle du consommateur est importante pour deux raisons: la première est que, s'il existe plusieurs threads de consommation, il est possible qu'un consommateur reçoive une notification, puis qu'un autre se faufile et vole le produit dans la file d'attente. Dans ce cas, la seule chose raisonnable que le premier consommateur puisse faire est d’attendre le prochain produit. L'autre raison pour laquelle la boucle est importante est que Javadoc indique que Object.wait () est autorisé à retourner même lorsque l'objet n'a pas été notifié. C'est ce qu'on appelle un "réveil parasite", et la bonne façon de le gérer est de revenir en arrière et d'attendre à nouveau.
Remarque: le verrou est private
et la file d'attente est private
. Cela garantit qu'aucune autre unité de compilation ne va interférer avec la synchronisation dans cette unité de compilation.
Et remarque: le verrou est un objet différent de la file d'attente elle-même. Cela garantit que la synchronisation dans cette unité de compilation n'interférera pas avec la synchronisation que l'implémentation de Queue implémente (le cas échéant).
NOTE: Mon exemple réinvente une roue pour prouver un point. En code réel, vous utiliseriez les méthodes put () et take () d'un ArrayBlockingQueue qui prendrait en charge toutes les attentes et les notifications pour vous.
Vous ne pouvez attendre qu'un objet si vous le verrouillez déjà, vous pouvez essayer:
synchronized (updateThread) {
updateThread.wait(300);
}
... mais je ne suis pas vraiment sûr de ce que vous essayez de réaliser avec les serrures.
On dirait vraiment que vous essayez d'utiliser synchronized
et wait
là où vous ne devriez pas être.
Si vous voulez vraiment attendre que le fil se termine, vous devriez faire quelque chose comme ça
Dans votre UpdateThread
:
class UpdateThread extends Thread{
public AtomicBoolean stopped = new AtomicBoolean(false);
public void run() {
while (!stopped.get()){
.....
Dans ta création:
updateThread = new UpdateThread();
progressDialog = new ProgressDialog(GroupListActivity.this);
updateThread.start(); // no synchronization necessary
Dans votre congédiement:
progressDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
try {
updateThread.stopped.set(true);
updateThread.join(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i(TAG,"Thread is stopped");
}
});
Remarque, j'ai ajouté une condition de sortie à votre thread afin qu'il s'arrête réellement (tel quel, votre thread continue à fonctionner). Vous voudrez probablement rendre la condition de sortie privée et ajouter un passeur pour la propreté. De plus, j'utilise join
pour attendre que votre thread se termine.