Android中的异步消息机制分为四个部分:Message、Handler、MessageQueue和Looper。

其中,Message是线程之间传递的消息,其what、arg1、arg2字段可以携带整型数据,obj字段可以携带一个Object对象。

Handler是处理者,主要用于发送消息和处理消息。发送消息的方法是sendMessage;处理消息的方法是handleMessage(),Message字段携带的信息在该方法中用作判别。

MessageQueue是消息队列,存放所有Handler发送的消息。

Looper是消息队列的“管家”,将消息从消息队列中一条条取出,并分派到Handler的handleMessage()方法中。

异步消息处理的流程为:

①首先,需要在主线程中创建一个Handler对象,并重写handleMessage()方法。

②当子线程处理完耗时操作,需要将处理结果反馈到UI中时,先创建一个Message对象,并让其what字段携带一个int值,然后通过Handler对象发送出去。

③之后该消息会被添加到MessageQueue中等待被处理,而Looper会一直尝试从MessageQueue中取出待处理消息,最后分发回Handler对象中的handleMessage()方法中。由于Handler对象是在主线程中创建的,所以可以在handleMessage()方法中安心地进行UI操作。

通过一个例子来验证一下:活动MainActivity中有一个按钮和一个TextView。TextView初始化显示“Hello World!”,之后点击按钮,进行耗时操作;耗时操作结束后,TextView显示“Nice to meet you”。根据以上的分析,我无比自然地写出了以下代码:

package com.shaking.androidthreadtest;

import android.os.Handler;

import android.os.Message;

import android.support.v7.app.AppCompatActivity;

import android.os.Bundle;

import android.view.View;

import android.widget.Button;

import android.widget.TextView;

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

private static final int UPDATE_TEXT=1;

private String data;

private TextView textView;

private Handler handler=new Handler(){

@Override

public void handleMessage(Message msg) {

switch (msg.what){

case UPDATE_TEXT:

textView.setText(data);

}

}

};

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main_layout);

Button button=findViewById(R.id.button);

textView=findViewById(R.id.text_view);

button.setOnClickListener(this);

}

@Override

public void onClick(View view) {

new Thread(new Runnable() {

@Override

public void run() {

//假设此处进行了耗时操作,最终得到结果字符串data

data="Nice to meet you";

Message message=new Message();

message.what=UPDATE_TEXT;

handler.sendMessage(message);

}

}).start();

}

}

首先,这么写,是肯定没有错误的!程序也可以正常运行。但是IDE给出了警告:“This Handler class should be static or leaks might occur”。

这个警告的意思是:我们使用Handler这个类时,应该将其声明为静态,否则会导致内存泄露。

那么,为什么会发生内存泄露呢?原因是:

第一:当我们通过Handler对象的sendMessage()方法发送一个Message对象时,该Message对象持有对该Handler对象的引用(正是依靠这个引用,Looper在消息队列中取出该Message对象后,才能准确地将该Message对象分派回该Handler对象!)。

第二,我们在主线程中创建Handler对象时,为了重写其handleMessage()方法,使用了匿名内部类的方式来创建该Handler对象。而匿名内部类和非静态内部类都是隐性地持有一个对外部类的引用!所以,该Handler对象持有外部类MainActivity的引用。

以上两个结合在一起,问题就来了:Message对象持有Handler对象引用,Handler对象持有MainActivity的引用。所以,MainActivity该活动永远无法被内存回收,直到Message被回收为止!如果Message对象在子线程中被发送至消息队列,然后一直没有被处理,该活动所在的主线程也会一直挂着,而不会被内存回收。所以,会导致内存泄露。

知道了原因,那么解决方法是什么?其实之前的警告,已经给出了解决方案。那就是通过静态内部类的方式创建Handler对象,因为静态内部类不会持有对外部类对象的引用。

这时候,我又自然而然地创建一个静态内部类,继承自Handler类,然后重写其handleMessage方法。

private static class MyHandler extends Handler{

@Override

public void handleMessage(Message msg) {

}

}

但是,此处又出现了一个问题!如果我不持有对外部类的引用了,那么我怎么使用外部类的方法和对象?毕竟我是要在handleMessage()方法中进行UI操作的。

对于这种使用了静态内部类来避免内存泄露,同时又需要调用外部类的方法的情况:可以使用弱引用!即我们在该内部类中声明一个对外部类对象的弱引用。这样即可以调用外部类的方法,又不会导致内存泄露。

具体修改后的代码,如下:

package com.shaking.androidthreadtest;

import android.os.Handler;

import android.os.Message;

import android.support.v7.app.AppCompatActivity;

import android.os.Bundle;

import android.view.View;

import android.widget.Button;

import android.widget.TextView;

import java.lang.ref.WeakReference;

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

private static final int UPDATE_TEXT=1;

private String data;

private TextView textView;

private static class MyHandler extends Handler{

//使该内部类持有对外部类的弱引用

private WeakReference weakReference;

//构造器中完成弱引用初始化

MyHandler(MainActivity activity){

weakReference=new WeakReference<>(activity);

}

@Override

public void handleMessage(Message msg) {

//通过弱引用的get()方法获得外部类对象的引用

MainActivity activity=weakReference.get();

activity.textView.setText(activity.data);

}

}

