以下未发布-Android的多线程以及异步消息处理机制

private Button but_send;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

text=(TextView)findViewById(R.id.text);

but_send=(Button)findViewById(R.id.sendMessage);

but_send.setOnClickListener(this);

}

@Override

public void onClick(View v){

switch(v.getId()){

case R.id.sendMessage:

new Thread() {

@Override

public void run() {

text.setText(“sendMessage()”);

}

}.start();

break;

default:

break;

}

}

}

程序运行后结果:

在这里插入图片描述

可以很容易地看出,该例子实现点击sendMessage按钮来打开一个线程将屏幕中的Hello World!改为sendMessage()。代码的逻辑很简单,只不过我们是在子线程中更新UI的。当点击sendMessage按钮,你会发现程序崩溃了,我们看下错误报告,如下图所示:

error

可以看出,Android确实是不允许在子进程中进行UI操作的。但有的时候,我们在子进程中执行一些耗时任务时必须更改UI内容,这该怎么么办呢?

事实上,对于这种情况Android提供了一套异步消息的处理机制,完美地解决了在子进程中进行UI操作的问题。

二、异步消息处理机制


Android中的异步消息处理主要由4个部分组成:Message、Handler、MessageQueue和Looper,每个线程只能有一个MessageQueue和Looper,可以有多个Hanlder。

1.Message:

Message 是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间进行数据交换。除了 what 字段,还可以使用 arg1 和 arg2 来携带整型数据,使用 obj 来携带 Object 数据。

2、Handler:

Handler主要用于发送和处理消息的。发送消息一般是使用Handler的sendMessage()方法,而发出的消息经过一系列的处理后,最终会传递到Handler的handleMessage()方法中。

3、MessageQueue:

MessageQueue是消息队列,主要用于存放所有通过Handler发送的消息。这部分消息会一直存放在于消息队列中,等待被处理。每个线程中只会有一个MessageQueue。

4、Looper:

用于管理 MessageQueue 队列,调用 Looper.loop() 方法之后,就会进入无限循环中,每当发现 MessageQueue 存在一条消息,就会将它取出,并传递到 Handler 的 handleMessage() 方法中。每个线程中只会有一个 Looper 对象。

了解了Message、Handler、MessageQueue和Looper的基本概念后,我们再通过图例来更清晰地理解异步消息处理,如下图所示:

# 贴贴

可以清晰地看到整个异步消息的处理过程。首先需要在UI县城中创建一个Handler对象,然后在子线程中调用Handle的sendMessage()方法,接着这个消息会存放在UI线程的MessageQueue中,通过Looper对象取出MessageQueue中的消息,最后分发会Handler的handleMessage()方法中。

二、异步消息处理机制实现


Handler机制

  • Handler 的使用

Handler 有两种使用方法,一种是 sendMessage(Message) ,另一种是 post(Runnable)。通过修改上述例子来进行展示。

修改main_activity布局,在原基础上添加一了一个按钮:

<?xml version="1.0" encoding="utf-8"?>

<android.support.constraint.ConstraintLayout xmlns:android=“http://schemas.android.com/apk/res/android”

xmlns:app=“http://schemas.android.com/apk/res-auto”

xmlns:tools=“http://schemas.android.com/tools”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

tools:context=“.MainActivity”>

<Button

android:id=“@+id/sendMessage”

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:text=“sendMessage()”

app:layout_constraintTop_toTopOf=“parent”

app:layout_constraintRight_toRightOf=“parent”

app:layout_constraintLeft_toLeftOf=“parent” />

<Button

android:id=“@+id/post”

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:text=“post()”

app:layout_constraintHorizontal_bias=“0.0”

app:layout_constraintLeft_toLeftOf=“parent”

app:layout_constraintRight_toRightOf=“parent”

app:layout_constraintTop_toBottomOf=“@id/sendMessage” />

<TextView

android:id=“@+id/text”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:text=“Hello World!”

app:layout_constraintBottom_toBottomOf=“parent”

app:layout_constraintLeft_toLeftOf=“parent”

app:layout_constraintRight_toRightOf=“parent”

app:layout_constraintTop_toTopOf=“parent” />

</android.support.constraint.ConstraintLayout>

修改MainActivity:

package com.example.threaddemo;

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 TextView text;

private Button but_send;

private Button but_post;

private static final int SENDMESSAGE=1;

//创建handler

private Handler handler1=new Handler(){

public void handleMessage(Message msg){

switch(msg.what){//将接收到的消息与SENDMESSAGE进行匹配

case SENDMESSAGE:

text.setText(“sendMessage()”);

break;

default:

break;

}

}

};

private Handler handler2=new Handler();

