Wie verwenden wir runOnUiThread in Android?

157

Ich bin neu in Android und versuche, den UI-Thread zu verwenden. Daher habe ich eine einfache Testaktivität geschrieben. Aber ich glaube, ich habe etwas falsch verstanden, denn beim Klicken auf die Schaltfläche reagiert die App nicht mehr

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
quelle

Antworten:

204

Unten ist ein korrigierter runThreadFunktionsausschnitt aufgeführt.

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
quelle
War das nicht Müll, der fast sofort gesammelt wurde? Wahrscheinlich müssen Sie einen Verweis auf den Thread ()
Nick
14
@Nick: Der Garbage Collector überwacht auch den Stack, dh wenn der Thread ausgeführt wird, wird er nicht GC'ed.
Miro Kropacek
@Vipul, ich hatte eine Frage zur Telefonrotation: Ich möchte, dass dieser Thread ausgeführt wird, sobald ich mein Telefon drehe, und es wird kein neuer Thread erstellt. Können Sie einige Hinweise geben, wie Sie verhindern können, dass nach dem Drehen des Telefons ein neuer Thread erstellt wird?
user1836957
89

Wickeln Sie es einfach als Funktion ein und rufen Sie diese Funktion in Ihrem Hintergrund-Thread auf.

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

quelle
3
upvoted für das Zeigen, wie man auf Daten im äußeren Bereich final
zugreift
27

Sie haben es von hinten nach vorne. Ihr Schaltflächenklick führt zu einem Aufruf von runOnUiThread(), dies ist jedoch nicht erforderlich, da der Klick-Handler bereits auf dem UI-Thread ausgeführt wird. Anschließend runOnUiThread()startet Ihr Code in einen neuen Hintergrundthread, in dem Sie versuchen, UI-Vorgänge auszuführen , die dann fehlschlagen.

Starten Sie stattdessen einfach den Hintergrund-Thread direkt von Ihrem Click-Handler. Schließen Sie dann die Anrufe in btn.setText()einen Anruf an ein runOnUiThread().

Graham Borland
quelle
Der Klick-Handler befindet sich zwar bereits im UI-Thread, ein Aufruf von runOnUiThread()ist jedoch nicht erforderlich, sollte jedoch harmlos sein. Das Javadoc für diese Methode lautet "Führt die angegebene Aktion im UI-Thread aus. Wenn der aktuelle Thread der UI-Thread ist, wird die Aktion sofort ausgeführt. Wenn der aktuelle Thread nicht der UI-Thread ist, wird die Aktion in die Ereigniswarteschlange gestellt des UI-Threads. "
k2col
15
runOnUiThread(new Runnable() {
                public void run() {
                //Do something on UiThread
            }
        });
Terranologie
quelle
10

Es gibt verschiedene Techniken, die runOnUiThread () verwenden. Lassen Sie uns alle sehen

Dies ist mein Hauptthread (UI-Thread) namens AndroidBasicThreadActivity, und ich werde ihn auf verschiedene Weise von einem Arbeitsthread aus aktualisieren -

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.) Durch Übergeben der Instanz von Activity als Argument für den Arbeitsthread

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.) Verwenden Sie die Post-Methode (Runnable Runnable) von View im Worker-Thread

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.) Mit der Handler-Klasse aus dem android.os-Paket Wenn wir nicht über den Kontext (this / getApplicationContext ()) oder die Instanz von Activity (AndroidBasicThreadActivity.this) verfügen, müssen wir die Handler-Klasse wie folgt verwenden:

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
quelle
Vielen Dank. Anstatt nur über runOnUIThread der Aktivität zu wiederholen, haben Sie alle möglichen Möglichkeiten zum Aufrufen erwähnt.
Arun
Vielen Dank. Anstatt nur über runOnUIThread der Aktivität zu wiederholen, haben Sie alle möglichen Möglichkeiten zum Aufrufen erwähnt.
Arun
6

Wenn Sie in Fragment verwenden, schreiben Sie einfach

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

dein dies:

@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
quelle
1

Wir verwenden Worker Thread, um Apps reibungsloser zu gestalten und ANRs zu vermeiden. Möglicherweise müssen wir die Benutzeroberfläche nach dem umfangreichen Prozess in Worker Tread aktualisieren. Die Benutzeroberfläche kann nur über den UI-Thread aktualisiert werden. In solchen Fällen verwenden wir Handler oder runOnUiThread. Beide haben eine Runnable-Ausführungsmethode, die im UI-Thread ausgeführt wird. Die onClick-Methode wird im UI-Thread ausgeführt, sodass runOnUiThread hier nicht verwendet werden muss.

Kotlin benutzen

Während der Aktivität,

this.runOnUiThread {
      // Do stuff
}

Aus Fragment,

activity?.runOnUiThread {
      // Do stuff
}

Mit Java ,

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

Sie können aus diesem Beispiel verwenden:

Im folgenden Beispiel verwenden wir diese Funktion, um das Ergebnis einer Synonym-Suche zu veröffentlichen, die von einem Hintergrund-Thread verarbeitet wurde.

Um das Ziel während des OnCreate-Aktivitätsrückrufs zu erreichen, richten wir onClickListener so ein, dass searchTask für einen erstellten Thread ausgeführt wird.

Wenn der Benutzer auf die Schaltfläche Suchen klickt, wird eine anonyme Runnable-Klasse erstellt, die nach dem in R.id.wordEt EditText eingegebenen Wort sucht und den Thread zum Ausführen von Runnable startet.

Nach Abschluss der Suche erstellen wir eine Instanz von Runnable SetSynonymResult, um das Ergebnis über den UI-Thread wieder im Synonym TextView zu veröffentlichen.

Diese Technik ist manchmal nicht die bequemste, insbesondere wenn wir keinen Zugriff auf eine Aktivitätsinstanz haben. Daher werden wir in den folgenden Kapiteln einfachere und sauberere Techniken zum Aktualisieren der Benutzeroberfläche von einer Hintergrund-Computeraufgabe diskutieren.

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";
    }
}

Quelle :

asynchrone Android-Programmierung Helder Vasconcelos


quelle
0

So benutze ich es:

runOnUiThread(new Runnable() {
                @Override
                public void run() {
                //Do something on UiThread
            }
        });
Josh Aquino
quelle
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
quelle
0

Versuche dies: getActivity().runOnUiThread(new Runnable...

Es ist, weil:

1) Das implizite Ergebnis in Ihrem Aufruf von runOnUiThread bezieht sich auf AsyncTask , nicht auf Ihr Fragment.

2) Fragment hat kein runOnUiThread.

Aktivität jedoch.

Beachten Sie, dass Activity die ausführbare Datei nur ausführt, wenn Sie sich bereits im Hauptthread befinden. Andernfalls wird ein Handler verwendet. Sie können einen Handler in Ihrem Fragment implementieren, wenn Sie sich nicht um den Kontext kümmern möchten. Es ist eigentlich sehr einfach:

// Eine Klasseninstanz

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

// irgendwo anders in deinem Code

mHandler.post(<your runnable>);

// ^ Dies wird immer bei der nächsten Ausführungsschleife im Hauptthread ausgeführt.

Pradeep Kumar
quelle