Handler
为什么要用handler
学习handler之前我们线模拟一个简单的视频下载,当我们在模拟视频下载的更新操作中,需要按下开始下载按钮,需要视频中准备下载的字幕立刻转换成正在下载。这里补充i一下开启线程的两个方法
1.继承Threadle类
2.实现runnable接口
这里需要用到线程来实时的对按钮的动作进行判断,首先布局文件给一个button和text view
在activity中添加单击事件,在单击事件中,开启一个线程如下:
public void onClick(View v) {
switch (v.getId()){
case R.id.download_btn:
new Thread(new Runnable() { //主线程
@Override
public void run() { //子线
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
download_tv.setText("正在下载");
}
}).start();
break;
报错: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
大概意思:只有主线程可以更新UI
主线程:ui线程,UI的更新必须放在主线程中。
引出handler
Handler: 是Android SDK中处理异步消息的核心类:两个线程同步通信
作用: 让子线程通过handler更新UI,不只是这一个作用
工作原理:子线程通过handler.setMessage发送到Message Queue,然后由looper取出消息 给主线程
什么是MessageQueue :
MessageQueue的中文翻译是消息队列,顾名思义,它的内部存储了一组消息,以队列的形式对外提供插入和删除的工作。虽然叫消息队列,但是它的内部存储结构并不是真正的队列,而是采用单链表的数据结构来存储消息。它只是用来存储消息,而并不能处理消息,Looper就填补了这个功能。
Looper:
在MessageQueue里存储了消息之后,Looper就会以无限循环的形式去查是否有新消息,如果有的话就去处理消息,否则就是一直等待着
一个线程中只会存在一个Looper和MessageQueue
UI线程会自动初始化Message Queue和looper
初始化Handler
导包:os
private Handler handler=new Handler(){
@Override
//接收子线程更新消息
public void handleMessage(Message msg) {
super.handleMessage(msg);
download_tv.setText("正在下载");
}
};
public void onClick(View v) {
switch (v.getId()){
case R.id.download_btn:
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.sendEmptyMessage(1);//接收int类型的数字
}
}).start();
break;
}
}
倒计时代码:
package com.example.xiaozhen.mynewapplication;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class DownloadActivity extends AppCompatActivity implements View.OnClickListener {
private TextView download_tv,download_tvtime;
private Button download_btn;
private EditText download_et;
private int x;
private Handler handler = new Handler() {
@Override
//接收子线程更新消息
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what==-1){
download_tvtime.setText("倒计时结束");
}else{
//直接将整型的转换成字符串类型的
download_tvtime.setText(msg.what+"");
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_download);
init();
download_btn.setOnClickListener(this);
download_et.setOnClickListener(this);
}
private void init() {
download_btn = (Button) findViewById(R.id.download_btn);
download_tv = (TextView) findViewById(R.id.download_tv);
download_et = (EditText) findViewById(R.id.download_et);
download_tvtime= (TextView) findViewById(R.id.download_tvtime);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.download_btn:
new Thread(new Runnable() {
@Override
public void run() {
//首先得到download——et所录入的时间,因为得到的是string类型的,所以要转成int类型的
//因为handler.sendEmptyMessage()这个方法只能接收int类型的
for (int x=Integer.parseInt(download_et.getText().toString());x>0;x--) {
//这里所需要传递的int就是所需要接收的倒计时数字
handler.sendEmptyMessage(x);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
handler.sendEmptyMessage(-1);
}
}).start();
break;
}
}
}
“`