Comment utilisons-nous runOnUiThread dans Android?

157

Je suis nouveau sur Android et j'essaie d'utiliser UI-Thread, j'ai donc écrit une activité de test simple. Mais je pense que j'ai mal compris quelque chose, car en cliquant sur le bouton, l'application ne répond plus

public class TestActivity extends Activity {

    Button btn;
    int i = 0;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        btn = (Button)findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                runThread();
            }
        });
    }

    private void runThread(){
        runOnUiThread (new Thread(new Runnable() {  
            public void run() {
                while(i++ < 1000){
                    btn.setText("#"+i);
                    try {
                        Thread.sleep(300);
                    } 
                    catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
             }
        }));
    }
}
user1049280
la source

Réponses:

204

Ci-dessous se trouve l'extrait de runThreadfonction corrigé .

private void runThread() {

    new Thread() {
        public void run() {
            while (i++ < 1000) {
                try {
                    runOnUiThread(new Runnable() {

                        @Override
                        public void run() {
                            btn.setText("#" + i);
                        }
                    });
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }.start();
}
Vipul Shah
la source
Cela n'a-t-il pas été ramassé presque immédiatement? Vous devez probablement garder une référence à la discussion ()
Nick
14
@Nick: le garbage collector surveille également la pile, c'est-à-dire que lorsque le thread est en cours d'exécution, il ne sera pas GC.
Miro Kropacek
@Vipul, j'avais une question sur la rotation du téléphone: je veux qu'une fois que je fais pivoter mon téléphone, ce fil s'exécute et qu'aucun nouveau fil ne soit créé. Pouvez-vous fournir des conseils sur la façon d'empêcher la création d'un nouveau fil une fois que le téléphone est tourné?
user1836957
89

Enveloppez-le simplement en tant que fonction, puis appelez cette fonction à partir de votre thread d'arrière-plan.

public void debugMsg(String msg) {
    final String str = msg;
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            mInfo.setText(str);
        }
    });
}

la source
3
voté pour avoir montré comment accéder aux données dans la portée externe ( final)
mariotomo
27

Vous l'avez dos à devant. Votre clic sur le bouton entraîne un appel à runOnUiThread(), mais ce n'est pas nécessaire, car le gestionnaire de clics est déjà en cours d'exécution sur le thread d'interface utilisateur. Ensuite, votre code dansrunOnUiThread() lance un nouveau thread d'arrière-plan, dans lequel vous essayez d'effectuer des opérations d'interface utilisateur, qui échouent ensuite.

Au lieu de cela, lancez simplement le thread d'arrière-plan directement à partir de votre gestionnaire de clics. Ensuite, encapsulez les appels btn.setText()dans un appel à runOnUiThread().

Graham Borland
la source
S'il est vrai que le gestionnaire de clics est déjà dans le thread d'interface utilisateur, un appel à runOnUiThread()n'est pas nécessaire mais il devrait être inoffensif. Le Javadoc de cette méthode indique "Exécute l'action spécifiée sur le thread d'interface utilisateur. Si le thread actuel est le thread d'interface utilisateur, l'action est exécutée immédiatement. Si le thread actuel n'est pas le thread d'interface utilisateur, l'action est publiée dans la file d'attente d'événements. du thread de l'interface utilisateur. "
k2col
15
runOnUiThread(new Runnable() {
                public void run() {
                //Do something on UiThread
            }
        });
Terranologie
la source
10

Il existe plusieurs techniques utilisant runOnUiThread (), voyons tout

Ceci est mon fil principal (fil d'interface utilisateur) appelé AndroidBasicThreadActivity et je vais le mettre à jour à partir d'un fil de travail de différentes manières -

public class AndroidBasicThreadActivity extends AppCompatActivity
{
    public static TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_android_basic_thread);

        textView = (TextView) findViewById(R.id.textview);

        MyAndroidThread myTask = new MyAndroidThread(AndroidBasicThreadActivity.this);
        Thread t1 = new Thread(myTask, "Bajrang");
        t1.start();
    }
}

1.) En passant l'instance d'Activity comme argument sur le thread de travail

class MyAndroidThread implements Runnable
{
    Activity activity;
    public MyAndroidThread(Activity activity)
    {
        this.activity = activity;
    }
    @Override
    public void run()
    {

        //perform heavy task here and finally update the UI with result this way - 
        activity.runOnUiThread(new Runnable()
        {
            @Override
            public void run()
            {
                AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread.");
            }
        });
    }
}

2.) En utilisant la méthode post (Runnable runnable) de View dans le thread de travail

class MyAndroidThread implements Runnable
{
    Activity activity;
    public MyAndroidThread(Activity activity)
    {
        this.activity = activity;
    }
    @Override
    public void run()
    {
     //perform heavy task here and finally update the UI with result this way - 
       AndroidBasicThreadActivity.textView.post(new Runnable()
      { 
        @Override
        public void run()
        {
            AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread.");
        }
    });

    }
}

3.) En utilisant la classe Handler du package android.os Si nous n'avons pas le contexte (this / getApplicationContext ()) ou l'instance Activity (AndroidBasicThreadActivity.this), nous devons utiliser la classe Handler comme ci-dessous -

