美文网首页
Handler Message分析

Handler Message分析

作者: migill | 来源:发表于2019-11-30 21:00 被阅读0次
1、什么是handler?

handler主要用于异步消息的处理:当发出一个消息之后,首先进入一个消息队列,发送消息的函数即刻返回,而另一个部分在消息队列中逐一将消息取出,然后对消息进行处理。


1、handler内存泄漏的测试?
    private Handler handler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            startActivity(new Intent(MainActivity.this, PersonalActivity.class));
            return false;
        }
    });

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        test();
    }

    private void test() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Message message = new Message();
                message.obj = "handler内存泄漏测试";
                message.what = 3;
                SystemClock.sleep(3000);
                handler.sendMessage(message);//跳转的第二个界面
            }
        }).start();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.e("handler内存泄漏测试 ", "onDestroy");
    }

如上面代码,在进入MainActivity后,退出后,但是还会跳转到PersonalActivity界面。这个怎么解决呢?
方法1:在发送消息的时候判断是否为空。在销毁activity的时候,handler移除对应的message和handler置空

  private void test() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Message message = new Message();
                message.obj = "handler内存泄漏测试";
                message.what = 3;
                SystemClock.sleep(3000);
                //不为空的时候调用
                if (handler != null) handler.sendMessage(message);
            }
        }).start();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.e("handler内存泄漏测试 ", "onDestroy");
        handler.removeMessages(3);
        handler = null;
    }

方法2:延时发送消息,销毁activity的时候,移除对应的message

   private void test() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Message message = new Message();
                message.obj = "handler内存泄漏测试";
                message.what = 3;
                //延时发送消息
                handler.sendMessageDelayed(message,3000);
            }
        }).start();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.e("handler内存泄漏测试 ", "onDestroy");
        handler.removeMessages(3);
    }

2、为什么不能在子线程创建Handler

//错误的使用     
private void test() {
        new Thread(new Runnable() {
            @Override
            public void run() {
            new Handler(new Handler.Callback() {
                @Override
                public boolean handleMessage(Message msg) {
                    return false;
                }
            });
            }
        }).start();
    }

  //正确的使用
  private void test2(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                Looper.prepare();//为子线程创建Looper  
                new Handler() {
                    @Override
                    public void handleMessage(Message msg) {
                        super.handleMessage(msg);
                        //子线程消息处理
                    }
                };
                Looper.loop(); //开启消息轮询
            }
        }).start();
    }

直接在子线程创建Handler,会报如下错误,因为没有给子线程创建一个Looper对象。

java.lang.RuntimeException: Can't create handler inside thread >Thread[Thread-2,5,main] that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:207)
at android.os.Handler.<init>(Handler.java:119)
at com.netease.handler.sample.MainActivity$4.run(MainActivity.java:98)
at java.lang.Thread.run(Thread.java:919)




主线程是什么时候创建Looper的呢?


3、new Handler()两种写法有什么区别?

    private Handler handler = 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());
        }
    };




4、ThreadLocal用法和原理

public class ThreadLocalTest {

    @Test
    public void test() {
        // 创建本地线程(主线程)
        final ThreadLocal<String> threadLocal = new ThreadLocal<String>() {
            @Override
            protected String initialValue() {
                // 重写初始化方法,默认返回null,如果ThreadLocalMap拿不到值再调用初始化方法
                return "冯老师";
            }
        };
        // 从ThreadLocalMap中获取String值,key是主线程
        System.out.println("主线程threadLocal:" + threadLocal.get());

        //--------------------------thread-0
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                // 从ThreadLocalMap中获取key:thread-0的值?没有,拿不到值再调用初始化方法
                String value1 = threadLocal.get();
                System.out.println("thread-0:" + threadLocal.get());

                // ThreadLocalMap存入:key:thread-0  value:"熊老师"
                threadLocal.set("熊老师");
                System.out.println("thread-0  set  >>> " + threadLocal.get()); 
                // 使用完成建议remove(),避免大量无意义的内存占用
                threadLocal.remove();
            }
        });
        thread.setName("thread-0");
        thread.start();

        //--------------------------thread-1
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                // 从ThreadLocalMap中获取key:thread-1的值?没有,拿不到值再调用初始化方法
                String value1 = threadLocal.get();
                System.out.println("thread-1:" + threadLocal.get());

                // ThreadLocalMap存入:key:thread-1  value:"刘老师"
                threadLocal.set("刘老师");
                System.out.println("thread-1  set  >>> " + threadLocal.get()); // 刘老师
                // 使用完成建议remove(),避免大量无意义的内存占用
                threadLocal.remove();
            }
        });
        thread.setName("thread-1");
        thread2.start();
    }
}


2、Handler+Message原理分析
  • Handler.sendMessage()发送消息时,会通过MessageQueue.enqueueMessage()向MessageQueue中添加一条消息;
  • 通过Looper.loop()开启循环后,不断轮询调用MessageQueue.next();
  • 调用目标Handler.dispatchMessage()方法,然后调用handler中的handleMessage方法

handler原理流程图


sendMessage发送消息


1、为什么主线程用Looper死循环不会引起ANR异常?
因为在Looper.next()开启死循环的时候,一旦需要等待时 或 还没有执行到执行的时候,会调用NDK里面的JNI方法,释放当前时间碎片,这样就不会引发ANR异常了。
2、为什么handler构造方法里面的Looper不是直接new?
如果在Handler构造方法里面newLooper,怕是无法保证Looper的唯一,只有用Looper.prepare()才能保证唯一性,具体去看prepare方法。
3、MessageQueue为什么要放在Looper私有的构造方法里初始化?
因为一个线程只绑定一个Looper,所以在Looper构造方法李曼初始化就可以保证mQueue也是唯一的的,Thread对应一个Looper对应一个mQueue

相关文章

网友评论

      本文标题:Handler Message分析

      本文链接:https://www.haomeiwen.com/subject/fvsowctx.html