从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;
			}
		}
	}
时间: 2024-10-14 04:43:38

从Android Handler内部类到WeakReference的知识关联的相关文章

Context内存泄露:Handler&amp;内部类

之前代码中,我经常会去使用Thread去处理耗时操作,再用Handler去返回到主线程,后面涉及到内存泄露,才知道这里面存在了很大的隐患–内存泄露. 之前,一直以为Context发生内存泄露的几率很小,就不以为意.奈何当Android Lint给出下面的警告时,我收起小觑之心. In Android, Handler classes should be static or leaks might occur. 这是我的代码: public class WallPaperActivity exte

【Android】[转] Android Handler应设为static

android开发中,使用Lint检测时会提示这么一句话 : This Handler class should be static or leaks might occur.意为handler应用static修饰否则容易发生内存泄漏. ADT20有这么一个变化:Look for handler leaks: This check makes sure that a handler inner class does not hold an implicit reference to its ou

【译】什么导致了Context泄露:Handler&amp;内部类

思考下面代码 1 public class SampleActivity extends Activity { 2 3 private final Handler mLeakyHandler = new Handler() { 4 @Override 5 public void handleMessage(Message msg) { 6 // ... 7 } 8 } 9 } 如果没有仔细观察,上面的代码可能导致严重的内存泄露.Android Lint会给出下面的警告: In Android,

什么导致了Context泄露:Handler&amp;内部类

参考:http://www.cnblogs.com/kissazi2/p/4121852.html 为什么 内部自定义handler类要static类型? 原因: 1.当一个Android应用程序第一次启动时,Android框架为应用程序的主线程创建一个Looper对象.一个Looper实现了一个简单的消息队列,在一个循环中处理Message对象.所有主要的应用程序框架事件(如活动生命周期方法调用,单击按钮,等等)都包含在Message对象,它被添加到Looper的消息队列然后一个个被处理.主线

Android Handler Leak

转自:Android中使用Handler引发的内存泄露 在Activity中,经常会用到自定义的Handler来处理主线程收到的Message,但是ADT20以后,直接定义的如下定义的内部会有提示说这种使用方法有内存泄漏的风险: private Handler mHandle = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case 0: // this is the

Android handler详解(面试百分之100问到)

handler在Android中被称为“消息处理者”,在多线程中比较常用. handler内部实现原理 handler实现机制:1,Message对象,表示要传递的一个消息,内部使用链表数据结构实现一个消息池,用于重复利用,避免大量创建消息对象,造成内存浪费2,MessageQueue对象,存放消息对象的消息队列,先进先出原则3,Looper对象负责管理当前线程的消息队列4,handler对象负责把消息push到消息队列中,以及接收Looper从消息队列中取出的消息 handler的内存泄露问题

不会内存溢出的Android Handler写法

private static class ThisHandler extends Handler { private final WeakReference<MainActivity> wrActivity; @Override private void handleMessage() { MainActivity act = wrActivity.get(); if(act != null) { // TODO } } } 注意Activity onDestory()的时候将ThisHand

Android Handler的使用

大家好我们这一节讲的是Android Handler的使用,在讲Handler之前,我们先提个小问题,就是如何让程序5秒钟更新一下Title. 首先我们看一下习惯了Java编程的人,在不知道Handler的用法之前是怎么样写的程序,代码如下所示: package com.android.tutor; import java.util.Timer; import java.util.TimerTask; import android.app.Activity; import android.os.

Android Handler Message总结

当应用程序启动时,会开启一个主线程(也就是UI线程),由她来管理UI,监听用户点击,来响应用户并分发事件等.所以一般在主线程中不要执行比较耗时的操作,如联网下载数据等,否则出现ANR错误.所以就将这些操作放在子线程中,但是由于AndroidUI线程是不安全的,所以只能在主线程中更新UI.Handler就是用来 子线程和创建Handler的线程进行通信的. Handler的使用分为两部分:  一部分是创建Handler实例,重载handleMessage方法,来处理消息. [java] view