2010-05-04 4 views
1

J'essaie de créer un jeu multijoueur simple. Il y a un WorkerService qui est censé gérer toutes les communications réseau et toutes les interactions entre ce service et mes activités se font avec AIDL. Je pense que c'est une approche standard - pour permettre une interaction bidirectionnelle, j'utilise aussi une interface IWorkerCallback (aussi AIDL).Le rappel d'un autre thread provoque une exception

Le problème est que les rappels doivent changer les choses dans l'interface utilisateur, ce qui peut être fait uniquement dans le thread de l'interface utilisateur. J'ai créé un Handler (dans le fil de l'interface utilisateur) et je crois que c'est une solution évidente. Mais, étonnamment, ça ne marche pas.

Mes LoungeActivity appels startServer() méthode de IWorker interface. La méthode correspondante de mon WorkerService fait du travail et fait un rappel - cela fonctionne bien. Puis WorkerService fraie un nouveau thread et le rappel de ce fil entraîne une mauvaise exception levée:

Can't create handler inside thread that has not called Looper.prepare()

est ici un code pour préciser:

startServer() mise en œuvre:

private void startServerImpl(String name, float latStart, float latEnd, 
float lonStart, float lonEnd) 
{ 
    // some instructions here 

    // this works fine: 
    callback.notifySocketCreated(); 

    // my naughty thread: 
    new ServerThread().start(); 

    // some instructions here 
} 

ServerThread code:

private class ServerThread extends Thread { 
    @Override 
    public void run() 
    { 
     //some instructions here 

     // this call will cause an error 
     callback.notifyGameRegistered(); 

    } 
} 

Chaque méthode de callback ressemble que:

public void notifyGameRegistered() throws RemoteException 
{ 
    handler.dispatchMessage(handler.obtainMessage(CALLBACK_GAME_REGISTERED)); 
} 

Dans la méthode de gestionnaire handleMessage() que je fais simple switch(msg.what) et dans tous les cas il y a une modification de l'interface utilisateur simple (montrant une modification du texte, Toast, etc.). Je n'ai aucune idée de pourquoi cette Exception est levée .. J'ai réussi à la corriger en plaçant le code dans un Runnable et en appelant runOnUiThread() mais cela me rend toujours curieux - un gestionnaire ne devrait-il pas toujours fonctionner dans le thread qui l'a créé? ? Ou peut-être que je fais quelque chose de mal?

Répondre

0

Vous devez en quelque sorte appeler la fonction incriminée à partir du thread principal.

+0

Eh bien .. Je le fais maintenant. Mais pourquoi handleMessage est-il exécuté dans deux threads différents?Une fois qu'il est dans l'interface utilisateur (notifySocketCreated()) et une autre fois pas (notifyGameRegistered()). – omarcin

0

La fonction qui modifie l'interface utilisateur doit se trouver dans l'activité propriétaire de l'interface utilisateur.

Ce lien devrait vous aider: http://android-developers.blogspot.com/2009/05/painless-threading.html

+0

Oh et j'ai oublié de mentionner. La méthode devrait également être appelée à partir de l'activité qui possède l'interface utilisateur – Sid

+0

Merci pour le lien, mais je l'ai déjà vu auparavant. Je crois que AsyncTask serait une exagération dans la situation décrite. Ce n'est pas vraiment important pour moi de savoir comment réparer mon code (je me souviens que le code de retour dans Runnables avait aidé), mais je suis curieux de savoir pourquoi une instance de Handler était dans le thread et une autre fois non. La documentation indique que "chaque instance de gestionnaire est associée à un seul thread et à la file d'attente de messages de ce thread." ... – omarcin

1

Je sais que c'est un peu en retard - mais le problème est que vous avez appelé dispatchMessage().

La méthode correcte est sendMessage().

dispatchMessage() appellera handleMessage() sur le même fil.

Je suppose que le problème n'est pas que votre gestionnaire soit sur le mauvais thread - mais que l'interface utilisateur essaie de créer un gestionnaire quelque part dans la méthode onHandle(). Parce que onHandle() est appelé sur le mauvais thread, vous obtenez une exception.

/** 
* Handle system messages here. 
*/ 
public void dispatchMessage(Message msg) 
{ 
    if (msg.callback != null) { 
     handleCallback(msg); 
    } else { 
     handleMessage(msg); 
    } 
} 
Questions connexes