class MyAndroidThread implements Runnable
{
    Activity activity;
    public MyAndroidThread(Activity activity)
    {
        this.activity = activity;
    }
    @Override
   public void run()
  {
  //perform heavy task here and finally update the UI with result this way - 
  new Handler(Looper.getMainLooper()).post(new Runnable() {
        public void run() {
            AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread.");
        }
    });
  }
}
Bajrang Hudda
la source
Merci .. Au lieu de simplement répéter à propos de runOnUIThread de l'activité, vous avez mentionné toutes les façons possibles de l'invoquer ..
arun
Merci .. Au lieu de simplement répéter à propos de runOnUIThread de l'activité, vous avez mentionné toutes les façons possibles de l'invoquer ..
arun
6

Si vous utilisez un fragment, écrivez simplement

getActivity().runOnUiThread(new Runnable() {
    @Override
    public void run() {
        // Do something on UiThread
    }
});
Shivam Yadav
la source
1

ton ceci:

@UiThread
    public void logMsg(final String msg) {
        new Handler(Looper.getMainLooper()).post(new Runnable() {
            @Override
            public void run() {
                Log.d("UI thread", "I am the UI thread");


            }
        });
    }
MrGuy
la source
1

Nous utilisons Worker Thread pour rendre les applications plus fluides et éviter les ANR. Nous pouvons avoir besoin de mettre à jour l'interface utilisateur après le processus lourd dans Work Tread. L'interface utilisateur ne peut être mise à jour qu'à partir de UI Thread. Dans de tels cas, nous utilisons Handler ou runOnUiThread ont tous deux une méthode d'exécution Runnable qui s'exécute dans UI Thread. La méthode onClick s'exécute dans le thread d'interface utilisateur, vous n'avez donc pas besoin d'utiliser runOnUiThread ici.

Utilisation de Kotlin

En activité,

this.runOnUiThread {
      // Do stuff
}

De Fragment,

activity?.runOnUiThread {
      // Do stuff
}

Utilisation de Java ,

this.runOnUiThread(new Runnable() {
     void run() {
         // Do stuff
     }
});
Varun Chandran
la source
0

Vous pouvez utiliser à partir de cet exemple:

Dans l'exemple suivant, nous allons utiliser cette fonctionnalité pour publier le résultat d'une recherche de synonymes qui a été traitée par un fil d'arrière-plan.

Pour atteindre l'objectif lors du rappel de l'activité OnCreate, nous allons configurer onClickListener pour exécuter searchTask sur un thread créé.

Lorsque l'utilisateur clique sur le bouton Rechercher, nous allons créer une classe anonyme Runnable qui recherche le mot tapé dans R.id.wordEt EditText et démarre le thread pour exécuter Runnable.

Une fois la recherche terminée, nous créerons une instance de Runnable SetSynonymResult pour publier le résultat sur le synonyme TextView via le fil d'interface utilisateur.

Cette technique n'est parfois pas la plus pratique, surtout lorsque nous n'avons pas accès à une instance Activity; Par conséquent, dans les chapitres suivants, nous allons discuter de techniques plus simples et plus propres pour mettre à jour l'interface utilisateur à partir d'une tâche de calcul en arrière-plan.

public class MainActivity extends AppCompatActivity {

    class SetSynonymResult implements Runnable {
        String synonym;

        SetSynonymResult(String synonym) {
            this.synonym = synonym;
        }

        public void run() {
            Log.d("AsyncAndroid", String.format("Sending synonym result %s on %d",
                    synonym, Thread.currentThread().getId()) + " !");
            TextView tv = (TextView) findViewById(R.id.synonymTv);
            tv.setText(this.synonym);
        }
    }

    ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button search = (Button) findViewById(R.id.searchBut);
        final EditText word = (EditText) findViewById(R.id.wordEt);
        search.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Runnable searchTask = new Runnable() {
                    @Override
                    public void run() {
                        String result = searchSynomim(word.getText().toString());
                        Log.d("AsyncAndroid", String.format("Searching for synonym for %s on %s",
                                word.getText(), Thread.currentThread().getName()));
                        runOnUiThread(new SetSynonymResult(result));
                    }
                };
                Thread thread = new Thread(searchTask);
                thread.start();
            }
        });

    }

    static int i = 0;

    String searchSynomim(String word) {
        return ++i % 2 == 0 ? "fake" : "mock";
    }
}

La source :

programmation asynchrone android Helder Vasconcelos


la source
0

Voici comment je l'utilise:

runOnUiThread(new Runnable() {
                @Override
                public void run() {
                //Do something on UiThread
            }
        });
Josh Aquino
la source
0
  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        gifImageView = (GifImageView) findViewById(R.id.GifImageView);
        gifImageView.setGifImageResource(R.drawable.success1);

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //dummy delay for 2 second
                    Thread.sleep(8000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                //update ui on UI thread
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        gifImageView.setGifImageResource(R.drawable.success);
                    }
                });

            }
        }).start();

    }
Keshav Gera
la source
0

Essaye ça: getActivity().runOnUiThread(new Runnable...

C'est parce que:

1) cela implicite dans votre appel à runOnUiThread fait référence à AsyncTask , pas à votre fragment.

2) Le fragment n'a pas runOnUiThread.

Cependant, Activity le fait.

Notez que Activity exécute simplement le Runnable si vous êtes déjà sur le thread principal, sinon il utilise un Handler. Vous pouvez implémenter un Handler dans votre fragment si vous ne voulez pas vous soucier du contexte, c'est en fait très simple:

// Une instance de classe

private Handler mHandler = new Handler(Looper.getMainLooper());

// n'importe où ailleurs dans votre code

mHandler.post(<your runnable>);

// ^ ceci sera toujours exécuté sur la prochaine boucle d'exécution sur le thread principal.

Pradeep Kumar
la source