美文网首页
View的构造函数是否需要传入application

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

作者: LevyLin | 来源:发表于2018-10-26 18:01 被阅读0次

    最近做一个需求,需要通过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时,中断该操作。

    相关文章

      网友评论

          本文标题:View的构造函数是否需要传入application

          本文链接:https://www.haomeiwen.com/subject/nbsltqtx.html