private final Runnable runnable = new Runnable() {

@Override

public void run() {

//更新UI显示

MainActivity.this.text.setText(“post()”);

}

};

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

text=(TextView)findViewById(R.id.text);

but_send=(Button)findViewById(R.id.sendMessage);

but_post=(Button)findViewById(R.id.post);

but_post.setOnClickListener(this);

but_send.setOnClickListener(this);

}

@Override

public void onClick(View v){

switch(v.getId()){

//Handler的sendMessage()方法

case R.id.sendMessage:

new Thread(new Runnable() {

@Override

public void run() {

Message msg = new Message();

msg.what = SENDMESSAGE;

handler1.sendMessage(msg);

}

}).start();

break;

//Handler的post方法

case R.id.post:

new Thread(new Runnable() {

@Override

public void run() {

handler2.post(runnable);

}

}).start();

break;

default:

break;

}

}

}

实现效果展示:

# 贴图贴图贴图

观察sendMessage()的源码和post()的源码:

/**

*Pushes a message onto the end of the message queue after all pending messages

  • before the current time.

  • 将消息添加到消息队列。

*/

public final boolean sendMessage(Message msg)

{

return sendMessageDelayed(msg, 0);

}

/**

  • Causes the Runnable r to be added to the message queue.

  • 把任务对象r添加到消息队列中。

*/

public final boolean post(Runnable r)

{

return sendMessageDelayed(getPostMessage®, 0);

}

/**

*Enqueue a message into the message queue after all pending messages

*post方法中调用发送延时消息的方法,把这个消息放入消息队列。

*/

public final boolean sendMessageDelayed(Message msg, long delayMillis)

{

if (delayMillis < 0) {

delayMillis = 0;

}

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

}

/post中调用的另外一个方法,我们很容易看出来,这个方法就是把任务r包装成了一个空的消息并且返回/

private static Message getPostMessage(Runnable r) {

Message m = Message.obtain();

m.callback = r;

return m;

}

可以看出handler.post和handler.sendMessage本质上是没有区别的,都是发送一个消息到消息队列中,而且消息队列和handler都是依赖于同一个线程的。

  • Handler内存泄漏问题及其解决办法

Android用java语言编写的,其中java提供了自动的GC机制(Garbage Collection)即垃圾回收机制,采用对象引用计数的方式。在分析Handler导致的内存泄漏问题前我们自然先要了解GC是怎么回收内存的。

首先,Java的垃圾回收机制使用有向图机制,通过GC自动检查内存中的对象,如果GC发现一个或一组对象为不可到达状态,则将该对象从内存中回收。也就是说,一个对象不被任何引用所指向,则该对象会在被GC发现的时候被回收;另外,如果一组对象中只包含互相的引用,而没有来自它们外部的引用(例如有两个对象A和B互相持有引用,但没有任何外部对象持有指向A或B的引用),这仍然属于不可到达,同样会被GC回收。

private Handler handler=new Handler(){

public void handleMessage(Message msg){

switch(msg.what){//将接收到的消息与SENDMESSAGE进行匹配

case SENDMESSAGE:

text.setText(“sendMessage()”);

break;

default:

break;

}

最后

上面这些公司都是时下最受欢迎的互联网大厂,他们的职级、薪资、福利也都讲的差不多了,相信大家都是有梦想和野心的人,心里多少应该都有些想法。

也相信很多人也都在为即将到来的金九银十做准备,也有不少人的目标都是这些公司。

我这边有不少朋友都在这些厂工作,其中也有很多人担任过面试官,上面的资料也差不多都是从朋友那边打探来的。除了上面的信息,我这边还有这些大厂近年来的面试真题及解析,以及一些朋友出于兴趣和热爱一起整理的Android时下热门知识点的学习资料

部分文件:


行匹配

case SENDMESSAGE:

text.setText(“sendMessage()”);

break;

default:

break;

}

最后

上面这些公司都是时下最受欢迎的互联网大厂,他们的职级、薪资、福利也都讲的差不多了,相信大家都是有梦想和野心的人,心里多少应该都有些想法。

也相信很多人也都在为即将到来的金九银十做准备,也有不少人的目标都是这些公司。

我这边有不少朋友都在这些厂工作,其中也有很多人担任过面试官,上面的资料也差不多都是从朋友那边打探来的。除了上面的信息,我这边还有这些大厂近年来的面试真题及解析,以及一些朋友出于兴趣和热爱一起整理的Android时下热门知识点的学习资料

部分文件:
[外链图片转存中…(img-TExvmnWu-1720121636547)]
[外链图片转存中…(img-eUZsnca2-1720121636547)]
[外链图片转存中…(img-BD4ZmXHB-1720121636547)]

  • 16
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值