zoukankan      html  css  js  c++  java
  • 从Android Handler内部类到WeakReference的知识关联

    Handler:

    普通使用方法:

    Handler用于处理和从队列MessageQueue中得到Message。一般我们要重写Handler的handleMessage(Message msg){}方法来处理,例如以下代码:

    public class MainActivity extends Activity {
        private TextView textView;
        
    	Handler normalHandler = new Handler(){
    		@Override
    		public void handleMessage(Message msg) {
    			switch (msg.what) {
    			case 1:
    				Log.i("test",textView.getText().toString());
    				break;
    
    			default:
    				break;
    			}
    		};
    	};
    }



    问题:

    这个时候Handler会被Android SDK中Lint工具检查警告你(左边那个黄色灯泡+叹号):This Handler class should be static or leaks might occur 

    原因:

    This Handler class should be static:

    (知识点一)为什么静态内部类能够解决问题呢?或者说静态内部类和非静态内部类的差别是什么?

    举例:class A{int a; static int b class B{}  static class C{} }  (A是外部类,B非静态内部类,C静态内部类,a普通字段。b静态字段)

    1)B非静态内部类:

    能够訪问A.a和A.b,也就是外部的属性都能方位。

    由于B隐式的持有A类对象的引用。相当于A的属性

    2)C静态内部类:

    C仅仅能够訪问A.b,不能够方位A.a。为什么?由于C不含有A的引用。它和A类是同一个级别。仅仅只是写到了A类的内部。

    本例原因:

    Handler匿名内部类,隐式的持有了外部类Activity的引用(这就是为什么你能在handleMessage()中调用MainActivity中TextView等的属性)。

    --->而以后调

    Message message = normalHandler.obtainMessage();
    normalHandler.sendMessageAtTime(message , 100*1000);
    

    得到的message中又含有这个Handler的引用(能够看源代码)。

    在100秒后message被运行,这期间message被放在MessageQueue中,MessageQueue在Looper中,Looper是线程的本地变量。

    也就是说MainActivity即使生命周期走完了也不会垃圾回收,为什么?由于Java的垃圾回收机制,就是看一个对象有没有被引用(从线程中的主要对象開始,对象之间的引用形成网状结构,假设有类的对象不在这张网上,就证明它没被引用。这就是数据结构中图的遍历,什么连通子图,非连通子图)。

    而本文中一个MainActivity被Handler持有引用。Handler被Message持有引用,Message被MessageQueue持有引用,MessageQueue被Looper持有引用,Looper为线程本地变量,线程不被摧毁。它就不会被销毁。

    所以即便用户已经切换、退出到别的Activity。MainActivity占有的内存仍旧不会被释放。


    解决方式:

    打破引用链:

    1.Message在100秒后被处理。之后回收Message,然后回收MainActivity。

    (所以是实际上,你仅仅要不发非常长时间的Message也不会有什么问题)

    2.使Handler不持有MainActivity的引用,用弱引用WeakReference:(简单讲,就是仅仅有WeakReference引用的对象。垃圾回收将回收该对象,以后再另写一篇引用的文章吧)


    正常代码:

    	MyHandler handler = new MyHandler(this);
    
    	public static class MyHandler extends Handler {
    		private WeakReference<MainActivity> reference;
    
    		public MyHandler(MainActivity activity) {
    			reference = new WeakReference<MainActivity>(activity);
    		}
    
    		@Override
    		public void handleMessage(Message msg) {
    			switch (msg.what) {
    			case 1:
    				Log.i("test",textView.getText().toString());
    				break;
    
    			default:
    				break;
    			}
    		}
    	}



  • 相关阅读:
    数据库得四种隔离级别(非原创,转载文章)
    c#中的数据类型简介(委托)
    c#中的数据类型简介(数组)
    c#中的数据类型简介(枚举)
    c#中的数据类型简介(string)
    c#中的数据类型简介
    二分法的查找图解
    Linux下多个.c文件的编译和Makefile文件
    C语言中const和数组
    grep和正则表达式
  • 原文地址:https://www.cnblogs.com/lcchuguo/p/5234390.html
Copyright © 2011-2022 走看看