content: package com.taobao.schedulers;
  
  import android.os.Handler;
  import android.os.Message;
  import io.reactivex.Scheduler;
  import io.reactivex.disposables.Disposable;
  import io.reactivex.disposables.Disposables;
  import io.reactivex.plugins.RxJavaPlugins;
  
  import java.util.concurrent.TimeUnit;
  
  /**
   * @author lilong
   * @create 2017-06-05 上午9:51
   */
  
  final class HandlerScheduler extends Scheduler {
      private final Handler handler;
  
      HandlerScheduler(Handler handler) {
          this.handler = handler;
      }
  
      @Override
      public Disposable scheduleDirect(Runnable run, long delay, TimeUnit unit) {
          if (run == null) throw new NullPointerException("run == null");
          if (unit == null) throw new NullPointerException("unit == null");
  
          run = RxJavaPlugins.onSchedule(run);
          ScheduledRunnable scheduled = new ScheduledRunnable(handler, run);
          handler.postDelayed(scheduled, Math.max(0L, unit.toMillis(delay)));
          return scheduled;
      }
  
      @Override
      public Worker createWorker() {
          return new HandlerWorker(handler);
      }
  
      private static final class HandlerWorker extends Worker {
          private final Handler handler;
  
          private volatile boolean disposed;
  
          HandlerWorker(Handler handler) {
              this.handler = handler;
          }
  
          @Override
          public Disposable schedule(Runnable run, long delay, TimeUnit unit) {
              if (run == null) throw new NullPointerException("run == null");
              if (unit == null) throw new NullPointerException("unit == null");
  
              if (disposed) {
                  return Disposables.disposed();
              }
  
              run = RxJavaPlugins.onSchedule(run);
  
              ScheduledRunnable scheduled = new ScheduledRunnable(handler, run);
  
              Message message = Message.obtain(handler, scheduled);
              message.obj = this; // Used as token for batch disposal of this worker's runnables.
  
              handler.sendMessageDelayed(message, Math.max(0L, unit.toMillis(delay)));
  
              // Re-check disposed state for removing in case we were racing a call to dispose().
              if (disposed) {
                  handler.removeCallbacks(scheduled);
                  return Disposables.disposed();
              }
  
              return scheduled;
          }
  
          @Override
          public void dispose() {
              disposed = true;
              handler.removeCallbacksAndMessages(this /* token */);
          }
  
          @Override
          public boolean isDisposed() {
              return disposed;
          }
      }
  
      private static final class ScheduledRunnable implements Runnable, Disposable {
          private final Handler handler;
          private final Runnable delegate;
  
          private volatile boolean disposed;
  
          ScheduledRunnable(Handler handler, Runnable delegate) {
              this.handler = handler;
              this.delegate = delegate;
          }
  
          @Override
          public void run() {
              try {
                  delegate.run();
              } catch (Throwable t) {
                  IllegalStateException ie =
                          new IllegalStateException("Fatal Exception thrown on Scheduler.", t);
                  RxJavaPlugins.onError(ie);
                  Thread thread = Thread.currentThread();
                  thread.getUncaughtExceptionHandler().uncaughtException(thread, ie);
              }
          }
  
          @Override
          public void dispose() {
              disposed = true;
              handler.removeCallbacks(this);
          }
  
          @Override
          public boolean isDisposed() {
              return disposed;
          }
      }
  }
  
  