采用匿名内部类形式定义Handler有什么不妥?

写这篇博客,是为分析Handler引起内存泄漏做准备。

匿名内部类的含义是什么?

首先是内部类,(内部类不难理解,有时间再分析,这里不展开)为什么称之为匿名?因为没有明确定义类的名称。看下面的例子就知道了。

匿名内部类的三种情况

  • 实现接口的匿名内部类
    例如android中常用的setOnClickListener()runOnUiThread()
public class View implements Drawable.Callback, KeyEvent.Callback,
        AccessibilityEventSource {
    
    
	...
    public interface OnClickListener {
    
    
        void onClick(View v);
    }
	...
} 

		//使用:
        tv.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View v) {
    
    

            }
        });

View.OnClickListener只是接口名称,真正的类名,并没有给出。完整的写法,应该是:

    class TVListener implements View.OnClickListener{
    
    

        @Override
        public void onClick(View v) {
    
    
            System.out.println("onClick");
        }
    }
	
    tv.setOnClickListener(new TVListener());

TVListener就是具体的类名。

  • 继承抽象类的匿名内部类。实现抽象方法,例如Android中的AsyncTaskTimerTask
  • 继承普通类的匿名内部类。重写普通的某个方法,Android中的典型例子就是Handler,一般都会重写handleMessage()方法。
public class StandardActivity extends AppCompatActivity {
    
    
    private static final String TAG = "ActivityA";
    private Handler myHandler = new Handler() {
    
    
        @Override
        public void handleMessage(Message msg) {
    
    
            super.handleMessage(msg);
            if (msg.what == 100) {
    
    
                Log.i(TAG, "xxx");
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        Log.i(TAG, "onCreate: ");
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                Message msg = new Message();
                msg.what = 100;
                myHandler.sendMessage(msg);
            }
        }).start();
    }
}

非静态内部类为什么会持有外部类的引用?

静态内部类是不会持有外部类的引用的。详细查看:为啥非静态内部类能持有外部类?
我们写三个类,看看编译出来的.class文件。

//模拟Android SDK中Activity.java
public class Activity {
    
    

}

//模拟Android SDK中的Handler.java
public class Handler {
    
    
    public void handleMessage(){
    
    

    }
}

//模拟实际开发中的MainActivity
public class MainActivity extends Activity {
    
    

    Handler mH;

    public void onCreate() {
    
    
        mH = new Handler() {
    
    
            @Override
            public void handleMessage() {
    
    
                System.out.println("重写handleMessage()方法");
            }
        };

        System.out.println(mH.getClass().getName());
    }

    public static void main(String[] args) {
    
    
        new MainActivity().onCreate();
    }
}

编译完,确实生成了4个.class文件:

看看MainActivity$1.class,构造器里面确实传入了MainActivity的对象var1。

class MainActivity$1 extends Handler {
    
    
    MainActivity$1(MainActivity var1) {
    
    
        this.this$0 = var1;
    }

    public void handleMessage() {
    
    
        System.out.println("閲嶅啓handleMessage()鏂规硶");
    }
}

有点不确定,如果不是匿名内部类,仅仅是非静态内部类,会不会也持有引用了?
试下:

public class OutClass {
    
    
    class InClass{
    
    

    }
}

编译后:

看看OutClass$InnerClass.class文件:

class OutClass$InClass {
    
    
    OutClass$InClass(OutClass var1) {
    
    
        this.this$0 = var1;
    }
}

还是在构造器中传入了外部类OutClass的引用。注意:这说明,即使不采用匿名内部类,采用非静态成员内部类的形式,定义Handler,也还是会持有Activity的引用。所以只能使用静态内部类的方式自定义Handler。

所以非静态内部类的.class文件中,构造器会自动传入外部类的引用。不管是不是匿名,只要是非静态内部类,默认持有外部类的引用。

猜你喜欢

转载自blog.csdn.net/zhangjin1120/article/details/131542103
今日推荐