52 votes

CalledFromWrongThreadException : Seul le thread d'origine qui a créé une hiérarchie de vues peut toucher les vues.

J'ai un problème avec l'erreur suivante dans Android :

CalledFromWrongThreadException; : Seulement le thread original qui a créé une hiérarchie de vues peut toucher ses vues

Il semble que cela se produise lorsque j'essaie de mettre à jour un TextView dans mon activité, l'appel pour mettre à jour le TextView se fait à partir de mon activité mais je reçois toujours l'erreur ci-dessus.

Je l'ai comme ça :

onCreate() -met en place les boutons et la vue du texte.

onStateChange() - un écouteur pour les notifications sur les changements d'état, lorsqu'il reçoit une notification si le TextView est modifié pour afficher un texte différent.

Lorsque je reçois la notification d'un nouveau texte, j'essaie de modifier le TextView comme suit :

((TextView)findViewById(R.id.title)).setText("Some Text");

Mais je reçois l'erreur ci-dessus.

En cherchant sur Google, il semble que je doive utiliser un gestionnaire pour modifier le TextView ou peut-être utiliser AsyncTask ?

Quelqu'un peut-il expliquer lequel des deux serait le mieux à utiliser et pourquoi ?

EDIT : AJOUT DE BOUTS DE CODE :


     public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);

            requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);  

            setContentView(R.layout.my);

            getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.my_title);  

            ((TextView)findViewById(R.id.time)).setText("Hello Text");

            findViewById(R.id.keyboardimage).setOnClickListener(new OnClickListener() {
                public void onClick(View v) {

                    Intent dialIntent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:"));
                    startActivity(dialIntent);

                        dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.FLAG_SOFT_KEYBOARD));
                        dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK));       
                }
        });

     }

//CallBacks from running Service

private final ICallDialogActivity.Stub iCallDialogActivity = new ICallDialogActivity.Stub(){

@Override
public void onStateChanged(int callState)
                throws RemoteException {    
            switch(callState){
            case GlobalData.CALL_STATUS_IDLE:

                break;

            case GlobalData.CALL_STATUS_DISCONNECTING:
                byeSetup();
                break;
    } 

};

public void byeSetup(){

            ((TextView)findViewById(R.id.time)).setText("Bye Text");

            findViewById(R.id.keyboardimage).setOnClickListener(new OnClickListener() {
                public void onClick(View v) {
                    //Void the Button
                }});
}

1 votes

Vous êtes dans une sous-classe ? onStateChange est surchargé où ?

0 votes

Bonjour Pentium10, il est surchargé via une interface AIDL et communique avec un service, le service sera notifié d'un changement et dira ensuite à l'activité de mettre à jour son TextView en fonction de cela. J'ai ajouté des extraits de code pour mieux démontrer ce que j'essaie de faire. L'erreur semble apparaître de façon très aléatoire et apparaît aussi bien lorsque l'activité est au premier plan que lorsqu'elle ne l'est pas.

1 votes

Duplicata possible de CalledFromWrongThreadException

82voto

willcodejavaforfood Points 20365

On dirait que vous êtes sur le mauvais fil. Essayez d'utiliser un Handler pour mettre à jour l'interface graphique sur le bon thread. Voir Gestion des opérations coûteuses dans le thread de l'interface utilisateur exemple d'Android.com. En gros, vous devez envelopper byeSetup dans un Runnable et l'invoquer avec un Handler instance.

Handler refresh = new Handler(Looper.getMainLooper());
refresh.post(new Runnable() {
    public void run()
    {
        byeSetup();
    }
});

6 votes

On dirait que je n'ai pas à me tuer. Ouf

0 votes

Je pense que la réponse de Keshav est meilleure.

0 votes

Est-ce mieux que d'utiliser runOnUiThread() ? Je vois que nous n'avons pas besoin d'une référence à l'activité. Y a-t-il d'autres avantages à cette solution ?

7voto

Keshav Gera Points 1892

Lorsque le changement implique le thread principal ( UiThread ). Utilisez-le à l'intérieur d'un autre Thread pour modifier n'importe quelle vue.

runOnUiThread(new Runnable() {
    @Override
    public void run() {

      // TODO your Code 
        et_Pass.setText("");
    }
});

1 votes

Si vous utilisez Fragment, vous pouvez appeler cette méthode par getActivity.runOnUiThread().......

3voto

Kevin Points 150

Développant la réponse de willcodejavaforfood pour plus de clarté et de mise en œuvre...

J'ai réussi à le faire fonctionner et voici comment j'ai procédé. J'exécute plusieurs threads de traitement dans un service, donc les autres solutions qui s'exécutent dans l'activité ne fonctionnent pas, comme runOnUiThread(new Runnable() {}...

Mettez-le en haut de votre classe de service pour qu'il soit accessible partout dans cette classe :

Handler handler;

Mettez ceci dans la méthode onCreate de votre classe de service ou quelque chose qui se charge sur le fil principal du service.

handler= new Handler(Looper.getMainLooper());

Mettez-le dans votre thread supplémentaire pour "renvoyer" le code à exécuter dans l'interface utilisateur ou l'interface de service (quel que soit son nom) :

handler.post(new Runnable() {
    public void run() {
        playNext(); //or whatever method you want to call thats currently not working
    }
});

2voto

Joseph Selvaraj Points 566

Pour les autres, il suffit de remplacer byeSetup() ; par vos instructions ou méthodes de code. byeSetup() est un exemple de méthode. Nous espérons qu'il vous fera gagner du temps.

1voto

Jaroslav Záruba Points 1059

Une autre approche, cette fois-ci en utilisant android.os.Message

Avoir android.os.Handler défini comme un champ dans votre activité :

private final Handler myTextHandler = new Handler(new Handler.Callback() {
    @Override
    public boolean handleMessage(Message stringMessage) {
        textView.append((String) stringMessage.obj);
        return true;
    }
});

Puis alimentez-le à partir de votre autre fil comme ceci :

Message stringMessage = Message.obtain(myTextHandler);
stringMessage.obj = "Hello!";
stringMessage.sendToTarget();

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X