1、Handler与线程
在默认的情况下,使用Handler.post方法实际上和调用Handler的Activity是处于同一线程的。因为Handler是直接调用了run方法而并不是调用了线程的start方法。换句话说,线程是创建好了,但是并没有另外开启这个线程作为一个新的线程,而是在当前线程当中直接实现了该线程里面的run方法。这个可以通过Thread.currentThread().getId()和Thread.currentThread.getName()方法来获取当前线程的ID和名字来证实。结果是如果使用Handler来调用一个线程的run方法,那么线程里面获得的线程id和线程name与Activity或得到的线程id、线程name是一致的。
2、Bundle的用法
官方文档:A mapping from String values to various Parcelable types.
Bundle类是一种数据载体,类似于Map,用于存放key-value名值对形式的值。可以把Bundle看成是一种特殊的map。一般的map里面的键和值都是object(任意类型)的,而Bundle是把键固定成string类型的,值可以是基本类型和基本类型数组等。
常用方法:
putXxx()用于往Bundle对象放入数据,
getXxx()用于从Bundle对象里获取数据。
Bundle的内部实际上是使用了HashMap类型的变量来存放putXxx()方法放入的值。Bundle就是一个专门用于导入Intent传值的包。当然也可以在消息中使用。
3、在新线程当中处理消息的方法
1.Java标准启动一个线程方法
第一步、生成一个Handler对象
private Handler handler = new Handler();
第二步、定义一个Runnable类实现一个Runnable接口和里面的run方法
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("handler-->" + Thread.currentThread().getId());
System.out.println("handler-->" + Thread.currentThread().getName());
}
};
第三步、生成一个Thread对象,并把生成的Runnable对象作为参数传入
Thread thread = new Thread(runnable);
第四步、调用Thread线程的start方法
thread.start();
当掉用完start方法后,线程进入就绪状态。
2.使用looper对象
Looper是由Android框架提供的一个类,主要作用是从队列里面取得消息。当队列里面有消息时就不断的从里面取出消息,没有消息时就进入空闲休眠状态。除了使用Looper外,Android还提供了一个HandlerThread类,这个类就实现了looper的取得消息的功能。所以一般使用HandlerThread类就可以了,很少去使用looper本身。
下面贴上Activity代码:
package com.example.urien.handler;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class Handler2Activity extends AppCompatActivity {
private Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler2);
/**第一种方法创建线程
Thread thread = new Thread(runnable);
thread.start();
System.out.println("activity-->" + Thread.currentThread().getId());
System.out.println("activity-->" + Thread.currentThread().getName());
*/
System.out.println("activity-->" + Thread.currentThread().getId());
/**生成一个HandlerTherad对象,实现了使用Looper来处理消息队列的功能*/
HandlerThread handlerThread = new HandlerThread("handler_thread");
/**启动线程*/
handlerThread.start();
/**
* 生成一个MyHandler对象
* 并把HandlerThread使用getLooper得到的Looper对象作为参数传进去
* 进而调用MyHandler类当中相应的构造函数
* */
MyHandler myHandler = new MyHandler(handlerThread.getLooper());
/**通过Handler的obtainMessage方法来获取一个对应当前handler对象的消息对象*/
Message message = myHandler.obtainMessage();
/**s使用message里面的obj承载数据*/
message.obj = "string";
/**生成一个bundle对象存入不同类型的键值对*/
Bundle bundle = new Bundle();
bundle.putInt("test_int",12345);
bundle.putString("test_string","test_string");
/**使用message的setData方法存放数据*/
message.setData(bundle);
/**
* 使用SendToTarget方法像Handler对象发送消息对象
* 这里注意,这里的message.sendToTarget();中的message是对应的那个Handler
* 就向那个Handler发送消息
* 简单的说就是这个message对象是由那个handler生成的对应的Target就是那个Handler
* */
message.sendToTarget();
}
/**
* 对应第一种方法创建线程
* Runnable runnable = new Runnable() {
*
* @Override public void run() {
* System.out.println("handler-->" + Thread.currentThread().getId());
* System.out.println("handler-->" + Thread.currentThread().getName());
* }
* };
*/
class MyHandler extends Handler {
/**
* 无参数的构造函数
*/
public MyHandler() {
}
/**
* 带有一个Looper对象作为参数的构造函数
* 把looper作为参数的目的是把当前的Handler使用looper所在的线程去处理消息队列
* 换句话说就是把当前的Handler绑定在另外一个Looper队列上去取得消息队列,进而处理消息
*/
public MyHandler(Looper looper) {
super(looper);//
}
/**
* 每当向Handler发送一个消息对象的时候就会执行此方法
*/
@Override
public void handleMessage(Message msg) {
/**得到message里面的string类型的消息数据*/
String string = (String) msg.obj;
/**得到Bundle里面传递过来的Bundle对象*/
Bundle bundle = msg.getData();
/**通过Bundle取得里面的数据*/
int test_int = bundle.getInt("test_int");
String test_string = bundle.getString("test_string");
System.out.println("string-->" + string);
System.out.println("text_int-->" + test_int);
System.out.println("test_string-->" + test_string);
System.out.println("handler-->" + Thread.currentThread().getId());
System.out.println("handlerMessage");
}
}
}
代码注释的相对详细,不多解释。
顺带贴上第二种方法的测试结果: