欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android开发关于handler以及它已过时的构造函数handler()

程序员文章站 2022-01-09 09:51:00
一.android消息驱动机制Thread、Looper、Handler这三个是android消息驱动机制的核心对象,让我们先分析并了解一下一个线程拥有消息处理能力的过程:class LooperThread extends Thread{ public Handler mHandler; public void run() { Looper.prepare();//初始化该线程looper mHandler = new Handler...

一.android消息驱动机制

Thread、Looper、Handler这三个是android消息驱动机制的核心对象,让我们先分析并了解一下一个线程拥有消息处理能力的过程:


class LooperThread extends Thread
{
    public Handler mHandler;
    public void run() 
    {
        Looper.prepare();//初始化该线程looper
        mHandler = new Handler()  //创建handler对象的同时,将该hanlder注册到线程looper中
        {
            //消息处理
            public void handleMessage(Message msg) 
            {
                switch(msg.what)
                {
                    case 0:
                        break;
                    //case ....
                    default:
                        break;
                }
            }
        };
        Looper.loop();//进入消息循环
    }
}

线程一但被执行(run函数)首先做的就是通过Looper.prepare()函数初始化线程的looper,接着创建handler,创建的过程中hanlder会自动把自己注册到线程looper中,最后Looper.loop()进入消息循环,将CPU交给内核。

其实activity处理消息也是类似的过程,但activity已经把这些代码隐藏了起来以便让我们只做最关心的事情。那么activity里怎么处理用户自己的消息呢?因为关于looper的事都已经处理好了,所以只要创建handler就OK啦。

二.Handler构造函数过时问题

用户消息在Activity内如何接收处理?实现方法如下代码所示:

public class MainActivity extends ActionBarActivity {
 
	//接收消息处理
	private Handler handler = new Handler() {  
		@Override  
		public void handleMessage(Message msg) {  
			if(msg.what==0)
			{
            }
        }};

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

但现在,这个代码编译时会得到一个警告:“ 警告: [deprecation] Handler中的Handler()已过时” 。下面小编对这个警告以及其解决办法的理解。

Handler构造函数过时的官方解释是可能导致内存泄露,那么泄露原理是什么呢?

Handler应认为是属于内核的对象,内核和activity所在线程是异步的,当Activity被销毁时内核可能还在用这个Handler,于是内核不让释放Handler,于是这个Handler没用了,却错过了唯一一次被销毁 的机会,就这样占据着内存,这就是内存泄露。

三.解决办法

以下为小编认为的标准解决办法:

public class MainActivity extends Activity {
    public int m_var; //需要在消息处理中访问的成员变量,一定要声明成public

    MyHandler handler = new MyHandler(this);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_auto);
    }
 
    //新的handler类要声明成静态类
    static class MyHandler extends Handler{
        WeakReference<MainActivity> mactivity;
         
        //构造函数,传来的是外部类的this
        public MyHandler(MainActivity activity){
            mactivity = new WeakReference<MainActivity>(activity);
        }
 
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);  

            MainActivity nactivity=mactivity.get();
            if(nactivity == null)
                return ;//avtivity都没了还处理个XXX

            switch (msg.what) {
            case 0:   
                //在这里通过nactivity引用外部类
                nativity.m_var=0;          
                break;              
            default:
                break;
            }
        }
    }

为了防止内存泄露,官方要求将handler声明为静态类,静态就意味着全局,也就是说当app全部被销毁的时候内核不会忘记销毁你这个handler,可内存泄露问题解决了,却引来了另一个很棘手的问题,静态类是无法访问外部类成员的,

访问外部类的成员变量是消息处理代码非常迫切的需求,那怎么办呢?就把外部类的对象引用通过构造函数的参数传递过来不就可以访问了吗,的确是这样,但参数又被WeakReference包装了一下又是什么意思呢?

还是为了解决最初的那个问题,怕的是消息没处理完呢activity被销毁了。在我看来WeakReference就是个具有感知内部对象是否已经被销毁能力的东东。怎么感知?当然是.get()函数啦。

最后还要提醒一下,要在handler消息处理中访问的activity成员要声明成public才行,这是java类的一个常识。

 

 

 

 

 

 

本文地址:https://blog.csdn.net/BitFu/article/details/110183184