//创建Handler对象

private MyHandler handler=new MyHandler(this);

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main_layout);

Button button=findViewById(R.id.button);

textView=findViewById(R.id.text_view);

button.setOnClickListener(this);

}

@Override

public void onClick(View view) {

new Thread(new Runnable() {

@Override

public void run() {

//假设此处进行了耗时操作,最终得到结果字符串data

data="Nice to meet you";

Message message=new Message();

message.what=UPDATE_TEXT;

handler.sendMessage(message);

}

}).start();

}

}

完美解决以上所有问题!6~

最后推荐直接使用最后的解决方案:静态内部类+弱引用。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

android异步工作,Android异步消息机制详解相关推荐

  1. Android消息机制详解

    *本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 Android消息机制 这一定是一个被写烂了的专题吧.那本媛也来凑一个热闹吧.哈哈 这篇博客将会涉及以下内容: 消息机制概述 UM ...

  2. Android 消息机制详解(Android P)

    前言 Android 消息机制,一直都是 Android 应用框架层非常重要的一部分,想更加优雅的进行 Android 开发,我想了解消息机制是非常必要的一个过程,此前也分析过很多次 Handler ...

  3. 简述在android中如何发送广播消息,Android Intent发送广播消息实例详解

    Android Intent发送广播消息 Intent的另一种用途是发送广播消息,应用程序和Android系统都可以使用Intent发送广播消息,广播消息的内容是可以与应用程序密切相关的数据信息,也可 ...

  4. Handler消息机制详解

    Handler机制是Android开发中最常见的机制,可以说贯穿整个Android,在探究Handler机制原理之前,我们先来捋一下用法 1.handler.post(Runnable) 2.hand ...

  5. windows消息机制详解-3

    1. 引言 Windows 在操作系统平台占有绝对统治地位,基于Windows 的编程和开发越来越广泛. Dos 是过程驱动的,而Windows 是事件驱动的[6],这种差别的存在使得很多Dos 程序 ...

  6. Windows消息机制详解-5

    一. 什么是消息 在解释什么是消息之前,我们先讨论一下程序的执行机制问题.大体上说,程序按照执行机制可以分为两类: 第一类是过程驱动.比如我们最早接触编程时写的C程序,又或者单片机程序.这类程序往往预 ...

  7. Windows消息机制详解

    消息是指什么?      消息系统对于一个win32程序来说十分重要,它是一个程序运行的动力源泉.一个消息,是系统定义的一个32位的值,他唯一的定义了一个事件,向 Windows发出一个通知,告诉应用 ...

  8. Windows消息机制详解-6

    消息系统对于一个win32程序来说十分重要,它是一个程序运行的动力源泉.一个消息,是系统定义的一个32位的值,他唯一的定义了一个事件,向 Windows发出一个通知,告诉应用程序某个事情发生了.例如, ...

  9. Windows消息机制详解-2

    消息是指什么?      消息系统对于一个win32程序来说十分重要,它是一个程序运行的动力源泉.一个消息,是系统定义的一个32位的值,他唯一的定义了一个事件,向 Windows发出一个通知,告诉应用 ...

最新文章

  1. Linux地址映射--线性映射与非线性映射
  2. GitHub访问越来越慢了,怎么办?
  3. SQL数据库基础知识总结(三)---对象
  4. 车窗上为啥总有一些小黑点?没想到居然藏着大作用!
  5. oracle忽略除数为0,ora-01476除数为0的解决办法,oracle中decode()的使用
  6. Swin Transformer(W-MSA详解)代码+图解
  7. 排除MySQL中常见错误的实用招术
  8. 【华为云技术分享】Linux内核编程环境 (2)
  9. 团队管理(3)---如何成为一名优秀的管理者
  10. RectTransformUtility.ScreenPointToWorldPointInRectangle使用说明
  11. 几个找pdf资源的网站
  12. oracle误删表恢复方法
  13. 数理方程与特殊函数|均匀各向同性介质内的热传导方程
  14. 实现在线预览office文档(word,excel,ppt)的几种方法
  15. 是官方的-FeedDemon是炸弹
  16. 埃睿迪展台热度持续 为绿色城市建设进言献策
  17. js_window.open新标签页,当前标签页打开
  18. Light OJ 1129 Consistency Checker
  19. BatchNorm的作用--原理详解
  20. 泰坦尼克号幸存者预测 python 详解

热门文章

  1. C#空接合操作符——??
  2. IList对象排序算法
  3. 解决「matplotlib 图例中文乱码」问题
  4. angular--解决angular图片加载失败问题
  5. 更新条目时出错。有关详细信息,请参见内部异常。
  6. 【报告分享】2021年中国新经济企业500强发展研究报告.pdf(附下载链接)
  7. 【报告分享】快消产业互联网案例研究报告.pdf(附下载链接)
  8. 入门到精通!珍藏资源!VAE变分自编码器
  9. ACL2021 | 信息抽取相关论文
  10. 怎么调整矩形边框宽度_Illustrator实例教程:利用自定义画笔绘制中国风传统边框...