View的构造函数是否需要传入application

2018-10-26  本文已影响0人  LevyLin

最近做一个需求,需要通过view.getContext()来获取activity,按理说,这是一个很正常的操作,但是没想到有一次获取到了application,与相关开发沟通后,得到的结论是为了防止内存泄露。

但我并不这么认为,我觉得只要这个view有添加在持有activity的viewgroup中,如果view本身无法释放,view中的parent也无法被释放,也就会导致activity内存泄露,所以与是否传入application无关。

由此去翻了资料。查到WindowManager会在Activity调用onDestroy之后,调用removeViewImmediate方法。
代码如下:


image.png
image.png
image.png

经过断点调试后发现,removeViewLocked()方法中的view.assignParent(null)的view,其实只有DecorView,这其实只是WindowManager和Activity解除绑定。具体到单个子View,并没有调用到view.assignParent(null)这个方法,所以结论依然是:
子View继续持有parent,parent也持有activity,所以activity还是无法被释放。

为此专门做了个实验,代码如下:

public class LeakActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_leak);

        findViewById(R.id.add_leak_view_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                LeakView leakView = new LeakView(v.getContext().getApplicationContext());
                ViewGroup group = findViewById(R.id.viewgroup);
                group.addView(leakView);
                leakView.leak();
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        ViewGroup group = findViewById(R.id.viewgroup);
        group.removeAllViews();
    }

    static class LeakView extends AppCompatTextView {

        public LeakView(Context context) {
            super(context);
            setText("我是内存泄露View");
        }

        public void leak() {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    int i = 0;
                    while (true) {
                        i++;
                        System.out.println("我是内存泄露线程,啦啦啦啦" + i + ",parent=" + getParent()+","+getContext());
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }, "leak thread").start();
        }
    }
}

实验结果:

  1. LeakView传入的是LeakActivity,则不管有没有添加到viewgroup,activity和LeakView都会内存泄露
  2. LeakView传入的是application,若是不添加到viewgroup,则activity不会内存泄露,LeakView自己肯定会内存泄露
    3.LeakView传入的是application,若是添加到viewgroup,activity和LeakView都会内存泄露
    4.LeakView传入的application,若是添加到viewgroup,但是在ondestroy时执行移除,则activity不会内存泄露,LeakView自己肯定会内存泄露。

结论:
一般来说,view是和activity绑定生命周期会比较好,activity销毁,view也跟着销毁,所以view的构造传入activity是比较合理的。
如果view中有耗时操作,则应该在activity调用ondestroy时,中断该操作。

上一篇下一篇

猜你喜欢

热点阅读