LeakTest.java revision 4d4979490e1fa374c0d7f3599fed0a9e83a579d0
1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *      http://www.apache.org/licenses/LICENSE-2.0
7 * Unless required by applicable law or agreed to in writing, software
8 * distributed under the License is distributed on an "AS IS" BASIS,
9 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 * See the License for the specific language governing permissions and
11 * limitations under the License.
12 */
13
14package android.databinding.testapp;
15
16import android.databinding.testapp.databinding.LeakTestBinding;
17import android.test.ActivityInstrumentationTestCase2;
18import android.util.Log;
19import android.widget.FrameLayout;
20
21import java.lang.ref.WeakReference;
22
23public class LeakTest extends ActivityInstrumentationTestCase2<TestActivity> {
24    WeakReference<LeakTestBinding> mWeakReference = new WeakReference<LeakTestBinding>(null);
25
26    public LeakTest() {
27        super(TestActivity.class);
28    }
29
30    @Override
31    protected void setUp() throws Exception {
32        super.setUp();
33
34        try {
35            getActivity().runOnUiThread(new Runnable() {
36                @Override
37                public void run() {
38                    try {
39                        LeakTestBinding binding = LeakTestBinding.inflate(
40                                getActivity().getLayoutInflater());
41                        getActivity().setContentView(binding.getRoot());
42                        mWeakReference = new WeakReference<LeakTestBinding>(binding);
43                        binding.setName("hello world");
44                        binding.executePendingBindings();
45                    } catch (Exception e) {
46                        e.printStackTrace();
47                        throw e;
48                    }
49                }
50            });
51            getInstrumentation().waitForIdleSync();
52        } catch (Throwable t) {
53            throw new Exception(t);
54        }
55    }
56
57    public void testBindingLeak() throws Throwable {
58        assertNotNull(mWeakReference.get());
59        runTestOnUiThread(new Runnable() {
60            @Override
61            public void run() {
62                getActivity().setContentView(new FrameLayout(getActivity()));
63            }
64        });
65        WeakReference<Object> canary = new WeakReference<Object>(new Object());
66        while (canary.get() != null) {
67            byte[] b = new byte[1024 * 1024];
68            System.gc();
69        }
70        assertNull(mWeakReference.get());
71    }
72
73    // Test to ensure that when the View is detached that it doesn't rebind
74    // the dirty Views. The rebind should happen only after the root view is
75    // reattached.
76    public void testNoChangeWhenDetached() throws Throwable {
77        final LeakTestBinding binding = mWeakReference.get();
78        final AnimationWatcher watcher = new AnimationWatcher();
79
80        runTestOnUiThread(new Runnable() {
81            @Override
82            public void run() {
83                getActivity().setContentView(new FrameLayout(getActivity()));
84                binding.setName("goodbye world");
85                binding.getRoot().postOnAnimation(watcher);
86            }
87        });
88
89        watcher.waitForAnimationThread();
90
91        runTestOnUiThread(new Runnable() {
92            @Override
93            public void run() {
94                assertEquals("hello world", binding.textView.getText().toString());
95                getActivity().setContentView(binding.getRoot());
96                binding.getRoot().postOnAnimation(watcher);
97            }
98        });
99
100        watcher.waitForAnimationThread();
101
102        runTestOnUiThread(new Runnable() {
103            @Override
104            public void run() {
105                assertEquals("goodbye world", binding.textView.getText().toString());
106            }
107        });
108    }
109
110    private static class AnimationWatcher implements Runnable {
111        private boolean mWaiting = true;
112
113        public void waitForAnimationThread() throws InterruptedException {
114            synchronized (this) {
115                while (mWaiting) {
116                    this.wait();
117                }
118                mWaiting = true;
119            }
120        }
121
122
123        @Override
124        public void run() {
125            synchronized (this) {
126                mWaiting = false;
127                this.notifyAll();
128            }
129        }
130    }
131}
132