29

我是 android 新手,正在阅读官方 android 网站上的演示应用程序。我遇到了一个Handler名为的类方法postDelayed(Runnable r, long milliseconds)

谁能解释一下这种方法的作用?

4

3 回答 3

52

您可以查看文档

但是要理解文档,首先要了解几个概念:Message、Message Queue、Handler 和 Looper,以及它们之间的关系

下面说明 Looper 是如何工作的,它表明 Looper 是一个线程本地对象以及它与 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();
            }
        }
    }
}

几点说明:

Looper 是一个线程本地对象,因此每个线程都有一个 Looper。每个 Looper 都与一个消息队列相关联。looper 不断地从队列中获取messagese("tasks", "commands" 或任何你喜欢的名字),并将消息分派到它的目标,它是一个处理该消息的处理程序(例如,通过回调包含在消息)。当队列中没有消息时,线程会阻塞,直到有新消息。要停止 Looper,您必须在其上调用 quit() (这可能不会立即停止循环,而是设置一个从循环中定期检查的私有标志,指示它停止)。

Android 框架提供了 Handler 类来简化事情。当您创建一个 Handler 实例时,它(默认情况下)绑定到已经附加到当前线程的 Looper。(处理程序知道要附加到哪个 Looper,因为我们之前调用了 prepare(),它将对 Looper 的引用存储在 ThreadLocal 中。)

使用处理程序,您只需调用 post() 即可“将消息放入线程的消息队列”(可以这么说)。Handler 将处理所有 IdleHandler 回调的东西,并确保您发布的 Runnable 被执行。(如果您延迟发布,它也可能会检查时间是否正确。)

下面的代码展示了我们使用它们的典型方式。

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在Android服务中被广泛使用。Android 支持应用程序间通信。通常,当我们实现一个不需要处理多线程的服务时,我们会实现一个 Handler,它接收来自客户端的每个调用的回调。然后创建一个 Messenger 对象(对 Handler 的引用),它是一个 Binder 对象,并在客户端绑定此服务时将此对象返回给客户端。因此客户端可以使用这个 Messenger 将消息(进入线程本地队列,通过 Looper 发送到处理程序)发送到该服务,并在处理程序中处理它们。附上代码示例:

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();
    }
}
于 2013-01-30T10:38:34.133 回答
6

postDelayed (Runnable r, long delayMillis)

使Runnable r被添加到消息队列中,并在经过指定的时间后运行。将runnable在附加此处理程序的线程上运行。

  • Runnable表示可以执行的命令。

  • delayMillis表示应该执行的时间。

基本上,它会将命令(可能是某些代码)的执行延迟特定时间段(delayMillis),以便在指定时间后执行命令。

于 2013-01-30T10:31:43.507 回答
-1
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;
    }
  }
}
于 2017-06-26T02:47:21.390 回答