android Handler如何使用 以及runable thread等问题
android Handler如何使用
前言
android 多线程中Handler如何使用 以及runable thread等问题时常困扰着我,一直没机会弄明白就将就过去,现在有机会好好捋捋这东西
一、Handler是什么?
handler是一个处理两个线程间通信的消息机制。最常见的就是绑定ui线程,然后再绑定一个自定义的线程,自定义线程执行完毕后发消息给主线程ui更新UI界面
二、Thread和runable的关系
Thread是runable的一个子类,一种具体实现。
Thread这种具体实现在每次实例化的时候都是单独的对象
而runable实例化多次后为同一个对象执行同一个任务
具体见这举例说明
线程可以自己RUN也可以用Handler.post
三、一个应用
package com.example.module_learn.androidfunc.network;
import com.example.module_learn.R;
import com.example.module_learn.androidfunc.network.util.DateUtil;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.method.ScrollingMovementMethod;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
/**
* Created by ouyangshen on 2017/11/11.
*/
@SuppressLint("HandlerLeak")
public class MessageActivity extends AppCompatActivity implements OnClickListener {
private TextView tv_message; // 声明一个文本视图对象
private boolean isPlaying = false; // 是否正在播放新闻
private int BEGIN = 0, SCROLL = 1, END = 2; // 0为开始,1为滚动,2为结束
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_message);
// 从布局文件中获取名叫tv_message的文本视图
tv_message = findViewById(R.id.tv_message);
// 设置tv_message内部文字的对齐方式为靠左且靠下
tv_message.setGravity(Gravity.LEFT | Gravity.BOTTOM);
tv_message.setLines(8); // 设置tv_message高度为八行文字那么高
tv_message.setMaxLines(8); // 设置tv_message最多显示八行文字
// 设置tv_message内部文本的移动方式为滚动形式
tv_message.setMovementMethod(new ScrollingMovementMethod());
findViewById(R.id.btn_start_message).setOnClickListener(this);
findViewById(R.id.btn_stop_message).setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.btn_start_message) { // 点击了开始播放新闻的按钮
if (!isPlaying) {
isPlaying = true;
new PlayThread().start(); // 创建并启动新闻播放线程
}
} else if (v.getId() == R.id.btn_stop_message) { // 点击了结束播放新闻的按钮
isPlaying = false;
}
}
private String[] mNewsArray = {
};
// 定义一个新闻播放线程
private class PlayThread extends Thread {
@Override
public void run() {
// 向处理器发送播放开始的空消息
mHandler.sendEmptyMessage(BEGIN);
while (isPlaying) {
try {
sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Message message = Message.obtain(); // 获得一个默认的消息对象
message.what = SCROLL; // 消息类型
message.obj = mNewsArray[(int) (Math.random() * 30 % 5)]; // 消息描述
mHandler.sendMessage(message); // 向处理器发送消息
}
isPlaying = true;
try {
sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
mHandler.sendEmptyMessage(END); // 向处理器发送播放结束的空消息
// 如果只要简单处理,也可绕过Handler,直接调用runOnUiThread方法操作界面
// runOnUiThread(new Runnable() {
// @Override
// public void run() {
// String desc = String.format("%s\n%s %s", tv_message.getText().toString(), DateUtil.getNowTime(), "新闻播放结束,谢谢观看");
// tv_message.setText(desc);
// }
// });
isPlaying = false;
}
}
// 创建一个处理器对象
private Handler mHandler = new Handler() {
// 在收到消息时触发
public void handleMessage(Message msg) {
String desc = tv_message.getText().toString();
if (msg.what == BEGIN) { // 开始播放
desc = String.format("%s\n%s %s", desc, DateUtil.getNowTime(), "开始播放新闻");
} else if (msg.what == SCROLL) { // 滚动播放
desc = String.format("%s\n%s %s", desc, DateUtil.getNowTime(), msg.obj);
} else if (msg.what == END) { // 结束播放
desc = String.format("%s\n%s %s", desc, DateUtil.getNowTime(), "新闻播放结束");
}
tv_message.setText(desc);
}
};
}
在handleMessage里接收来自不同分线程发送过来的信息,然后调用主线程方法
延伸一下
android使用了AsyncTask来封装了Handler+Thread。就像是Ajax一样吧