web-dev-qa-db-fra.com

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

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

CalledFromWrongThreadException ;: Only le thread d'origine qui a créé un hiérarchie de vue peut toucher ses vues

Il semble que cela se produise lorsque j'essaie de mettre à jour une vue de texte dans mon activité. L'appel à mettre à jour le TextView provient de mon activité, mais j'obtiens toujours l'erreur ci-dessus.

Je l'ai comme ça:

onCreate () - configure les boutons et la vue texte.

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

Lorsque je reçois une notification d'un nouveau texte, j'essaie de modifier le TextView de la manière suivante:

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

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

De googler, il semble que je devrais utiliser un gestionnaire pour modifier le TextView ou peut-être utiliser AsyncTask?

Quelqu'un pourrait-il expliquer lequel serait le mieux à utiliser et pourquoi?

EDIT: AJOUTS SNIPPETS 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
                }});
}
45
Donal Rafferty

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

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

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

J'ai réussi à faire fonctionner cela et voici comment je l'ai fait. J'exécute plusieurs threads de traitement dans un service afin que les autres solutions exécutées dans Activity ne fonctionnent pas, comme runOnUiThread (new Runnable () {} ...

Placez ceci au sommet de votre classe de service afin qu'il soit accessible partout dans cette classe:

Handler handler;

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

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

Mettez ceci dans votre fil supplémentaire dans le code "post back" pour s'exécuter dans l'interface utilisateur ou dans l'interface utilisateur du service (quel que soit le nom de l'appelant):

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

Pour les autres, remplacez simplement byeSetup (); avec vos instructions de code ou méthodes. byeSetup () est un exemple de méthode. J'espère que cela vous fera gagner du temps. 

2
Joseph Selvaraj

Cette méthode est juste pour Activités et est préférable lorsque le changement implique le fil 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
Keshav Gera

Une autre approche, utilisant cette fois Android.os.Message

Définissez Android.os.Handler comme champ de 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();
0
Jaroslav Záruba

Vous pouvez utiliser la méthode post intégrée de view pour mettre à jour le contenu d'un autre fil, comme j'utilise le texte de modification dans kotlin.

address_box.post { address_box.text="my text"}
0
Nero