Domanda Come funzionano le classi di gestori in Android


Sono nuovo di Android e stavo leggendo le applicazioni demo sul sito ufficiale di Android. E mi sono imbattuto in un metodo di Handler classe chiamata come postDelayed(Runnable r, long milliseconds).

Qualcuno può spiegare cosa fa questo metodo?


28
2018-01-30 10:27


origine


risposte:


Puoi vedere il documentazione.

Ma per capire i documenti, dovresti prima capire diversi concetti: Messaggio, Coda messaggi, Gestore e Looper, e il loro relazione.

Quanto segue illustra come funziona Looper, mostra che looper è un oggetto locale del thread e la sua relazione con 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();
            }
        }
    }
}

Alcune osservazioni:

Looper è un oggetto locale del thread tale che ogni thread ha un looper. Ogni looper è associato a una coda di messaggi. Il looper riceve continuamente messagese ("tasks", "commands" o qualsiasi altra cosa vogliate chiamarli) dalla coda e invia il messaggio al suo target, che è un gestore per gestire quel messaggio (es. Richiamando un Runnable contenuto in il messaggio). Quando non ci sono messaggi rimasti nella coda, il thread si blocca fino a quando non ci sono nuovi messaggi. Per fermare un Looper, devi chiamare quit () su di esso (che probabilmente non interrompe immediatamente il ciclo, ma imposta piuttosto un flag privato che viene controllato periodicamente dal loop, segnalandone l'interruzione).

Il framework Android fornisce la classe Handler per semplificare le cose. Quando si crea un'istanza Handler, questa è (per impostazione predefinita) associata al Looper già associato al thread corrente. (Il Gestore sa a cosa è collegato Looper perché abbiamo chiamato prepare () in precedenza, che memorizzava un riferimento al Looper in un ThreadLocal.)

Con un gestore, puoi semplicemente chiamare post () per "mettere un messaggio nella coda dei messaggi del thread" (per così dire). L'Handler si prenderà cura di tutto il materiale di callback di IdleHandler e si assicurerà che il Runnable pubblicato sia eseguito. (Potrebbe anche controllare se il momento è giusto, se hai postato con un ritardo.)

Il seguente codice mostra i modi tipici in cui li usiamo.

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();
  }

}

Il gestore è ampiamente utilizzato nei servizi Android. Comunicazione inter applicazione supporto Android. Tipicamente quando implementiamo un servizio, che non ha bisogno di gestire il multithreading, implementiamo un Handler che riceve un callback per ogni chiamata da un client. Quindi creare un oggetto Messenger (riferimento al gestore), che è un oggetto Raccoglitore e restituire questo oggetto ai client quando eseguono il bind di questo servizio. In questo modo il client può utilizzare questo Messenger per inviare messaggi (nella coda locale del thread, inviare al gestore tramite Looper) a questo servizio e riceverli gestiti nel Gestore. Il codice di esempio è allegato:

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();
    }
}

51
2018-01-30 10:38



postDelayed (Runnable r, long delayMillis)

Provoca il Runnable r da aggiungere alla coda dei messaggi, da eseguire dopo che è trascorso il tempo specificato. Il runnable verrà eseguito sul thread a cui è collegato questo gestore.

  • Runnable Rappresenta un comando che può essere eseguito.

  • delayMillis rappresenta il tempo dopo il quale dovrebbe essere eseguito.

Fondamentalmente, ritarda l'esecuzione del comando (qualche codice forse) per un particolare periodo di tempo (delayMillis), in modo da eseguire il comando dopo il tempo specificato.


6
2018-01-30 10:31



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

-1
2018-06-26 02:47