Czy z punktu widzenia uruchamiania kodu w wątku interfejsu użytkownika występuje jakaś różnica między:
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
Log.d("UI thread", "I am the UI thread");
}
});
lub
MainActivity.this.myView.post(new Runnable() {
public void run() {
Log.d("UI thread", "I am the UI thread");
}
});
i
private class BackgroundTask extends AsyncTask<String, Void, Bitmap> {
protected void onPostExecute(Bitmap result) {
Log.d("UI thread", "I am the UI thread");
}
}
Odpowiedzi:
Żadne z nich nie jest dokładnie takie samo, chociaż wszystkie będą miały taki sam efekt netto.
Różnica między pierwszym a drugim polega na tym, że jeśli zdarzy ci się być w głównym wątku aplikacji podczas wykonywania kodu, pierwszy (
runOnUiThread()
) wykonaRunnable
natychmiast. Drugi (post()
) zawsze umieszczaRunnable
koniec kolejki zdarzeń, nawet jeśli jesteś już w głównym wątku aplikacji.Trzeci, zakładając, że utworzysz i wykonasz instancję
BackgroundTask
, będzie marnował dużo czasu na pobieranie wątku z puli wątków, aby wykonać domyślny brak operacjidoInBackground()
, zanim ostatecznie zrobisz to, co wynosipost()
. Jest to zdecydowanie najmniej efektywny z tych trzech. Użyj,AsyncTask
jeśli faktycznie masz pracę do zrobienia w wątku w tle, nie tylko na użytekonPostExecute()
.źródło
AsyncTask.execute()
wymaga to i tak wywoływania z wątku interfejsu użytkownika, co czyni tę opcję bezużyteczną w przypadku użycia po prostu uruchomienia kodu w wątku interfejsu z wątku tła, chyba że przeniesiesz całą pracę w tle dodoInBackground()
i będziesz używaćAsyncTask
poprawnie.AsyncTask
z wątku interfejsu użytkownika?boolean isUiThread = (Looper.getMainLooper().getThread() == Thread.currentThread());
Looper.getMainLooper().isCurrentThread
Podoba mi się ten z komentarza HPP , można go używać w dowolnym miejscu bez żadnego parametru:
źródło
Istnieje czwarty sposób użycia
Handler
źródło
new Handler(Looper.getMainLooper()).post(r)
, co jest preferowanym sposobem, ponieważLooper.getMainLooper()
wykonuje statyczne wywołanie main, podczas gdypostOnUiThread()
musi mieć instancjęMainActivity
w zakresie.Odpowiedź Pomber jest do zaakceptowania, jednak nie jestem wielkim fanem wielokrotnego tworzenia nowych obiektów. Najlepszymi rozwiązaniami są zawsze te, które próbują złagodzić problem pamięci. Tak, istnieje automatyczne zbieranie śmieci, ale zachowanie pamięci w urządzeniu mobilnym mieści się w zakresie najlepszych praktyk. Poniższy kod aktualizuje TextView w usłudze.
Można go używać z dowolnego miejsca takiego:
źródło
The best solutions are always the ones that try to mitigate memory hog
. Istnieje wiele innych kryteriówbest
, a to ma delikatny zapachpremature optimization
. Oznacza to, że jeśli nie wiesz, że nazywasz to wystarczająco, że liczba utworzonych obiektów stanowi problem (w porównaniu z dziesięcioma tysiącami innych sposobów, w jaki twoja aplikacja prawdopodobnie tworzy śmieci), to może byćbest
napisanie najprostszego (najłatwiejszego do zrozumienia ) i przejdź do innego zadania.textViewUpdaterHandler
lepiej byłoby nazwać coś podobnegouiHandler
lubmainHandler
, ponieważ jest ogólnie przydatne dla każdego posta w głównym wątku interfejsu użytkownika; wcale nie jest powiązany z twoją klasą TextViewUpdater. Odsunąłbym go od reszty tego kodu i wyjaśniłbym, że można go użyć gdzie indziej ... Reszta kodu jest wątpliwa, ponieważ aby uniknąć dynamicznego tworzenia jednego obiektu, przerywasz to, co może być pojedynczym wywołaniem dwa krokisetText
ipost
polegają na długotrwałym obiekcie, którego używasz jako tymczasowego. Niepotrzebna złożoność i bezpieczeństwo wątków. Niełatwe w utrzymaniu.uiHandler
itextViewUpdater
, a następnie poprawić swoją klasę przez zmianępublic void setText(String txt, Handler uiHandler)
oraz dodanie metodą liniowąuiHandler.post(this);
Następnie rozmówcy można zrobić w jednym kroku:textViewUpdater.setText("Hello", uiHandler);
. Następnie, jeśli w przyszłości ma być bezpieczny wątek, metoda może owinąć swoje instrukcje wewnątrz blokadyuiHandler
, a osoba dzwoniąca pozostaje niezmieniona.Od Androida P możesz używać
getMainExecutor()
:Z dokumentacji dla programistów Androida :
Z CommonsBlog :
źródło
Jeśli potrzebujesz użyć we fragmencie, powinieneś użyć
zamiast
Ponieważ w niektórych sytuacjach, takich jak fragment pagera, wystąpi wyjątek wskaźnika zerowego
źródło
cześć chłopaki, to jest podstawowe pytanie, jak mówię
użyj Handler
źródło
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
jeśli nie jest wywoływane z wątku interfejsu użytkownika.