精华内容
下载资源
问答
  • Android Handler使用方法

    2021-06-05 09:12:32
    前言本篇文章介绍 Android Handler 的基本使用方法,且 Demo 会以 Java & Kotlin 两种代码形式进行展示。在 Android 实际开发中,我们经常会遇到耗时任务,比如:网络请求API接口来获取数据、数据库 CRUD 操作...

    目录:

    4b951885168f

    目录

    1. 前言

    本篇文章介绍 Android Handler 的基本使用方法,且 Demo 会以 Java & Kotlin 两种代码形式进行展示。

    在 Android 实际开发中,我们经常会遇到耗时任务,比如:网络请求API接口来获取数据、数据库 CRUD 操作等等,我们需要额外创建开启工作线程来处理这些耗时任务。由于 Android 规定只能由主线程才能处理 UI 工作,所以这时候我们就需要通过 Handler 来通知主线程处理 UI 工作。

    1.1 定义

    Handler:子线程与主线程之间的沟通中介,用于传递处理消息。

    在 Android 中,为保证处理 UI 工作的线程稳定安全,规定只有主线程才能更新处理 UI 工作。所以当子线程想处理 UI 工作时,就需要通过 Handler 来通知主线程作出相对应的 UI 处理工作。

    如下图所示:

    4b951885168f

    Handler是子线程与主线程的沟通中介

    本篇文章,我将介绍 Handler 的三种使用方法,分别是:

    Handler.sendMessage(Message)

    Handler.post(Runnable)

    Handler.obtainMessage(what).sendToTarget();

    2. Handler.sendMessage()方法

    Handler.sendMessage(Msg) 方法是最为常见的一种方法。

    2.1 使用步骤说明

    其使用步骤分四步,如下所示:

    步骤一:新建 Handler 对象,覆写 handleMessage(Message) 方法。

    步骤二:新建 Message 对象,设置其携带的数据。

    步骤三:在子线程中通过 Handler.sendMessage(Message) 方法发送信息。

    步骤四:在 Handler 的 handleMessage(Message msg) 方法中处理消息,通知主线程作出相对应的 UI 工作。

    步骤一:新建 Handler 对象,覆写 handleMessage(Message) 方法

    //创建 Handler对象,并关联主线程消息队列

    mHandler = new Handler(Looper.getMainLooper()) {

    @Override

    public void handleMessage(Message msg) {

    super.handleMessage(msg);

    ···略···

    }

    }

    };

    步骤二:新建 Message 对象,设置其携带的数据

    Bundle bundle = new Bundle();

    bundle.putInt(CURRENT_PROCESS_KEY, i);

    Message msg = new Message();

    msg.setData(bundle);

    msg.what = 2;

    步骤三:在子线程中通过 Handler.sendMessage(Message) 方法发送信息

    mHandler.sendMessage(msg)

    步骤四:在 Handler 的 handleMessage(Message msg) 方法中处理消息,通知主线程作出相对应的 UI 工作

    mHandler = new Handler(Looper.getMainLooper()) {

    @Override

    public void handleMessage(Message msg) {

    super.handleMessage(msg);

    //根据信息编码及数据做出相对应的处理

    switch (msg.what) {

    case 1:

    //更新 TextView UI

    mDisplayTv.setText("CustomChildThread starting!");

    break;

    case 2:

    //获取 ProgressBar 的进度,然后显示进度值

    Bundle bundle = msg.getData();

    int process = bundle.getInt(CURRENT_PROCESS_KEY);

    mProgressBar.setProgress(process);

    break;

    default:

    break;

    }

    }

    };

    2.2 具体例子

    根据上述的使用步骤,我们来完成一个完整的例子:

    新建一个线程,模拟处理耗时任务,然后将处理进度通过 ProgressBar 显示出来。

    效果如下所示:点击按钮,开启线程处理耗时操作。

    4b951885168f

    Handler.sendMessage() Demo

    具体代码见下:

    2.2.1 Java版本Demo

    Java版本的具体代码如下所示:

    public class HandlerAddThreadActivity extends AppCompatActivity {

    public static final String CURRENT_PROCESS_KEY = "CURRENT_PROCESS";

    private TextView mDisplayTv;

    private Handler mHandler;

    private ProgressBar mProgressBar;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_handler_add_thread);

    TextView titleTv = findViewById(R.id.title_tv);

    titleTv.setText("Handler + Thread");

    mDisplayTv = findViewById(R.id.display_tv);

    mProgressBar = findViewById(R.id.test_handler_progress_bar);

    //mHandler用于处理主线程消息队列中的子线程消息

    mHandler = new Handler(Looper.getMainLooper()) {

    @Override

    public void handleMessage(Message msg) {

    super.handleMessage(msg);

    switch (msg.what) {

    case 1:

    //更新 TextView UI

    mDisplayTv.setText("CustomChildThread starting!");

    break;

    case 2:

    //获取 ProgressBar 的进度,然后显示进度值

    Bundle bundle = msg.getData();

    int process = bundle.getInt(CURRENT_PROCESS_KEY);

    mProgressBar.setProgress(process);

    break;

    default:

    break;

    }

    }

    };

    Button mClickBtn = findViewById(R.id.click_btn);

    mClickBtn.setOnClickListener(new View.OnClickListener() {

    @Override

    public void onClick(View view) {

    //开启子线程,子线程处理UI工作

    CustomChildThread customThread = new CustomChildThread();

    customThread.start();

    }

    });

    }

    /**

    * 子线程,用于处理耗时工作

    */

    public class CustomChildThread extends Thread {

    @Override

    public void run() {

    //在子线程中创建一个消息对象

    Message childThreadMessage = new Message();

    childThreadMessage.what = 1;

    //将该消息放入主线程的消息队列中

    mHandler.sendMessage(childThreadMessage);

    //模拟耗时进度,将进度值传给主线程用于更新 ProgressBar 进度。

    for (int i = 1; i <= 5; i++) {

    try {

    //让当前执行的线程(即 CustomChildThread)睡眠 1s

    Thread.sleep(1000);

    //Message 传递参数

    Bundle bundle = new Bundle();

    bundle.putInt(CURRENT_PROCESS_KEY, i);

    Message progressBarProcessMsg = new Message();

    progressBarProcessMsg.setData(bundle);

    progressBarProcessMsg.what = 2;

    mHandler.sendMessage(progressBarProcessMsg);

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    }

    }

    }

    }

    执行结果看上图 Handler.sendMessage() Demo。

    2.2.2 Kotlin版本Demo

    Kotlin版本的代码如下所示:

    class TestThreadAddHandlerActivity : AppCompatActivity() {

    companion object {

    const val PROGRESS_VALUE_KEY = "PROGRESS_VALUE"

    }

    override fun onCreate(savedInstanceState: Bundle?) {

    super.onCreate(savedInstanceState)

    setContentView(R.layout.activity_thread_add_handler)

    handlerAddThreadStartBtn.setOnClickListener(View.OnClickListener {

    //工作线程开始模拟下载任务

    val workThread: WorkThread = WorkThread(this)

    workThread.start()

    })

    }

    class WorkThread(activity: TestThreadAddHandlerActivity) : Thread() {

    private var handler: MyHandler = MyHandler(activity)

    override fun run() {

    super.run()

    for (i in 0..6) {

    sleep(1000)

    //通过 Handler 将进度参数传递给 主线程,让其更新 progressBar 进度

    val message = Message()

    message.what = 1

    val bundle = Bundle()

    bundle.putInt(PROGRESS_VALUE_KEY, i)

    message.data = bundle

    handler.sendMessage(message)

    }

    }

    }

    /**

    * 静态内部类,防止内存泄漏

    */

    class MyHandler(activity: TestThreadAddHandlerActivity) : Handler() {

    private var weakReference = WeakReference(activity)

    override fun handleMessage(msg: Message) {

    super.handleMessage(msg)

    //处理消息

    when (msg.what) {

    1 -> {

    val activity = weakReference.get()

    if (activity != null && !activity.isFinishing) {

    //获取消息中携带的任务处理进度参数,然后设置成 ProgressBar 的进度。

    val progressValue: Int = msg.data.get(PROGRESS_VALUE_KEY) as Int

    activity.handlerAddThreadProgressBar.progress = progressValue

    }

    }

    }

    }

    }

    }

    执行结果看上图 Handler.sendMessage() Demo

    3. Handler.post()方法

    除了使用 Handler.sendMessage(Message) 来发送信息,Handler 还支持 post(Runnable) 方法来传递消息,通知主线程做出相对应的 UI 工作。使用方法如下:

    /**

    * 将可运行的 Runnable 添加到消息队列。Runnable 将在该 Handler 相关的线程上运行处理。

    * The runnable will be run on the thread to which this handler is attached.

    */

    new Handler().post(new Runnable() {

    @Override

    public void run() {

    //更新处理 UI 工作

    }

    });

    3.1 具体例子

    实现上述同样的功能 -> 点击按钮,子线程开始工作模拟处理耗时任务,通过 Handler 将进度告诉主线程,再通过 ProgressBar 将进度显示出来。

    效果如下:

    4b951885168f

    Handler.post() Demo

    具体代码见下:

    3.1.1 Java版本Demo

    Java版本的具体代码如下:

    public class HandlerPostFunctionActivity extends AppCompatActivity {

    private Handler mMainHandler;

    private ProgressBar mProgressBar;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_handler_add_thread);

    TextView titleTv = findViewById(R.id.title_tv);

    titleTv.setText("Handler post() function");

    mProgressBar = findViewById(R.id.test_handler_progress_bar);

    //新建静态内部类 Handler 对象

    mMainHandler = new Handler(getMainLooper());

    Button mClickBtn = findViewById(R.id.click_btn);

    mClickBtn.setOnClickListener(new View.OnClickListener() {

    @Override

    public void onClick(View view) {

    //开启子线程,子线程处理UI工作

    CustomChildThread customThread = new CustomChildThread();

    customThread.start();

    }

    });

    }

    /**

    * 子线程,用于处理耗时工作

    */

    public class CustomChildThread extends Thread {

    @Override

    public void run() {

    //模拟耗时进度,将进度值传给主线程用于更新 ProgressBar 进度。

    for (int i = 1; i <= 5; i++) {

    try {

    //让当前执行的线程(即 CustomChildThread)睡眠 1s

    Thread.sleep(1000);

    //新创建一个 Runnable 用户处理 UI 工作

    MyRunnable runnable = new MyRunnable(HandlerPostFunctionActivity.this, i);

    //调用Handler post 方法。

    mMainHandler.post(runnable);

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    }

    }

    }

    /**

    * 将 Runnable 写成静态内部类,防止内存泄露

    */

    public static class MyRunnable implements Runnable {

    private int progressBarValue;

    private WeakReference weakReference;

    MyRunnable(HandlerPostFunctionActivity activity, int value) {

    this.weakReference = new WeakReference<>(activity);

    this.progressBarValue = value;

    }

    @Override

    public void run() {

    HandlerPostFunctionActivity activity = weakReference.get();

    if (activity != null && !activity.isFinishing()) {

    activity.mProgressBar.setProgress(progressBarValue);

    }

    }

    }

    }

    执行结果看上图 Handler.post() Demo

    3.1.2 Kotlin版本Demo

    Kotlin版本的具体代码如下:

    class TestHandlerPostRunnableActivity : AppCompatActivity() {

    private var mMainHandler: Handler? = null

    override fun onCreate(savedInstanceState: Bundle?) {

    super.onCreate(savedInstanceState)

    setContentView(R.layout.activity_thread_add_handler)

    handlerAddThreadStartBtn.setOnClickListener(View.OnClickListener {

    //工作线程开始模拟下载任务

    val workThread: WorkThread = WorkThread(this)

    workThread.start()

    })

    //创建 Handler,关联App的 主Looper 对象

    mMainHandler = Handler(Looper.getMainLooper())

    }

    class WorkThread(private var activity: TestHandlerPostRunnableActivity) : Thread() {

    private var handler: Handler? = activity.mMainHandler

    override fun run() {

    super.run()

    for (i in 0..6) {

    sleep(1000)

    //新建 Runnable 设置进度参数传,然后通过 post(Runnable) 方法,让其更新 progressBar 进度

    val runnable: MyRunnable = MyRunnable(activity, i)

    handler?.post(runnable)

    }

    }

    }

    /**

    * 处理 UI 工作。

    * 静态内部类,防止内存泄露

    */

    class MyRunnable(activity: TestHandlerPostRunnableActivity, value: Int) : Runnable {

    private var weakReference = WeakReference(activity)

    private var progressValue = value

    override fun run() {

    val activity = weakReference.get()

    if (activity != null && !activity.isFinishing) {

    //获取任务执行进度参数,更新 progressBar 进度

    activity.handlerAddThreadProgressBar.progress = progressValue

    }

    }

    }

    }

    执行结果看上图 Handler.post() Demo

    4. obtainMessage()方法

    obtainMessage() 方法与 sendMessage() 方法很相似,通过 mHandler.obtainMessage().sendToTarget() 发送信息。该方法与 sendMessage() 的区别就是你不用额外去创建一个 Message 对象。

    obtainMessage() 方法有三种,分别是:

    //指定 what 用于区分,通过 Message.what 获得

    public final Message obtainMessage(int what);

    //传递obj参数,通过 Message.obj 获得

    public final Message obtainMessage(int what, @Nullable Object obj)

    //传递arg1 arg2参数,通过 Message.arg1 Message.arg2 获得

    public final Message obtainMessage(int what, int arg1, int arg2)

    4.1 具体例子

    同样实现上述同样的功能 -> 点击按钮,子线程开始工作,通过 Handler 将进度告诉主线程,通过 ProgressBar 将进度显示出来。

    效果如下:

    4b951885168f

    Handler.obtainMessage() Demo

    具体代码如下:

    4.1.1 Java版本Demo

    Java版本的具体代码如下:

    public class HandlerObtainMessageActivity extends AppCompatActivity {

    private TextView mDisplayTv;

    private Handler mHandler;

    private ProgressBar mProgressBar;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_handler_add_thread);

    TextView titleTv = findViewById(R.id.title_tv);

    titleTv.setText("Handler + Thread");

    mDisplayTv = findViewById(R.id.display_tv);

    mProgressBar = findViewById(R.id.test_handler_progress_bar);

    //mHandler用于处理主线程消息队列中的子线程消息

    mHandler = new Handler(Looper.getMainLooper()) {

    @Override

    public void handleMessage(Message msg) {

    super.handleMessage(msg);

    switch (msg.what) {

    case 1:

    //更新 TextView UI

    mDisplayTv.setText("Handler obtainMessage() Test!!");

    break;

    case 2:

    //通过 msg.obj 获取 ProgressBar 的进度,然后显示进度值

    int process = (int) msg.obj;

    mProgressBar.setProgress(process);

    break;

    default:

    break;

    }

    }

    };

    Button mClickBtn = findViewById(R.id.click_btn);

    mClickBtn.setOnClickListener(new View.OnClickListener() {

    @Override

    public void onClick(View view) {

    //开启子线程,子线程处理UI工作

    CustomChildThread customThread = new CustomChildThread();

    customThread.start();

    }

    });

    }

    /**

    * 子线程,用于处理耗时工作

    */

    public class CustomChildThread extends Thread {

    @Override

    public void run() {

    //发送第一条消息,代表开始执行异步任务

    mHandler.obtainMessage(1).sendToTarget();

    //模拟耗时进度,将进度值传给主线程用于更新 ProgressBar 进度。

    for (int i = 1; i <= 5; i++) {

    try {

    //让当前执行的线程(即 CustomChildThread)睡眠 1s

    Thread.sleep(1000);

    //将执行进度参数 i 传递给主线程 progressBar

    mHandler.obtainMessage(2, i).sendToTarget();

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    }

    }

    }

    }

    执行结果看上图 Handler.obtainMessage() Demo

    4.1.2 kotlin版本Demo

    Kotlin版本的具体代码如下:

    class TestHandlerObtainMessageActivity : AppCompatActivity() {

    companion object {

    const val PROGRESS_VALUE_KEY = "PROGRESS_VALUE"

    }

    override fun onCreate(savedInstanceState: Bundle?) {

    super.onCreate(savedInstanceState)

    setContentView(R.layout.activity_thread_add_handler)

    handlerAddThreadStartBtn.setOnClickListener(View.OnClickListener {

    //工作线程开始模拟下载任务

    val workThread: WorkThread = WorkThread(this)

    workThread.start()

    })

    }

    class WorkThread(activity: TestHandlerObtainMessageActivity) : Thread() {

    private var handler: MyHandler = MyHandler(activity)

    override fun run() {

    super.run()

    for (i in 0..6) {

    sleep(1000)

    //通过 Handler 将进度参数传递给 主线程,让其更新 progressBar 进度

    val bundle = Bundle()

    bundle.putInt(PROGRESS_VALUE_KEY, i)

    handler.obtainMessage(1, bundle).sendToTarget()

    }

    }

    }

    /**

    * 静态内部类,防止内存泄漏

    */

    class MyHandler(activity: TestHandlerObtainMessageActivity) : Handler() {

    private var weakReference = WeakReference(activity)

    override fun handleMessage(msg: Message) {

    super.handleMessage(msg)

    when (msg.what) {

    1 -> {

    val activity = weakReference.get()

    if (activity != null && !activity.isFinishing) {

    //获取任务执行进度参数,然后通过 ProgressBar 显示出来

    val bundle: Bundle = msg.obj as Bundle

    val progressValue: Int = bundle.get(PROGRESS_VALUE_KEY) as Int

    activity.handlerAddThreadProgressBar.progress = progressValue

    }

    }

    }

    }

    }

    }

    执行结果看上图 Handler.obtainMessage() Demo

    5. 总结:

    在实际开发中,三种方法的使用都可行,具体用哪种方法,需结合你的实际情况及个人喜好。另外,在实际使用中往往将 Handler 写成静态内部类,这时需要注意防止内存泄露!(The handler class should be static or leaks might occur),具体代码见上方!

    5.1 在子线程中创建Handler

    思考: 在上面代码中, 我们都是在主线程中创建了 Handler 对象,那如果在子线程中创建一个 Handler 对象呢?会发生什么呢?

    如下所示:我们在 CustomChildThread 线程中,新建一个 Handler 对象。

    public class CustomChildThread extends Thread {

    @Override

    public void run() {

    Handler handler = new Handler(Activity.this);

    //会报错:java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

    }

    }

    结果: 抛出异常: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()。

    原因: 因为在创建 Handler对象时要关联所处线程的 Looper对象,而我们的子线程没有 Looper,所以会抛出上述异常。

    解决方法: 通过调用,Looper.prepare() 方法为子线程创建一个 Looper 对象,并且调用 Looper.loop() 方法开始消息循环。如下所示:

    class CustomChildThread extends Thread {

    @Override

    public void run() {

    //为当前线程创建一个 Looper 对象

    Looper.prepare();

    //在子线程中创建一个 Handler 对象

    Handler handler = new Handler() {

    public void handleMessage(Message msg) {

    // 在这里处理传入的消息

    }

    };

    //开始消息循环

    Looper.loop();

    }

    }

    至此关于 Handler 的使用方法也就介绍完毕了,如果你想深入学习 Handler,了解其通信机制以及源码分析,请看博客 Android Handler深入学习(源码分析)

    其实分享文章的最大目的正是等待着有人指出我的错误,如果你发现哪里有错误,请毫无保留的指出即可,虚心请教。

    另外,如果你觉得文章不错,对你有所帮助,请给我点个赞,就当鼓励,谢谢~Peace~!

    展开全文
  • handler用法

    2021-03-18 00:30:21
    简单的说,Handler获取当前线程中的looper对象,looper用来从存放Message的MessageQueue中取出Message,再有Handler进行Message的分发和处理.Message Queue(消息队列):用来存放通过Handler发布的消息,通常附属于某...

    简单的说,Handler获取当前线程中的looper对象,looper用来从存放Message的MessageQueue中取出Message,再有Handler进行Message的分发和处理.

    Message Queue(消息队列):用来存放通过Handler发布的消息,通常附属于某一个创建它的线程,可以通过Looper.myQueue()得到当前线程的消息队列

    Handler:可以发布或者处理一个消息或者操作一个Runnable,通过Handler发布消息,消息将只会发送到与它关联的消息队列,然也只能处理该消息队列中的消息

    Looper:是Handler和消息队列之间通讯桥梁,程序组件首先通过Handler把消息传递给Looper,Looper把消息放入队列。Looper也把消息队列里的消息广播给所有的

    Handler:Handler接受到消息后调用handleMessage进行处理

    Message:消息的类型,在Handler类中的handleMessage方法中得到单个的消息进行处理

    在单线程模型下,为了线程通信问题,Android设计了一个Message Queue(消息队列), 线程间可以通过该Message Queue并结合Handler和Looper组件进行信息交换。下面将对它们进行分别介绍:

    1. Message

    Message消息,理解为线程间交流的信息,处理数据后台线程需要更新UI,则发送Message内含一些数据给UI线程。

    2. Handler

    Handler处理者,是Message的主要处理者,负责Message的发送,Message内容的执行处理。后台线程就是通过传进来的 Handler对象引用来sendMessage(Message)。而使用Handler,需要implement 该类的 handleMessage(Message)方法,它是处理这些Message的操作内容,例如Update UI。通常需要子类化Handler来实现handleMessage方法。

    3. Message Queue

    Message Queue消息队列,用来存放通过Handler发布的消息,按照先进先出执行。

    每个message queue都会有一个对应的Handler。Handler会向message queue通过两种方法发送消息:sendMessage或post。这两种消息都会插在message queue队尾并按先进先出执行。但通过这两种方法发送的消息执行的方式略有不同:通过sendMessage发送的是一个message对象,会被 Handler的handleMessage()函数处理;而通过post方法发送的是一个runnable对象,则会自己执行。

    4. Looper

    Looper是每条线程里的Message Queue的管家。Android没有Global的Message Queue,而Android会自动替主线程(UI线程)建立Message Queue,但在子线程里并没有建立Message Queue。所以调用Looper.getMainLooper()得到的主线程的Looper不为NULL,但调用Looper.myLooper() 得到当前线程的Looper就有可能为NULL。对于子线程使用Looper,API Doc提供了正确的使用方法:这个Message机制的大概流程:

    1. 在Looper.loop()方法运行开始后,循环地按照接收顺序取出Message Queue里面的非NULL的Message。

    2. 一开始Message Queue里面的Message都是NULL的。当Handler.sendMessage(Message)到Message Queue,该函数里面设置了那个Message对象的target属性是当前的Handler对象。随后Looper取出了那个Message,则调用 该Message的target指向的Hander的dispatchMessage函数对Message进行处理。在dispatchMessage方法里,如何处理Message则由用户指定,三个判断,优先级从高到低:

    1) Message里面的Callback,一个实现了Runnable接口的对象,其中run函数做处理工作;

    2) Handler里面的mCallback指向的一个实现了Callback接口的对象,由其handleMessage进行处理;

    3) 处理消息Handler对象对应的类继承并实现了其中handleMessage函数,通过这个实现的handleMessage函数处理消息。

    由此可见,我们实现的handleMessage方法是优先级最低的!

    3. Handler处理完该Message (update UI) 后,Looper则设置该Message为NULL,以便回收!

    在网上有很多文章讲述主线程和其他子线程如何交互,传送信息,最终谁来执行处理信息之类的,个人理解是最简单的方法——判断Handler对象里面的Looper对象是属于哪条线程的,则由该线程来执行!

    1. 当Handler对象的构造函数的参数为空,则为当前所在线程的Looper;

    2. Looper.getMainLooper()得到的是主线程的Looper对象,Looper.myLooper()得到的是当前线程的Looper对象。

    现在我们再来看一下使用Handler的基本实现代码:

    // 主线程中新建一个handler

    normalHandler = new Handler() {

    public void handleMessage(android.os.Message msg) {

    btnSendMsg2NormalHandler.setText("normalHandler");

    Log.d(Constant.TAG, MessageFormat.format("Thread[{0}]--normalHandler handleMessage run...", Thread.currentThread()

    .getName()));

    }

    };

    ...

    //发送消息到hanlder

    myThreadHandler.sendEmptyMessage(0);

    你现在已经很清楚了sendEmptyMessage到handleMessage的过程,途中经过Looper.MessageQueue队列,转由Looper所在的线程去处理了,这是一个异步的过程,当然Looper所在的线程也可以是sendEmptyMessage所在的线程。

    看了上面你也许还是迷惑不解,那么什么要Looper了,跟我们要用的Handler又有啥鸟关系呢?

    我在前面一直强调在主线程中使用handler,为什么要这么说呢,因为你在自己new一个新线程中去像我前面那样简单建立一个Handler,程序执行是会报错的:

    java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

    at android.os.Handler.(Handler.java:121)

    at com.cao.android.demos.handles.HandleTestActivity$MyThread$1.(HandleTestActivity.java:86)

    at com.cao.android.demos.handles.HandleTestActivity$MyThread.run(HandleTestActivity.java:86)

    为什么在主线程中不会报错,而在自己新见的线程中就会报这个错误呢?很简单,因为主线程它已经建立了Looper,你可以打开ActivityThread的源码看一下:

    public static final void main(String[] args) {

    SamplingProfilerIntegration.start();

    Process.setArgV0("");

    Looper.prepareMainLooper();

    ActivityThread thread = new ActivityThread();

    thread.attach(false);

    Looper.loop();

    if (Process.supportsProcesses()) {

    throw new RuntimeException("Main thread loop unexpectedly exited");

    }

    thread.detach();

    String name = (thread.mInitialApplication != null)

    ? thread.mInitialApplication.getPackageName()

    : "";

    Slog.i(TAG, "Main thread of " + name + " is now exiting");

    }

    在main函数中它已经做了这个事情了,为什么要调用 Looper.prepareMainLooper(); Looper.loop();我们可以进去看一下,在prepareMainLooper方法中新建了一个looper对象,并与当前进程进行了绑定,而在Looper.loop方法中,线程建立消息循环机制,循环从MessageQueue获取Message对象,调用  msg.target.dispatchMessage(msg);进行处理msg.target在myThreadHandler.sendEmptyMessage(0)设置进去的,因为一个Thead中可以建立多个Hander,通过msg.target保证MessageQueue中的每个msg交由发送message的handler进行处理,那么Handler又是怎样与Looper建立联系的呢,在Handler构造函数中有这样一段代码:

    mLooper =Looper.myLooper();        if (mLooper == null) {

    throw new RuntimeException(

    "Can't create handler inside thread that has not called Looper.prepare()");

    }

    mQueue = mLooper.mQueue;

    在新建Handler时需要设置mLooper成员,Looper.myLooper是从当前线程中获取绑定的Looper对象:

    public static final Looper myLooper() {

    return(Looper)sThreadLocal.get();    }

    若Looper对象没有创建,就会抛异常"Can't create handler inside thread that has not called Looper.prepare()"这跟我前面讲的是一致的。所以我们在一个新线程中要创建一个Handler就需要这样写:

    class MyThread extends Thread {

    public void run() {

    Log.d(Constant.TAG, MessageFormat.format("Thread[{0}]-- run...", Thread

    .currentThread().getName()));

    // 其它线程中新建一个handler

    Looper.prepare();//创建该线程的Looper对象,用于接收消息,在非主线程中是没有looper的所以在创建handler前一定要使用prepare()创建一个Looper                        myThreadHandler = new Handler() {

    public void handleMessage(android.os.Message msg) {

    Log.d(Constant.TAG, MessageFormat.format("Thread[{0}]--myThreadHandler handleMessage run...", Thread

    .currentThread().getName()));

    }

    };Looper.myLooper().loop();//建立一个消息循环,该线程不会退出                }

    }

    现在,你应该对Handler的机制有所了解了吧,若有什么疑问,欢迎在评论中提出

    在其它线程中Handler使用主线程的Looper

    前面我说了在新线程中要新建一个Handler需要调用Looper.prepare();也有另一种方法就是使用主线程中的Looper,那就不必新建Looper对象了:

    threadMainLoopHandler =new Handler(Looper.getMainLooper()){                                public void handleMessage(android.os.Message msg) {

    Log.d(Constant.TAG, MessageFormat.format("Thread[{0}]--threadMainLoopHandler handleMessage run...", Thread

    .currentThread().getName()));

    }

    //该handleMessage方法将在mainthread中执行

    };

    这时候注意不要在handleMessage做太多的操作,因为它在主线程中执行,会影响主线程执行ui更新操作。

    使用Message.callback回调

    public void dispatchMessage(Message msg) {

    if (msg.callback != null) {

    handleCallback(msg);

    } else {

    if (mCallback != null) {

    if (mCallback.handleMessage(msg)) {

    return;

    }

    }

    handleMessage(msg);

    }

    }

    从dispatchMessage定义可以看出,如果Message对象自带callback对象,handler不会执行handleMessage方法而是执行message.callback中定义的run方法,当然callback还是在handler关联的looper所绑定的线程中执行的。实际上Handler.post(Runnable r)方法就是把r添加到一个msg.callback的,也就是说,下面两种写法,没有什么区别:

    1.使用Message.callback

    Message msg = Message.obtain(myThreadHandler,newRunnable() {

    @Override

    publicvoidrun() {

    Log.d(Constant.TAG, MessageFormat.format("Thread[{0}]--myThreadHandler.Message.callback.run",

    Thread.currentThread().getName()));

    }

    });

    myThreadHandler.sendMessage(msg);

    2.使用Handler.post

    myThreadHandler.post(newRunnable() {

    @Override

    publicvoidrun() {

    Log.d(Constant.TAG, MessageFormat.format("Thread[{0}]--myThreadHandler.Message.callback.run",

    Thread.currentThread().getName()));

    }

    });

    3.Handler对Activity finish影响。

    在开发的过程中碰到一个棘手的问题,调用Activity.finish函数Acitivity没有执行生命周期的ondestory函数,后面查找半天是因为有一个handler成员,因为它有一个delay消息没有处理,调用Activity.finish,Activity不会马上destory,所以记得在Ativity finish前清理一下handle中的未处理的消息,这样Activity才会顺利的destory

    展开全文
  • Handler 高级用法

    2021-03-22 11:19:09
    Handler原理简述只做简单概述,具体详细细节可查看相关源码1.handler发送消息根据时间先后顺序插入到消息队列public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {if (delayMillis &...

    Handler原理简述

    只做简单概述,具体详细细节可查看相关源码

    1.handler发送消息根据时间先后顺序插入到消息队列

    public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {

    if (delayMillis < 0) {

    delayMillis = 0;

    }

    //根据消息具体的执行时间点排序

    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);

    }

    2.Looper.loop()不断从消息队列中取消息

    for (;;) {

    //不断从消息队列中取消息 queue.next()会阻塞

    Message msg = queue.next(); // might block

    if (msg == null) {

    // No message indicates that the message queue is quitting.

    return;

    }

    ...

    ...

    //取消消息后回调 handler分发消息 msg.target是发送消息的handler

    msg.target.dispatchMessage(msg);

    ...

    ...

    }

    }

    3.MessageQueue.next() 取消息,重点分析

    Message next() {

    //mPtr 相当于一把锁

    final long ptr = mPtr;

    if (ptr == 0) {

    return null;

    }

    int pendingIdleHandlerCount = -1; // -1 only during first iteration

    //距离最近的消息需要等待的时间

    int nextPollTimeoutMillis = 0;

    for (;;) {

    if (nextPollTimeoutMillis != 0) {

    Binder.flushPendingCommands();

    }

    //等待 nextPollTimeoutMillis

    nativePollOnce(ptr, nextPollTimeoutMillis);

    synchronized (this) {

    // Try to retrieve the next message. Return if found.

    final long now = SystemClock.uptimeMillis();

    Message prevMsg = null;

    Message msg = mMessages;

    //重点 如果消息头是一个屏障消息(标志:msg.target == null)

    if (msg != null && msg.target == null) {

    // Stalled by a barrier. Find the next asynchronous message in the queue.

    //查找下一个 msg.isAsynchronous() = true 的消息,如果没有 msg =null

    //将会等待进入休眠状态,不会处理msg.isAsynchronous() = false的消息

    //所以当消息头为屏障消息是,只会处理异步消息,之后的同步消息和屏障消息都不处理

    //如果没有异步消息将会进入休眠状态

    do {

    prevMsg = msg;

    msg = msg.next;

    } while (msg != null && !msg.isAsynchronous());

    }

    //msg != null 说明头部不是屏障头,或者是屏障消息头且找到了异步消息

    if (msg != null) {

    if (now < msg.when) {

    // Next message is not ready. Set a timeout to wake up when it is ready.

    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);

    } else {

    // Got a message.

    mBlocked = false;

    if (prevMsg != null) {

    //如果是消息头是屏障消息,队列移除找到的异步消息,消息头不变,还是屏障消息

    prevMsg.next = msg.next;

    } else {

    //如果是消息头是不是屏障消息,队列移除找到的消息,消息头后移

    mMessages = msg.next;

    }

    msg.next = null;

    if (DEBUG) Log.v(TAG, "Returning message: " + msg);

    msg.markInUse();

    return msg;

    }

    } else {

    // No more messages.

    nextPollTimeoutMillis = -1;

    }

    ····

    ····

    }

    }

    4.简单总结一下

    1.消息队列中可存放三种消息,屏障消息(msg.target == null),异步消息(msg.isAsynchronous()= true),同步消息(msg.isAsynchronous()= false)

    2.如果消息头不是屏障消息,则异步消息和同步消息没有区别,消息队列头会后移

    3.如果消息头是屏障消息,则只能通过异步消息,不能通过同步消息,消息队列头不会后移,只能手动移除

    发送三种消息

    1.发送普通消息,当然handler可指定默认消息类型

    //构造方法 async

    public Handler(boolean async) {

    this(null, async);

    }

    private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,

    long uptimeMillis) {

    msg.target = this;

    msg.workSourceUid = ThreadLocalWorkSource.getUid();

    if (mAsynchronous) {

    msg.setAsynchronous(true);

    }

    return queue.enqueueMessage(msg, uptimeMillis);

    }

    //如果handler mAsynchronous = ture ,设置message的isAsynchronous= false无效,

    //此handler发送的消息都是异步消息

    val obtainMessage = handler.obtainMessage().apply {

    what = 1

    isAsynchronous = false

    obj = "普通消息”

    }

    handler.sendMessageDelayed(obtainMessage, time)

    2.发送异步消息

    val obtainMessage = handler.obtainMessage().apply {

    what = 2

    isAsynchronous = true

    obj = "异步消息”

    }

    handler.sendMessageDelayed(obtainMessage, time)

    3.发送屏障消息,同步异步消息只有在遇到屏障头消息时才有效,查看源码

    /*

    * @hide

    */

    @TestApi

    public int postSyncBarrier() {

    return postSyncBarrier(SystemClock.uptimeMillis());

    }

    // 注意:when是计算后的时间

    //可以看出屏障消息的特点是msg.target == null,且msg.isAsynchronous() = false

    private int postSyncBarrier(long when) {

    synchronized (this) {

    final int token = mNextBarrierToken++;

    final Message msg = Message.obtain();

    msg.markInUse();

    msg.when = when;

    msg.arg1 = token;

    Message prev = null;

    Message p = mMessages;

    if (when != 0) {

    while (p != null && p.when <= when) {

    prev = p;

    p = p.next;

    }

    }

    if (prev != null) { // invariant: p == prev.next

    msg.next = p;

    prev.next = msg;

    } else {

    msg.next = p;

    mMessages = msg;

    }

    return token;

    }

    }

    4.发送屏障消息,反射调用

    //获取 发送屏障消息postSyncBarrier函数

    private val postSyncBarrier = MessageQueue::class.java.getDeclaredMethod("postSyncBarrier", Long::class.java).apply {

    isAccessible = true

    }

    //获取 撤销屏障消息 removeSyncBarrier函数

    private val removeSyncBarrier = MessageQueue::class.java.getDeclaredMethod("removeSyncBarrier", Int::class.java).apply {

    isAccessible = true

    }

    使用Demo

    //初始化handler

    private val handler = object : Handler(Looper.getMainLooper()) {

    override fun handleMessage(msg: Message) {

    super.handleMessage(msg)

    Log.d(TAG, "handleMessage:-${msg.what}--${msg.isAsynchronous}-- ${msg.obj}--${msg.`when`}")

    when (msg.what) {

    0 -> {

    //收到消息后异常屏障,注意只能用异步消息移除屏障

    removeSyncBarrier.invoke(queue, msg.g1)

    }

    }

    }

    }

    //获取当前队列

    private val queue = handler.looper.queue

    //获取队列的postSyncBarrier函数

    private val postSyncBarrier = MessageQueue::class.java.getDeclaredMethod("postSyncBarrier", Long::class.java).apply {

    isAccessible = true

    }

    //获取队列的removeSyncBarrier函数

    private val removeSyncBarrier = MessageQueue::class.java.getDeclaredMethod("removeSyncBarrier", Int::class.java).apply {

    isAccessible = true

    }

    private fun senMsg(handler: Handler, w: Int, async: Boolean, str: String, time: Long, arg: Int = 0) {

    val obtainMessage = handler.obtainMessage().apply {

    what = w

    arg1 = arg

    isAsynchronous = async

    obj = str

    }

    handler.sendMessageDelayed(obtainMessage, time)

    }

    override fun onCreate(savedInstanceState: Bundle?) {

    super.onCreate(savedInstanceState)

    setContentView(R.layout.activity_main)

    senMsg(handler, 1, false, "同步消息", 1000)

    //发送屏障消息 返回屏障标识token

    val token = postSyncBarrier.invoke(queue, SystemClock.uptimeMillis() + 2000)

    senMsg(handler, 2, false, "同步消息", 3000)

    senMsg(handler, 3, false, "同步消息", 4000)

    senMsg(handler, 4, true, "isAsynchronous 异步消息 ", 5000)

    senMsg(handler, 5, false, "同步消息", 6000)

    senMsg(handler, 6, true, "isAsynchronous 异步消息", 7000)

    senMsg(handler, 7, false, "同步消息", 8000)

    senMsg(handler, 8, true, "isAsynchronous 异步消息", 9000)

    //发送0 移除屏障token

    senMsg(handler, 0, true, "isAsynchronous 移除屏障", 9000, token as Int)

    senMsg(handler, 9, false, "同步消息", 10 * 1000)

    senMsg(handler, 10, false, "同步消息", 11 * 1000)

    senMsg(handler, 11, true, "isAsynchronous 异步消息", 12 * 1000)

    senMsg(handler, 12, false, "同步消息", 13 * 1000)

    senMsg(handler, 13, false, "同步消息", 14 * 1000)

    senMsg(handler, 11, true, "isAsynchronous 异步消息", 15 * 1000)

    }

    测试结果

    //1 消息后是一个屏障消息

    19:54:37.854 : handleMessage:-1--false-- 同步消息--11075427

    //只处理异步消息

    19:54:41.857 : handleMessage:-4--true-- isAsynchronous 异步消息 --11079427

    19:54:43.855 : handleMessage:-6--true-- isAsynchronous 异步消息--11081427

    19:54:45.855 : handleMessage:-8--true-- isAsynchronous 异步消息--11083427

    //收到0后 会移除屏障消息

    19:54:45.855 : handleMessage:-0--true-- isAsynchronous 移除屏障--11083427

    //继续按照队列的顺序正常执行

    19:54:45.855 : handleMessage:-2--false-- 同步消息--11077427

    19:54:45.856 : handleMessage:-3--false-- 同步消息--11078427

    19:54:45.856 : handleMessage:-5--false-- 同步消息--11080427

    19:54:45.856 : handleMessage:-7--false-- 同步消息--11082427

    19:54:46.854 : handleMessage:-9--false-- 同步消息--11084427

    19:54:47.854 : handleMessage:-10--false-- 同步消息--11085427

    19:54:48.854 : handleMessage:-11--true-- isAsynchronous 异步消息--11086427

    19:54:49.854 : handleMessage:-12--false-- 同步消息--11087427

    19:54:50.855 : handleMessage:-13--false-- 同步消息--11088428

    19:54:51.855 : handleMessage:-11--true-- isAsynchronous 异步消息--11089428

    展开全文
  • Handler 使用详解

    千次阅读 2021-02-27 20:50:00
    每日十点,和您一起终身学习,这里是程序员Android本篇文章主要介绍 Android 开发中的部分知识点,通过阅读本篇文章,您将收获以下内容:Handler 消息处理机制原理Handler 机制处理的4个关键对象Handler常用方法子线...

    1c272b63e1e098ac69ab49e1a813b1d3.gif

    d85f2eccb2341c07ed074177a4c922dc.png

    阅读五分钟,每日十点,和您一起终身学习,这里是程序员Android

    本篇文章主要介绍 Android 开发中的部分知识点,通过阅读本篇文章,您将收获以下内容:

    Handler 消息处理机制原理

    Handler 机制处理的4个关键对象

    Handler常用方法

    子线程更新UI 异常处理

    主线程给子线程发送消息的方法

    子线程给主线程发送消息的方法

    主、子 线程 互发消息方法

    子线程方法中调用主线程更新UI的方法

    Handler是 Android中用来更新UI 的一套消息处理机制。Handler 允许线程间发送Message或Runnable对象进行通信。在Android中UI修改只能通过UI Thread,子线程不能更新UI。如果子线程想更新UI,需要通过 Handler发送消息给主线程,进而达到更新UI的目的。

    Handler 简介

    继承关系如下:

    java.lang.Object

    ↳ android.os.Handler

    1. Handler 消息处理机制原理

    当Android 应用程序创建的时候,系统会给每一个进程提供一个Looper,Looper 是一个死循环,它内部维护一个消息队列,Looper不停的从消息队列中取Message,取到的消息就发送给handler,最后Handler 根据接收的消息去修改UI等。

    2. Handler 机制处理的4个关键对象

    1.Message

    线程之间传递的消息,可以携带一些简单的数据供子线程与主线程进行交换数据。

    2.Message Queue

    存放通过Handler 发送的Message 的消息队列,每一个线程只有一个消息队列。

    3.Handler

    消息处理者,主要用于发送跟处理消息。

    主要功能:

    发送消息SendMessage()

    处理消息 HandleMessage()

    4.Looper

    内部包含一个死循环的MessageQueue,用于存储handler发送的Message,Looper则是不断的从消息队列中取消,如果有消息就取出发送给Handler 处理,没有则阻塞。

    总结:

    Handler负责发送Message到Message Queue,Looper负责从Message Queue 遍历Message ,然后直接把遍历的消息回传给Handler自己,通过Handler自身的handleMessage处理更新UI等操作。

    41d69e91fe102c4d5e07d45585f71742.png

    3. Handler常用方法

    1.Runnable对象

    post(Runnable)

    使用方法举例:

    public void BtnRunnableMethod(View view) {

    // 1.Runnable 对象

    RunnableHandlderMethod();

    }

    /**

    * Runnable 对象更新 UI

    * **/

    private Handler mRunnableHandler = new Handler();

    public void RunnableHandlderMethod() {

    new Thread() {

    @Override

    public void run() {

    try {

    Thread.sleep(1000);

    mRunnableHandler.post(new Runnable() {

    @Override

    public void run() {

    ((Button) findViewById(R.id.btn_runnable))

    .setText("Runnable");

    }

    });

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    }

    }.start();

    }

    postAtTime(Runnable, long)

    postDelayed(Runnable, long)

    2. Message 对象

    sendEmptyMessage(int)

    使用方法举例:

    public void BtnMessageThreadMethod(View view) {

    // 2.Message 对象

    new MessageHandlerThreadMethod("子线程不能更新UI").start();

    }

    /**

    * Message 对象举例

    * ***/

    private int mCount = 0;

    private Handler mMessageHandler = new Handler() {

    @Override

    public void handleMessage(Message msg) {

    super.handleMessage(msg);

    ((Button) findViewById(R.id.btn_thread)).setText("" + mCount);

    }

    };

    class MessageHandlerThreadMethod extends Thread {

    String mString;

    public MessageHandlerThreadMethod(String str) {

    mString = str;

    }

    @Override

    public void run() {

    for (int i = 0; i < 10; i++) {

    try {

    Thread.sleep(1000);

    } catch (Exception e) {

    }

    mCount++;

    mMessageHandler.sendEmptyMessage(0);

    }

    }

    }

    sendMessage(Message)

    使用方法举例:

    public void BtnMessageObjMethod(View view) {

    HandlerMessageObjMethods();

    }

    /***

    * handler sendmessage 处理方法

    * **/

    private Handler mHandlerMessageObj = new Handler() {

    @Override

    public void handleMessage(Message msg) {

    ((Button) findViewById(R.id.btn_message)).setText("arg1:"

    + msg.arg1 + "\n" + msg.obj);

    }

    };

    private void HandlerMessageObjMethods() {

    new Thread() {

    @Override

    public void run() {

    try {

    Thread.sleep(1000);

    // Message message = new Message();

    Message message = mHandlerMessageObj.obtainMessage();

    message.arg1 = 100;

    Person person = new Person();

    person.name = "Lucy";

    person.age = 12;

    message.obj = person;

    mHandlerMessageObj.sendMessage(message);

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    }

    }.start();

    }

    class Person {

    public int age;

    public String name;

    public String toString() {

    return "Name=" + name + "\n Age=" + age;

    }

    }

    sendMessageAtTime(Message, long),

    sendMessageDelayed(Message, long)

    3.接收、处理Message

    handleMessage(Message)

    使用方法举例:

    private Handler mMessageHandler = new Handler() {

    @Override

    public void handleMessage(Message msg) {

    super.handleMessage(msg);

    ((Button) findViewById(R.id.btn_thread)).setText("" + mCount);

    }

    };

    4. 子线程更新UI 异常处理

    子线程不能更新UI,如果在子线程中更新UI,会出现CalledFromWrongThreadException 异常。

    CalledFromWrongThreadException

    1a834156aa3af30aa4da17da679a6e5b.png

    解决方法:

    子线程通过Handler发送消息给主线程,让主线程处理消息,进而更新UI。

    5. 主线程给子线程发送消息的方法

    此例子中子线程通过Looper不断遍历主线程发送的消息,Looper使用方法如下:

    准备Looper 轮询器

    Looper.prepare();

    Handler 处理遍历消息

    Handler mHandler = new Handler()

    遍历消息队列

    Looper.loop();

    Looper 使用方法如下:

    // 自定义 Loop 线程 ---> 不停的处理主线程发的消息

    class ChildLooperThread extends Thread {

    @Override

    public void run() {

    // 1.准备成为loop线程

    Looper.prepare();

    // 2.处理消息

    mMainHandler = new Handler() {

    // 处理消息

    public void handleMessage(Message msg) {

    super.handleMessage(msg);

    ... ...

    }

    });

    }

    };

    // 3.Loop循环方法

    Looper.loop();

    }

    }

    主线程发送消息给子线程 的使用例子如下:

    启动 子线程,并再启动后发送消息

    public void BtnMainMessageMethod(View view) {

    // 点击主线程 按钮,启动子线程,并在子线程启动后发送消息

    Message msg = new Message();

    msg.obj = "主线程:这是我携带的信息";

    if (mMainHandler != null) {

    // 2.主线程发送消息

    mMainHandler.sendMessage(msg);

    } else {

    Toast.makeText(getApplicationContext(), "开启子线程轮询消息,请再次点击发送消息",

    Toast.LENGTH_SHORT).show();

    // 1.开启轮询线程,不断等待接收主线成消息

    new ChildLooperThread().start();

    }

    }

    子线程启动,不停的变量主线程发送的消息

    private Handler mMainHandler;

    String mMainMessage;

    // 自定义 Loop 线程 ---> 不停的处理主线程发的消息

    class ChildLooperThread extends Thread {

    @Override

    public void run() {

    // 1.准备成为loop线程

    Looper.prepare();

    // 2.处理消息

    mMainHandler = new Handler() {

    // 处理消息

    public void handleMessage(Message msg) {

    super.handleMessage(msg);

    mMainMessage = (String) msg.obj;

    Log.i("TAG", "子线程:从主线程中接受的消息为:\n" + mMainMessage);

    // 使用 runOnUiThread 在主线程中更新UI

    runOnUiThread(new Runnable() {

    @Override

    public void run() {

    ((Button) findViewById(R.id.btn_main_message))

    .setText(mMainMessage);

    }

    });

    }

    };

    // 3.Loop循环方法

    Looper.loop();

    }

    }

    6. 子线程给主线程发送消息的方法

    1.子线程发送消息给主线程方法

    public void BtnChildMessageMethod(View view) {

    new Thread() {

    public void run() {

    while (mCount < 100) {

    mCount++;

    try {

    Thread.sleep(100);

    } catch (InterruptedException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }

    /**

    * 利用handler 对象发送消息 Message msg=Message.obtain(); Message

    * msg=new Message(); 获取一个消息对象message

    * */

    Message msg = Message.obtain();

    // 消息标记

    msg.what = 1;

    // 传递整型值msg.obj="传递object数据"

    msg.arg1 = mCount;

    Log.i("TAG", "count 值=" + mCount);

    if (mhandler != null) {

    mhandler.sendMessage(msg);

    }

    }

    }

    }.start();

    }

    2.主线程接收并处理消息的方法

    // 定义一个handler 主线程 接收子线程发来的信息

    private Handler mhandler = new Handler() {

    // 處理消息的方法

    public void handleMessage(android.os.Message msg) {

    switch (msg.what) {

    case 1:

    int value = msg.arg1;

    Log.i("TAG", "value值=" + value);

    ((Button) findViewById(R.id.btn_child_message)).setText("当前值="

    + value);

    break;

    default:

    break;

    }

    }

    };

    7. 主、子 线程 互发消息方法

    主要实现主、子线程每隔1s中通信一次

    实现打印Log如下:

    d4ba5fa720002b19ebd4d3ef251d6ffd.png

    实现方法如下:

    启动子线程并发送给主线程消息

    public void BtnMainChildMessageMethod(View view) {

    // 创建 名称为currentThread 子线程

    HandlerThread mChildThread = new HandlerThread("ChildThread");

    mChildThread.start();

    mChildHandler = new Handler(mChildThread.getLooper()) {

    @Override

    public void handleMessage(Message msg) {

    Log.i("TAG", "主线程对我说:" + msg.obj);

    // 子线程携带的消息

    Message message = new Message();

    message.obj = Thread.currentThread() + "我是子线程,小样,让我听你的没门";

    // 向主线程发送消息

    mainhandler.sendMessageDelayed(message, 1000);

    }

    };

    // 主线成发送空消息,开启通信

    mainhandler.sendEmptyMessage(1);

    }

    2.主线程接收并处理子线程发送的消息

    // 创建主线程

    private Handler mainhandler = new Handler() {

    @Override

    public void handleMessage(Message msg) {

    Log.i("TAG", "子线程对我说:" + msg.obj);

    // 主线成携带的消息内容

    Message message = new Message();

    message.obj = Thread.currentThread() + "我是主线程:小子你得听我的。";

    // 向子线程发送消息

    mChildHandler.sendMessageDelayed(message, 1000);

    }

    };

    8.子线程方法中调用主线程更新UI的方法

    Activity 中 可以使用 runOnUiThread(Runnable)

    // 使用 runOnUiThread 在主线程中更新UI

    runOnUiThread(new Runnable() {

    @Override

    public void run() {

    ((Button) findViewById(R.id.btn_main_message))

    .setText(mMainMessage);

    }

    });

    子线程使用 Handler.post(Runnable)

    mRunnableHandler.post(new Runnable() {

    @Override

    public void run() {

    ((Button) findViewById(R.id.btn_runnable))

    .setText("Runnable");

    }

    });

    View.post()

    ((Button) findViewById(R.id.btn_runnable)).post(new Runnable() {

    @Override

    public void run() {

    // TODO Auto-generated method stub

    ((Button) findViewById(R.id.btn_runnable)).setText("View.post()方法使用");

    }

    });

    Handler.sendMessage(Message)

    public void BtnMainMessageMethod(View view) {

    // 点击主线程 按钮,启动子线程,并在子线程启动后发送消息

    Message msg = new Message();

    msg.obj = "主线程:这是我携带的信息";

    if (mMainHandler != null) {

    // 2.主线程发送消息

    mMainHandler.sendMessage(msg);

    }

    }

    9.移除Handler 发送的消息方法

    1.移除 handler 发送的所有消息

    private Handler mChildHandler;

    mChildHandler.removeCallbacksAndMessages(null);

    2.移除 指定消息

    private Handler mainhandler;

    mainhandler.removeMessages(what);

    至此,本篇已结束,如有不对的地方,欢迎您的建议与指正。同时期待您的关注,感谢您的阅读,谢谢!

    db590a4fd388ef925a54667c21de0447.png

    展开全文
  • android handler使用,在讲handler之前,我们先提个小问题,就是如何让程序5秒钟更新一下title.首先我们看一下习惯了java编程的人,在不知道handler用法之前是怎么样写的程序,代码如下所示:package ...
  • Handler常用方法 子线程更新UI 异常处理 主线程给子线程发送消息的方法 子线程给主线程发送消息的方法 主、子 线程 互发消息方法 子线程方法中调用主线程更新UI的方法 Handler是 Android中用来更新UI 的一套...
  • Handler的基本用法

    2021-03-18 00:30:49
    Handler 的Send message ,可以传: what , arg1 ,arg2 ,obj :packagecom.example.userrecyclerviewapplication;importandroidx.annotation.NonNull;importandroidx.appcompat.app.AppCompatActivity;importandroid....
  • 本文实例讲述了Android定时器和Handler用法。分享给大家供大家参考。具体分析如下:一、环境:主机:WIN8开发环境:Android Studio二、定时器使用示例:初始化://定时器private Timer Timer_Work = new Timer();//...
  • MP typeHandler 用法

    2021-06-18 13:48:11
    typeHandler 可以在新增、更新、查询时候字段进行数据类型转换与解析 步骤1、实体类配置注解: // 只针对jdbcType为varchar的字段进行mapping处理,勿略jdbcType设置为空的字段 @MappedJdbcTypes...
  • Handler用法 /** * 1、Handler内存泄露测试 * 2、为什么不能在子线程创建Handler * 3、textView.setText()只能在主线程执行,这句话是错误! * 4、new Handler()两种写法有什么区别? * 5、ThreadLocal用法...
  • Android——Handler详解

    2021-05-27 10:58:53
    1. 简介 Handler是一套 Android ...使用Handler消息传递机制主要是为了多个线程并发更新UI的同时,保证线程安全 2. 相关概念解释 Handler、Message、Message Queue、Looper Android消息机制: 以Handler的sendMes
  • 一、Handler Handler是一个用作线程之间相互通信的类。...当一条message通过handler的sendmessage方法被发送以后,这条消息就会加入到MessageQueue队列中,等待被发送到handler对象的回调方法handler
  • 一、Handler的定义:Handler主要接收子线程发送的数据, 并用此数据配合主线程更新UI,用来跟UI主线程交互用。比如可以用handler发送一个message,然后在handler的线程中来接收、处理该消息,以避免直接在UI主线程中...
  • boost::log::make_exception_handler用法的测试程序实现功能C++实现代码 实现功能 boost::log::make_exception_handler用法的测试程序 C++实现代码 #include <cstddef> #include <string> #include <...
  • private Handler uiHandler = new Handler() {//handler线程是主要用来和UI主线程进行交互的 @Overridepublic voidhandleMessage(Message msg) {super.handleMessage(msg);switch(msg.what) {case 1:if (!paused) { ...
  • } /** * 方法目标执行之后 * @param request * @param response * @param handler * @param modelAndView * @throws Exception */ @Override public void postHandle(HttpServletRequest request, ...
  • Android中Handler用法

    2021-06-05 18:05:43
    说明啦handler可以处理一些消息,这些...因为程序里使用啦多线程,线程中要输出一些消息提示,然而直接在线程中弹消息框会异常,所以就用这些方式,发一个消息出来实现消息框@SuppressLint("HandlerLeak")publicHan...
  • 本文主要是对Android中Handler的作用于如何使用进行了初步介绍,如果大家想了解Handler的内部实现原理,可以参见下一篇博文《深入源码解析Android中的Handler,Message,MessageQueue,Looper》。
  • 那么你一定遇到过这样的错误提示“android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.”这个时候就需要使用Handler...
  • 这篇文章介绍了Android消息机制Handler用法总结,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧 1.简述 Handler消息机制主要包括: MessageQueue、 Handler、 Looper、...
  • Handler使用例1这个例子是最简单的介绍handler使用的,是将handler绑定到它所建立的线程中.本次实验完成的功能是:单击Start按钮,程序会开始启动线程,并且线程程序完成后延时1s会继续启动该线程,每次线程的run函数...
  • Handler用法

    2021-04-17 08:49:08
    Handler在线程通讯中起到了一个枢纽作用:Handler即负责和消息队列打交道,也负责处理相应的消息,其他线程通过Handler和主线程通讯,就可以不需要考虑和主线程的竞争和同步问题,极大的简化了线程的使用。...
  • 可通过自定义的TypeHandler实现某个属性在插入数据库以及查询时的自动转换,本例中是要将Map类型的属性转化成CLOB,然后存入数据库。由于是复杂的Map,mp自带的json转换器会丢失部分信息。 类型转换器还可以通过注解...
  • 最近一直在学习多线程,handler的作用真的很重要啊,所以保存这篇看的蛮懂的。Handler mHandler = newHandler();mHandler.post(newRunnable() {@...下面我们先来看一下这个方法是怎么执行的首先:public final bool...
  • Handler

    2021-03-16 06:55:28
    Handler使用方法原理消息屏障异步消息IdelHandlerHandler.CallbackActivity中使用HandlerHandler native层nativeInit()nativeDestroy()nativePollOnce()HandlerThread面试问题总结1. 为什么主线程调用了Looper的loop...
  • Handler默认关联主线程,虽然要提供Runnable参数,但默认是直接调用Runnable中的run()方法。也就是默认下会在主线程执行,如果在这里面的操作会有阻塞,界面也会卡住。如果要在其他线程执行,可以使用HandlerThread...
  • 背景Android 11(即API 30:Android R)弃用了Handler默认的无参构造方法 源代码(android.os.Handler)//API 30,Android 11/*** Default constructor associates this handler with the {@link Looper} for the* ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 499,274
精华内容 199,709
关键字:

handler用法