几个热身问题
一、handler内存泄漏测试
1、handler的基本使用
2、handler发送的过程中(休眠2s),关闭activity,消息仍然可以接收到。
3、使用removeMessage的方式测试,发现没用。原因是还没有压入队列。
4、destory的时候直接置空handler,发现有用。
5、message.recycle方式:如果已经进消息队列了,还好说,如果还没进入消息队列,则会报异常。
二、不能在子线程中创建handler
1、理由是子线程中的looper还是空的
三、TextView.setText()真的只能在子线程中执行吗
1、定位到TextView的requestLayout和invalidate方法,requestlayout方法中有检查代码的逻辑。所以invalidate在检查代码前先执行,就能很神奇的发现setText()能正常在子线程中执行。
四、new Handler的两种写法有何区别
五、ThreadLocal的用法和原理
测试代码片段:
/**
* 1、Handler内存泄露测试
* 2、为什么不能在子线程创建Handler
* 3、textView.setText()只能在主线程执行,这句话是错误!
* 4、new Handler()两种写法有什么区别?
* 5、ThreadLocal用法和原理
*/
public class MainActivity extends AppCompatActivity {
private TextView textView;
private Message message;
// 4、new Handler()两种写法有什么区别?
private Handler handler1 = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
startActivity(new Intent(MainActivity.this, PersonalActivity.class));
return false;
}
});
// 这是谷歌备胎的api,不推荐使用
private Handler handler2 = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
textView.setText(msg.obj.toString());
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.tv);
message = new Message();
test();
}
private void test() {
new Thread(new Runnable() {
@Override
public void run() {
// 常规的写法
// message.obj = "Net163";
// message.what = 163;
// handler2.sendMessage(message);
// 1、Handler内存泄露测试(假象)
SystemClock.sleep(1000); // 销毁Activity
// message.what = 3;
// This message is already in use.
// if (handler1 != null) handler1.sendMessage(message); // 跳转到第二个界面
// handler1.sendMessageDelayed(message, 3000);
// 2、为什么不能在子线程创建Handler
// new Handler();
// 3、textView.setText()只能在主线程执行,这句话是错误!
// textView.setText("彭老师");
Toast.makeText(MainActivity.this, "孙老师", Toast.LENGTH_SHORT).show();
}
}).start();
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.e("moon >>> ", "onDestroy");
// 不推荐写法
message.recycle();
handler1.removeMessages(3);
handler1 = null;
}
}
随意查阅了几篇高流量博客
android Handler机制原理解析
安卓 handler解析
Handler原理架构图
问题思考:
1.为什么主线程用_ooper死循环不会引发ANR异常?
答:因为在Looper.next()开启死循环的时候,一旦 需要等待时或还没有执行到执行的时候,
会调用NDK里面的JNI方法,释放当前时间片,这样就不会引发ANR异常了
2.为什么Handler构造方法里面的ooper不是直接new?
答:如果在Handler构造方法里面new Looper,怕是无法保证保证Looper唯一-, 只有用
Looper.prepare()才能保证唯一性, 具体去看prepare方法
3.MessageQueue为什么要放在L ooper私有构造方法初始化?
答:因为一个线程只绑定一个L ooper,所以在l ooper构造方法里面初始化就可以保证mQueue也是
唯一的Thread对应一个Looper对应一个mQueue
4.主线程里面的ooper.prepare/L ooper.loop,是一直在无限循环里面的吗?
答:是的
手写一个简化版的handler
Handler.java
public class Handler {
private Looper mLooper;
private MessageQueue mQueue;
public Handler() {
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
}
public void sendMessage(Message message) {
// 将消息放入消息队列中
enqueueMessage(message);
}
private void enqueueMessage(Message message) {
// 赋值当前handler
message.target = this;
// 使用mQueue,将消息放入
mQueue.enqueueMessage(message);
}
public void dispatchMessage(Message msg) {
handleMessage(msg);
}
// 给开发者提供的开放API,用于重写和回调监听
public void handleMessage(Message msg) {
}
}
Looper.java
public class Looper {
public MessageQueue mQueue;
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private Looper() {
mQueue = new MessageQueue();
}
public static void prepare() {
// 主线程只有唯一一个Looper对象
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
// 应用启动时,初始化赋值
sThreadLocal.set(new Looper());
}
//
public static Looper myLooper() {
return sThreadLocal.get();
}
// 轮询,提取消息
public static void loop() {
// 从全局ThreadLocalMap中获取唯一:Looper对象
Looper me = myLooper();
// 从Looper对象中获取全局唯一消息队列MessageQueue对象
final MessageQueue queue = me.mQueue;
Message resultMessage;
// 从消息队列中取消息
while (true) {
Message msg = queue.next();
if (msg != null) {
if (msg.target != null) msg.target.dispatchMessage(msg);
}
}
}
}
Message.java
// 消息对象
public class Message {
// 标识
public int what;
// Handler对象
public Handler target;
// 消息内容
public Object obj;
public Message() {
}
public Message(Object obj) {
this.obj = obj;
}
// 模拟
@Override
public String toString() {
return obj.toString();
}
}
MessageQueue.java
// 消息队列
public class MessageQueue {
// 阻塞队列
BlockingQueue<Message> blockingQueue = new ArrayBlockingQueue<>(50);
// 将Message消息对象存入阻塞队列中
public void enqueueMessage(Message message) {
try {
blockingQueue.put(message);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 从消息队列中取出消息
public Message next() {
try {
return blockingQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
}