Android Handler

Hanlder简介

相比于 AsyncTask,Handler类允许准确的控制操作的运行时间,而且还可以多次使用,执行的操作会一直运行,直到被显示的停止。每个Handler实例都被包含在一个单独的线程里面。

Handler 有两个主要的用途 :
1. 确保一些调度信息和任务在未来的某一时刻被执行
2. 让一些行为在其他的线程中表现出来

HandlerThread 介绍

HandlerThread 类用于创建一个带有 Looper 的新线程,这个Looper可以用于创建Handler 实例,HandlerThread 的实例必须在调用start() 方法后才可以使用。

构造方法 :
1. HandlerThread(String name)
2. HandlerThread (String name, int priority) //priority 就是线程运行的优先级,由 Process类中的变量 来指定

方法 :
1. getLooper ()

这个方法用于获取与该线程相关联的 Looper,如果该线程没有开启,也即未调用 start() 方法,那么这个方法会返回一个 null 值。如果线程已经开启,这个方法会被阻塞直到 Looper 初始化完成。

  1. getThreadId ()

用于返回线程的标识符

  1. quit ()

停止线程中的Looper,该方法被调用后,任何对Looper 的请求都会失败。比如,sendMessage(Message) 方法会返回false。使用这个方法可能是不安全的,因为在Looper被终止的时候可能还有 Message 未被递交。

  1. quitSafely ()

和上一个方法完成的功能相同,不过这个方法更安全,因为在Looper被终止时,一些未递交的 Message 会因为时间的关系不再递交。

  1. run ()

调用 Runnable 对象中的run() 方法,如果未设置Runnable,就什么也不做。

  1. onLooperPrepared ()

该方法是 protected 类型的,当我们需要在 Looper 的loop() 方法调用前需要完成一些工作,那么可以复写这个方法。

Looper 的简单介绍

Looper 类用来为线程运行 消息循环,默认的Threads 并不包含一个 message loop,为了创建一个,可以在线程中调用 prepare(),然后调用 loop() 去处理messages

官方给出的示例

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

}

介绍一下Looper 类中的一些方法

  1. Looper getMainLooper ()

获得应用程序的主 Looper,存在于主线程中

  1. Thread getThread ()

返回与该 Looper 关联的 Thread

  1. void loop ()

在线程中运行 message queue,与此方法对应的是 quit() 方,而且这两个方法必须同时出现。

  1. Looper myLooper ()

返回与该线程关联的 Looper,如果该线程没有关联 Looper,就返回 null

  1. MessageQueue myQueue ()

返回与该线程关联的 MessageQueue,如果在未关联 Looper 的线程中调用该方法,会抛出 NullPointerException

  1. void prepare ()

初始化该线程作为一个Looper

  1. void quit ()
  2. void quitSafely()

功能和上面HandlerThread 中介绍的一样

异步消息处理机制

首先,在主线程中创建一个 Handler,并重写 handleMessage() 方法,然后当子线程需要进行 UI 操作时,就创建一个 Message 对象,并通过 Handler 将消息发送出去。之后这条消息会被添加到 MessageQueue 的队列中进行等待,而 Looper 会一直尝试从 MessageQueue 中取出待处理消息,最后分发回 Handler 的 handleMessage() 方法中。由于 Handler 是在主线程中创建的,此时的 handleMessage() 也会在主线程中得到执行。

一个Message 经过一个流程的辗转,从子线程进入到主线程,从不能更新 UI 到可以更新 UI,这就是异步消息处理机制的核心思想。

Hanlder 的简单使用

由于 Handler 中的方法太多,就不逐一介绍了,下面来介绍 几种给 Handler 发送信息的方法。

  1. Message.obtain(mHanlder,FLAG,data).sendToTarget()

创建一个标识为 FLAG,数据为 data 的Message,立刻将其发送到 Handler 去执行

  1. mHandler.sendEmptyMessage(FLAG)

立刻给 Handler 发送一个带有标识的空消息

  1. mHanlder.sendEmptyMessageAtTime(FLAG,1000)

给 Handler 发送一个简单的空消息,该消息会在一秒后被递交给 Looper

  1. mHandler.sendEmptyMessageDelayed(FLAG,1000)

效果同上

下面利用 Handler 来更改 UI
public class MainActivity extends AppCompatActivity {

public static final int FLAG = 0;
private Button mButton;
private TextView mTextView;
private Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        if (msg.what == FLAG) {
            mTextView.setText("After Changer");
        }
    }
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mButton = (Button) findViewById(R.id.start);
    mTextView = (TextView) findViewById(R.id.tx);

    mButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    mHandler.sendEmptyMessage(FLAG);
                }
            }).start();
        }
    });
  }
}

注意,这个时候mHandler 使用的是默认 Looper,也即 MainLooper,我们也可以通过 HandlerThread 来使用自己的 Looper执行该操作。

public class MainActivity extends AppCompatActivity implements Handler.Callback {

public static final int FLAG = 0;
private Button mButton;
private TextView mTextView;

private HandlerThread mHandlerThread;
private Handler mHandler;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mHandlerThread = new HandlerThread("MyHandlerThread");
    mHandlerThread.start();
    mHandler = new Handler(mHandlerThread.getLooper(), this);

    mButton = (Button) findViewById(R.id.start);
    mTextView = (TextView) findViewById(R.id.tx);

    mButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    mHandler.sendEmptyMessage(FLAG);
                }
            }).start();
        }
    });

}

@Override
public boolean handleMessage(Message message) {
    if (message.what == FLAG) {
        mTextView.setText("After Change");
    }
    return true;
}

}

这个时候会出现一个错误,因为我们自己的 Looper 是没有权限去更新 UI 的,如果想要更新 UI ,可以在 Handler 的构造方法中使用 getMainLooper() 方法。

以上我们都使用使用默认的 mHandler 和 HandlerThread,我们也可以写一个类继承自 HandlerThread 或者 Handler,在自定义的类中可以执行一些耗时任务,因为这个时候所有的任务都是在子线程中执行的,并不会阻塞主线程。

关于 AsyncTask 和 Handler 的选择,如果不是很频繁的执行一个操作,而且操作可以在较短时间内完成,使用 AsyncTask 是十分方便的。如果需要安排操作的时间或者需要快速间隔的执行某操作,Handler 是不错的选择。

你可能感兴趣的:(android,线程)