Comment les classes handler fonctionnent sur Android
je suis nouveau sur android et je lisais les applications de démonstration sur le site officiel android. Et je suis tombé sur une méthode de Handler
classe appelé comme postDelayed(Runnable r, long milliseconds)
.
quelqu'un peut-il expliquer ce que fait cette méthode ?
3 réponses
vous pouvez voir la documentation .
mais pour comprendre les docs, vous devez d'abord comprendre plusieurs concepts: Message, File D'attente de Message, Handler et Looper , et leur relation .
ce qui suit illustre comment Looper fonctionne, il montre que le looper est un objet local de fil et sa relation avec MessageQueue:
class Looper{
public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
public static final void loop() {
Looper me = myLooper();
MessageQueue queue = me.mQueue;
while (true) {
Message msg = queue.next(); // might block
if (msg != null) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return;
}
msg.target.dispatchMessage(msg);
msg.recycle();
}
}
}
}
Plusieurs remarques:
Looper est un fil objet local tel que chaque fil a un looper. Chaque looper est associé à une file d'attente de messages. Le looper reçoit continuellement des messagese ("tâches"," commandes " ou tout ce que vous aimez appeler) de la file d'attente, et envoie le message à sa cible, qui est un handler pour gérer ce Messaging (par exemple en rappelant une exécutable contenue dans le message). Quand il n'y a plus de messages dans la file d'attente, le thread bloque jusqu'à ce qu'il y en ait de nouveaux. message. Pour arrêter un Looper, vous devez appeler quit() dessus (ce qui n'arrête probablement pas la boucle immédiatement, mais place plutôt un drapeau privé qui est vérifié périodiquement à partir de la boucle, signalant à l'it d'arrêter).
Android framework fournit la classe Handler pour simplifier les choses. Lorsque vous créez une instance Handler, elle est (par défaut) liée au Looper déjà attaché au thread courant. (Le Handler sait ce Looper à attacher à parce que nous avons appelé préparer() plus tôt, qui a stocké une référence au Looper dans un ThreadLocal.)
avec un gestionnaire, vous pouvez simplement appeler post() pour" mettre un message dans la file d'attente du fil " (pour ainsi dire). Le Gestionnaire va s'occuper de tous les trucs de rappel IdleHandler et s'assurer que votre exécutable posté est exécuté. (Il peut également vérifier si l'heure est déjà correcte, Si vous avez posté avec un retard.)
le code suivant montre les façons typiques dont nous les utilisons.
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
Handler est largement utilisé dans les Services Android. Android support de la communication entre les applications. Typiquement, lorsque nous implémentons un service, qui n'a pas besoin de gérer le multithreading, nous implémentons un gestionnaire qui reçoit un rappel pour chaque appel d'un client. Ensuite, créez un objet Messenger (référence au Handler), qui est un objet Binder et renvoyez cet objet aux clients lorsqu'ils lient ce service. Pour que le client puisse utiliser ce messager envoyer des messages (dans la file d'attente thread-local, envoyer au handler par Looper) à ce service, et les faire traiter dans le Handler. Exemple de Code ci-joint:
public class MessengerService extends Service {
/** Command to the service to display a message */
static final int MSG_SAY_HELLO = 1;
/**
* Handler of incoming messages from clients.
*/
class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SAY_HELLO:
Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
break;
default:
super.handleMessage(msg);
}
}
}
final Messenger mMessenger = new Messenger(new IncomingHandler());
@Override
public IBinder onBind(Intent intent) {
Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
return mMessenger.getBinder();
}
}
postDelayed (Runnable r, long delayMillis)
fait en sorte que le Runnable r
soit ajouté à la file d'attente de messages, pour être exécuté après l'expiration du délai spécifié. Le runnable
sera exécuté sur le fil auquel ce gestionnaire est attaché.
-
L'exécutable représente une commande qui peut être exécutée.
-
delayMillis représente le temps après lequel elle doit être exécutée.
fondamentalement, il retarde l'exécution de la commande(quelque code peut-être) pour une période de temps particulière ( delayMillis
), de manière à exécuter la commande après un temps spécifié.
public class ApiHandler {
public static final String BASE_URL = "http://xxx.yyy/xx/";
private static final long HTTP_TIMEOUT = TimeUnit.SECONDS.toMillis(120);
private static Webservices apiService;
public static Webservices getApiService() {
if (apiService == null) {
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setConnectTimeout(HTTP_TIMEOUT, TimeUnit.MILLISECONDS);
okHttpClient.setWriteTimeout(HTTP_TIMEOUT, TimeUnit.MILLISECONDS);
okHttpClient.setReadTimeout(HTTP_TIMEOUT, TimeUnit.MILLISECONDS);
RestAdapter restAdapter = new RestAdapter.Builder()
.setLogLevel(RestAdapter.LogLevel.FULL)
.setEndpoint(BASE_URL)
.setClient(new OkClient(okHttpClient))
.setConverter(new GsonConverter(new Gson()))
.build();
apiService = restAdapter.create(Webservices.class);
/*RestAdapter.Builder builder = new RestAdapter.Builder();
builder.setConverter(new StringConverter())
.setEndpoint(BASE_URL)
.setClient(new OkClient(new OkHttpClient()))
.setLogLevel(RestAdapter.LogLevel.NONE);
RestAdapter adapter = builder.build();
apiService = adapter.create(Webservices.class);*/
return apiService;
} else {
return apiService;
}
}
}