handler.post()的用法,在其他线程中更新主线程中的ui
public class MainActivity extends AppCompatActivity {
private TextView textView;
private Handler handler=new Handler();
private boolean is=true;
private int i=0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.text);
new Thread(new Runnable() {
@Override
public void run() {
while (is)
{
handler.post(new Runnable() {//Runnable的run方法中的代码相当于被handler发送到主线程中执行
@Override
public void run() {
textView.setText(i+"");
}
});
i++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
@Override
protected void onDestroy() {
super.onDestroy();
is=false;
}
}
handler.postDelayed()的用法,延迟发送
public class MainActivity extends AppCompatActivity {
private TextView textView;
private Handler handler=new Handler();
private boolean is=true;
private int i=0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.text);
new Thread(new Runnable() {
@Override
public void run() {
while (is)
{
handler.postDelayed(new Runnable() {
@Override
public void run() {
textView.setText(i+"");
}
},3000);//延迟3秒,然后开始发送,但是在延迟的同时,其他代码依然会被系统执行,只是不执行run方法中的代码而已,除非是Thread.sleep(3000),这样的话所有的代码都不会执行,直到3秒过后才会执行
i++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
@Override
protected void onDestroy() {
super.onDestroy();
is=false;
}
}
handler.sendMessage()的用法,将其他线程中的数据发送到主线程
public class MainActivity extends AppCompatActivity {
private TextView textView;
private Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
textView.setText(msg.getData().get("zhi").toString());
}
};
private boolean is=true;
private int i=0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.text);
new Thread(new Runnable() {
@Override
public void run() {
Bundle bundle=new Bundle();
bundle.putString("zhi","我是个好人");
Message message=new Message();
message.setData(bundle);
handler.sendMessage(message);
}
}).start();
}
}
handler.callback()的用法,将message截住,决定是否继续传递
public class MainActivity extends AppCompatActivity {
private TextView textView;
private Handler handler=new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
Toast.makeText(MainActivity.this,"拦截了"+msg.getData().get("zhi").toString(),Toast.LENGTH_LONG).show();
return true;//这里如果是返回true,那么msg将不会传递到下面的handleMessage方法中,textview将不会显示内容
}
}){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
textView.setText(msg.getData().get("zhi").toString());
}
};
private boolean is=true;
private int i=0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.text);
new Thread(new Runnable() {
@Override
public void run() {
Bundle bundle=new Bundle();
bundle.putString("zhi","我是个好人");
Message message=new Message();
message.setData(bundle);
handler.sendMessage(message);
}
}).start();
}
}
当然需要注意的是,线程是默认没有Looper的,如果需要使用Handler就必须为线程创建Looper。UI线程,也就是ActivityThread,ActivityThread被创建时就会初始化Looper,这也是在主线程中默认可以使用Handler的原因 。在子线程中开启Looper的代码如下所示(系统还封装了HandlerThread类,已经为Thread创建好了Looper,但是Handler由开发者自己创建):
new Thread(){
@Override
public void run() {
Looper.prepare();
Handler handler=new Handler();
Looper.loop();
}
}.start();
主线程中的Looper是存放在ThreadLocal中的,所以介绍一下ThreadLocal
final ThreadLocal<Boolean> threadLocal=new ThreadLocal();
threadLocal.set(true);
Log.d("CeShi", Thread.currentThread().getName() + ":" + threadLocal.get());
new Thread("第一个thread"){
@Override
public void run() {
threadLocal.set(false);
Log.d("CeShi", Thread.currentThread().getName() + ":" + threadLocal.get());
}
}.start();
new Thread("第二个thread"){
@Override
public void run() {
Log.d("CeShi", Thread.currentThread().getName() + ":" + threadLocal.get());
}
}.start();
/*输出结果为:
05-24 14:51:20.543 11241-11241/com.example.liang.arlvyou D/CeShi: main:true
05-24 14:51:20.553 11241-11262/com.example.liang.arlvyou D/CeShi: 第一个thread:false
05-24 14:51:20.553 11241-11263/com.example.liang.arlvyou D/CeShi: 第二个thread:null*/
从输出结果可以看出,虽然在不同线程中访问的是同一个ThreadLocal对象,但是它们通过ThreadLocal获取到的值确是不一样的,因为ThreadLocal内部会从各自的线程中取出一个数组,然后再从数组中根据当前ThreadLocal的索引去查找对应的value值。
Looper类的介绍
Looper提供了一个getMainLooper方法,通过它可以在任何地方获取到主线程的Looper。Looper提供了quit和quitSafely来退出一个Looper,二者的区别是:quit会直接退出Looper,而quitSafely只是设定一个退出标记,然后把消息队列中的已有消息处理完毕后才安全地退出。在子线程中,如果手动为其创建了Looper,那么在所有的事情完成以后应该调用quit方法来终止消息循环,否则这个子线程就会一直处于等待的状态,而如果退出Looper以后,这个线程就会立刻终止,因此建议不需要的时候终止Looper。
最后来个Handler运行机制说明,把Handler机制的过程说的很明了
Android 的消息机制也就是 handler 机制,创建 handler 的时候会创建一个 looper ( 通过 looper.prepare() 来创建 ),looper 一般为主线程 looper.
handler 通过 send 发送消息 (sendMessage) ,当然 post 一系列方法最终也是通过 send 来实现的,在 send 方法中handler 会通过 enqueueMessage() 方法中的 enqueueMessage(msg,millis )向消息队列 MessageQueue 插入一条消息,同时会把本身的 handler 通过 msg.target = this 传入.
Looper 是一个死循环,不断的读取MessageQueue中的消息,loop 方法会调用 MessageQueue 的 next 方法来获取新的消息,next 操作是一个阻塞操作,当没有消息的时候 next 方法会一直阻塞,进而导致 loop 一直阻塞,当有消息的时候,Looper 就会处理消息 Looper 收到消息之后就开始处理消息: msg.target.dispatchMessage(msg),当然这里的msg.target就是上面传过来的发送这条消息的 handler 对象,这样 handler 发送的消息最终又交给他的dispatchMessage方法来处理了,这里不同的是,handler 的 dispatchMessage 方法是在创建 Handler时所使用的 Looper 中执行的,这样就成功的将代码逻辑切换到了主线程了.
Handler 处理消息的过程是:首先,检查Message 的 callback 是否为 null,不为 null 就通过 handleCallBack 来处理消息,Message 的 callback 是一个 Runnable 对象,实际上是 handler 的 post 方法所传递的 Runnable 参数.其次是检查 mCallback 是 否为 null,不为 null 就调用 mCallback 的handleMessage 方法来处理消息.
参考文章:
Handler 使用
https://blog.csdn.net/qq_30379689/article/details/53394061