Om de GUI vanuit andere threads bij te werken, zijn er in principe twee hoofdbenaderingen:
-
Gebruik java.lang.Runnable met een van deze methoden:
Activity.runOnUiThread(Runnable) View.post(Runnable) View.postDelayed(Runnable, long) Handler.post(Runnable)
-
Gebruik android.os.Message:
Handler.sendMessage(Message) / Handler.handleMessage(Message)
Je kunt ook AsyncTask gebruiken, maar mijn vraag is meer gericht op het gebruik van een heel eenvoudig onderdeel. Laten we eens kijken hoe het zou worden gedaan met beide benaderingen:
-
Uitvoerbare bestanden gebruiken:
TextViev tv = ...; final String data = "hello"; Runnable r = new Runnable() { @Override public void run(){ tv.setText(data); } }; //Now call Activity.runOnUiThread(r) or handler.post(r), ...
-
Berichten gebruiken:
Message m = handler.obtainMessage(UPDATE_TEXT_VIEW, "hello"); handler.sendMessage(m); //Now on handler implementation: @Override public void handleMessage(Message msg) { if(msg.what == UPDATE_TEXT_VIEW){ String s = (String) msg.obj; tv.setText(data); } ... //other IFs? }
IMHO, Berichten zijn niet de juiste keuze omdat:
- Niet gemakkelijk te begrijpen voor nieuwe niet-android-programmeurs (handler haakt aan de draad tijdens de constructie).
- De payload van het object moet Parcellable zijn als het bericht de procesgrenzen overschrijdt.
- Berichten worden hergebruikt (foutgevoelig als ze niet goed worden opgeschoond?)
- De handler heeft een dubbele rol (hij verzendt berichten, maar behandelt ze ook)
- Berichtkenmerken zijn openbaar, maar bieden ook getter/setter.
Aan de andere kant volgen Runnables het bekende commandopatroon en zijn ze programmeervriendelijker en leesbaarder.
Dus wat zijn de voordelen van het gebruik van Berichten boven Runnables? Worden berichten naar de achtergrond geduwd in moderne Android-programmering? Is er iets dat u met Berichten kunt doen wat niet met Runnables kan?
Bij voorbaat dank.
Antwoord 1, autoriteit 100%
Ik zou zeggen dat er weinig verschil is tussen het gebruik van een Message
versus een Runnable
. Het zal vooral neerkomen op persoonlijke voorkeur. Waarom? Als je naar de broncode kijkt, zul je zien dat het plaatsen van een Runnable
exact hetzelfde berichtmechanisme gebruikt. Het voegt eenvoudig de Runnable
toe aan een Message
en verzendt dat.
4.4.2 Broncode
public final boolean post(Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
Ref: Grep-code – Handler
Antwoord 2, autoriteit 68%
Messages
kunnen opnieuw worden gebruikt, zodat er minder objecten worden gemaakt en minder GC. Je krijgt ook minder lessen en anonieme typen.
Een groot voordeel is dat een klas die een Message
naar een Handler
stuurt, niets hoeft te weten over de implementatie van die Message
. Dat kan helpen bij inkapseling, afhankelijk van waar het wordt gebruikt.
Overweeg ten slotte het verschil in netheid tussen
mHandler.obtainMessage(DO_STUFF, foo).sendToTarget();
vs
final Foo tempFoo = foo;
mHandler.post(new Runnable(){
@Override
public void run(){
doStuff(tempFoo);
}
};
Als u meerdere plaatsen heeft waar u doStuff()
zou moeten gebruiken, is de eerste VEEL leesbaarder en heeft u minder codeduplicatie.
Antwoord 3, autoriteit 18%
Handler
-interface biedt veel meer functionaliteit dan runOnUiThread()
, volgens docs:
Een Handler kan op twee manieren worden gebruikt:
(1) om berichten en runnables te plannen die op een bepaald moment in de toekomst moeten worden uitgevoerd
(2) om een actie in een wachtrij te plaatsen die moet worden uitgevoerd op een andere thread dan de uwe.
runOnUiThread
doet alleen een subset van (2). dat wil zeggen “een actie in de wachtrij plaatsen die moet worden uitgevoerd op UI-thread“
Dus IMO, tenzij je die extra functies nodig hebt, is runOnUiThread
voldoende en heeft de voorkeur.
Antwoord 4, autoriteit 9%
Ik geef de voorkeur aan Runnable
boven Message
. Ik denk dat code die Runnable
gebruikt veel duidelijker is dan Message
, omdat de gebeurtenisafhandelingscode heel dicht bij de gebeurtenis ligt. U kunt ook de overhead van het definiëren van constanten en schakelen tussen gevallen vermijden.
En ik denk niet dat het gebruik van Runnable
de inkapseling schendt. U kunt de code in Runnable.run()
extraheren in een andere methode in de outer class, bijvoorbeeld on...Event()
, of zelfs in een EventHandler
-object. Beide manieren zijn veel duidelijker dan het gebruik van Message
, vooral wanneer je winkelverwijzingen nodig hebt in Message
, omdat het gebruik van Runnable
downcasting van msg.obj
. En het naamloze veld msg.obj
is ook foutgevoelig en soms inefficiënt om te begrijpen.
En Runnable
kan ook opnieuw worden gebruikt door het op te slaan als een veld.