Fix-Android-TransactionTooLargeException
介绍
TransactionTooLargeException
表示在 RPC 调用中传输的数据过大(超过 1MB), 导致 RPC 调用失败.
TooLargeTool 是一款可以方便打开 Bundle 大小的工具, 可以借鉴里面的代码实现.
背景
除了常见的 Bundle 传输数据过大导致 startActivity 失败外, 经常还见到另一个堆栈:
1 | Caused by: |
同时 App 为单 Activity 多 Fragment 架构
复现路径
我们找到了一个复现路径:
- 在同一个Activity打开多个 Fragment, 尽量不少于 20 个
- App 退后台
- 此时可以在 Logcat 看到
TransactionTooLargeException
排查过程
查看代码, 退后台时会调用 Fragment 的
onSaveInstanceState(Bundle)
, 这是用来保存状态的方法, 尝试在 Fragment 的 onSaveInstanceState 方法中打印 Bundle 的大小, 结果只有大概 1kb .除了 Fragment 的 `onSaveInstanceState ,还有 Activity 的 onSaveInstanceState 方法, 打印出来. 两个 Fragment 大约有 100kb, 如果再开一个 Fragment, 还会增加 70kb. 以此类推, 大约16个 Fragment, 就会超过 1MB 的限制. 所以原因就是** Activity 调用 onSaveInstanceState 时 Bundle 太大了**.
1
2
3
4
5
6activity onSaveInstanceState: com.example.activity.MainActivity@7db60c7 size = Bundle62666159 contains 5 keys and measures 108.3 KB when serialized as a Parcel
* com.google.app_measurement.screen_service = 0.2 KB
* android:viewHierarchyState = 0.3 KB
* androidx.lifecycle.BundlableSavedStateRegistry.key = 107.3 KB
* android:lastAutofillId = 0.1 KB
* android:fragments = 0.4 KB bundle size 5Bundle 中什么东西占用了空间
通过查看源码和结合工具打印, Bundle 本质也是 Key-Value 的形式, 我们可以一层一层解析 Bundle 中的数据和大小.
androidx.lifecycle.BundlableSavedStateRegistry.key
存放的是 Bundle, 里面占用大小最大的是android:support:fragments
这个 key 存放的 Bundle.
源码:日志:
1
2
3
4
5
6androidx.lifecycle.BundlableSavedStateRegistry.key size = 101 KB , map size 5
key: androidx:appcompat size = 4 B
key: android:support:lifecycle size = 4 B
key: androidx.lifecycle.internal.SavedStateHandlesProvider size = 4 B
key: android:support:activity-result size = 7.4 KB bundle
key: android:support:fragments size = 93 KB bundle map size 3android:support:fragments
key 中存放的是 Bundle, 里面是每个 Fragment 的 FragmentState 对象.
源码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44``` FragmentManager
public abstract class FragmentManager implements FragmentResultOwner {
static final String SAVED_STATE_TAG = "android:support:fragments";
// 找到 android:support:fragments 的 key
SavedStateRegistry registry =
((SavedStateRegistryOwner) mHost).getSavedStateRegistry();
registry.registerSavedStateProvider(SAVED_STATE_TAG, () -> {
return saveAllStateInternal();
}
);
// 找到 fragment_ 的key
static final String FRAGMENT_STATE_TAG = "state";
static final String FRAGMENT_NAME_PREFIX = "fragment_";
private final FragmentStore mFragmentStore = new FragmentStore();
// saveAllStateInternal() 方法
Bundle saveAllStateInternal() {
...
// First save all active fragments.
ArrayList<String> active = mFragmentStore.saveActiveFragments();
...
for (FragmentState state : savedState) {
Bundle fragmentBundle = new Bundle();
fragmentBundle.putParcelable(FRAGMENT_STATE_TAG, state);
bundle.putBundle(FRAGMENT_NAME_PREFIX + state.mWho, fragmentBundle);
}
return bundle;
}
}
// FragmentStore
class FragmentStore {
private final HashMap<String, FragmentState> mSavedState = new HashMap<>();
ArrayList<FragmentState> getAllSavedState() {
return new ArrayList<>(mSavedState.values());
}
}日志:
1
2
3
4android:support:fragments size = 93 KB bundle map size 3
key: fragment_cc246ae6-d05a-44c1-9a07-e6b6e466cd03 size = 40 KB
key: fragment_98067ccf-09ad-415b-b937-bb79c097db81 size = 52 KBFragmentState 可以直接在源码中找到, 由于其他都是基础类型, 最大的怀疑对象只有 mSavedFragmentState.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16final class FragmentState implements Parcelable {
final String mClassName;
final String mWho;
final boolean mFromLayout;
final int mFragmentId;
final int mContainerId;
final String mTag;
final boolean mRetainInstance;
final boolean mRemoving;
final boolean mDetached;
final Bundle mArguments;
final boolean mHidden;
final int mMaxLifecycleState;
Bundle mSavedFragmentState;
}尝试反射打印一下大小也能印证:
1
2
3
4
5
6
7
8
9
10
11name: mArguments size 4 B
name: mClassName size 49 B
name: mContainerId size 82 B
name: mDetached size 48 B
name: mFragmentId size 82 B
name: mFromLayout size 48 B
name: mHidden size 48 B
name: mMaxLifecycleState size 82 B
name: mRemoving size 48 B
name: mRetainInstance size 48 B
name: mSavedFragmentState size 40 KBmSavedFragmentState 因为也是 Bundle, 可以打印里面的 value 的大小.
1
2
3
4
5
6
7onSaveInstanceState of: Bundle121352603 contains 6 keys and measures 57.4 KB
* fragmentation_arg_container = 0.1 KB
* android:support:fragments = 16.3 KB
* fragmentation_invisible_when_leave = 0.1 KB
* fragmentation_state_save_animator = 0.2 KB
* androidx.lifecycle.BundlableSavedStateRegistry.key = 0.2 KB
* android:view_state = 40.5 KB源码可以看到 android:view_state 就是一个 SparseParcelableArray
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19class FragmentStateManager {
private static final String VIEW_STATE_TAG = "android:view_state";
private Bundle saveBasicState() {
Bundle result = new Bundle();
// Fragment 保存状态
mFragment.performSaveInstanceState(result);
...
if (mFragment.mSavedViewState != null) {
if (result == null) {
result = new Bundle();
}
result.putSparseParcelableArray(
VIEW_STATE_TAG, mFragment.mSavedViewState);
}
...
return result;
}
}打印 android:view_state , Array 中存放的数据比较多
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310index: 9 value: CompoundButton.SavedState{5d3a096 checked=false} size 212 B
index: 10 value: CompoundButton.SavedState{d4417 checked=false} size 212 B
index: 11 value: CompoundButton.SavedState{12f3004 checked=false} size 212 B
index: 12 value: CompoundButton.SavedState{8d0d9ed checked=false} size 212 B
index: 13 value: CompoundButton.SavedState{da13022 checked=false} size 212 B
index: 14 value: CompoundButton.SavedState{6980ab3 checked=false} size 212 B
index: 15 value: CompoundButton.SavedState{b714870 checked=false} size 212 B
index: 16 value: CompoundButton.SavedState{9ee27e9 checked=false} size 212 B
index: 17 value: CompoundButton.SavedState{1c62c6e checked=false} size 212 B
index: 18 value: CompoundButton.SavedState{dfe9f0f checked=false} size 212 B
index: 19 value: CompoundButton.SavedState{e7a7b9c checked=false} size 212 B
index: 20 value: CompoundButton.SavedState{27859a5 checked=false} size 212 B
index: 21 value: CompoundButton.SavedState{32ca17a checked=false} size 212 B
index: 22 value: CompoundButton.SavedState{1901d2b checked=false} size 212 B
index: 23 value: CompoundButton.SavedState{d81b588 checked=false} size 212 B
index: 24 value: CompoundButton.SavedState{4b9eb21 checked=false} size 212 B
index: 25 value: CompoundButton.SavedState{5535b46 checked=false} size 212 B
index: 26 value: CompoundButton.SavedState{8716107 checked=false} size 212 B
index: 27 value: CompoundButton.SavedState{640a234 checked=false} size 212 B
index: 28 value: CompoundButton.SavedState{329185d checked=false} size 212 B
index: 29 value: CompoundButton.SavedState{2d9e5d2 checked=false} size 212 B
index: 30 value: CompoundButton.SavedState{d3906a3 checked=false} size 212 B
index: 31 value: CompoundButton.SavedState{65fada0 checked=false} size 212 B
index: 32 value: CompoundButton.SavedState{763dd59 checked=false} size 212 B
index: 33 value: CompoundButton.SavedState{ecc8d1e checked=false} size 212 B
index: 34 value: CompoundButton.SavedState{34b69ff checked=false} size 212 B
index: 35 value: CompoundButton.SavedState{ba203cc checked=false} size 212 B
index: 36 value: CompoundButton.SavedState{cebf615 checked=false} size 212 B
index: 37 value: CompoundButton.SavedState{eb05d2a checked=false} size 212 B
index: 38 value: CompoundButton.SavedState{5f6a71b checked=false} size 212 B
index: 39 value: CompoundButton.SavedState{ad190b8 checked=false} size 212 B
index: 40 value: CompoundButton.SavedState{ba2de91 checked=false} size 212 B
index: 41 value: CompoundButton.SavedState{94f21f6 checked=false} size 212 B
index: 42 value: CompoundButton.SavedState{d4e99f7 checked=false} size 212 B
index: 43 value: CompoundButton.SavedState{96b0064 checked=false} size 212 B
index: 44 value: CompoundButton.SavedState{e05d2cd checked=false} size 212 B
index: 45 value: CompoundButton.SavedState{6436782 checked=false} size 212 B
index: 46 value: CompoundButton.SavedState{4c8de93 checked=false} size 212 B
index: 47 value: CompoundButton.SavedState{609bed0 checked=false} size 212 B
index: 48 value: CompoundButton.SavedState{f29cec9 checked=false} size 212 B
index: 49 value: CompoundButton.SavedState{a4479ce checked=false} size 212 B
index: 50 value: CompoundButton.SavedState{f98d0ef checked=false} size 212 B
index: 51 value: CompoundButton.SavedState{b93f7fc checked=false} size 212 B
index: 52 value: CompoundButton.SavedState{c778e85 checked=true} size 212 B
index: 53 value: CompoundButton.SavedState{c3264da checked=false} size 212 B
index: 54 value: CompoundButton.SavedState{6cb8d0b checked=false} size 212 B
index: 55 value: CompoundButton.SavedState{b2697e8 checked=false} size 212 B
index: 56 value: CompoundButton.SavedState{7278e01 checked=false} size 212 B
index: 57 value: CompoundButton.SavedState{ee1f4a6 checked=false} size 212 B
index: 58 value: CompoundButton.SavedState{d23eee7 checked=false} size 212 B
index: 59 value: CompoundButton.SavedState{8c14a94 checked=false} size 212 B
index: 60 value: CompoundButton.SavedState{17e093d checked=false} size 212 B
index: 61 value: CompoundButton.SavedState{ba8b532 checked=false} size 212 B
index: 62 value: CompoundButton.SavedState{4b69283 checked=false} size 212 B
index: 63 value: CompoundButton.SavedState{6b27c00 checked=false} size 212 B
index: 64 value: CompoundButton.SavedState{3c6fc39 checked=false} size 212 B
index: 65 value: CompoundButton.SavedState{9a8f27e checked=false} size 212 B
index: 66 value: CompoundButton.SavedState{245d3df checked=false} size 212 B
index: 67 value: CompoundButton.SavedState{bc3582c checked=false} size 212 B
index: 68 value: CompoundButton.SavedState{51222f5 checked=false} size 212 B
index: 69 value: CompoundButton.SavedState{dddb88a checked=false} size 212 B
index: 70 value: CompoundButton.SavedState{a5dcefb checked=false} size 212 B
index: 71 value: CompoundButton.SavedState{23cb18 checked=false} size 212 B
index: 72 value: CompoundButton.SavedState{3aef971 checked=false} size 212 B
index: 73 value: CompoundButton.SavedState{fe6d356 checked=false} size 212 B
index: 74 value: CompoundButton.SavedState{4305fd7 checked=false} size 212 B
index: 75 value: CompoundButton.SavedState{d1680c4 checked=false} size 212 B
index: 76 value: CompoundButton.SavedState{968bbad checked=false} size 212 B
index: 77 value: CompoundButton.SavedState{f94cee2 checked=false} size 212 B
index: 78 value: CompoundButton.SavedState{e312273 checked=false} size 212 B
index: 79 value: CompoundButton.SavedState{b5ce530 checked=false} size 212 B
index: 80 value: CompoundButton.SavedState{78265a9 checked=false} size 212 B
index: 81 value: CompoundButton.SavedState{734f72e checked=false} size 212 B
index: 82 value: CompoundButton.SavedState{7172cf checked=false} size 212 B
index: 83 value: CompoundButton.SavedState{c63245c checked=false} size 212 B
index: 84 value: CompoundButton.SavedState{672b365 checked=false} size 212 B
index: 85 value: CompoundButton.SavedState{69d583a checked=false} size 212 B
index: 86 value: CompoundButton.SavedState{8bc6ceb checked=true} size 212 B
index: 87 value: CompoundButton.SavedState{a2c2a48 checked=false} size 212 B
index: 88 value: CompoundButton.SavedState{56020e1 checked=false} size 212 B
index: 89 value: CompoundButton.SavedState{2f8be06 checked=false} size 212 B
index: 90 value: CompoundButton.SavedState{c72ecc7 checked=false} size 212 B
index: 91 value: CompoundButton.SavedState{9fda2f4 checked=false} size 212 B
index: 92 value: CompoundButton.SavedState{55cea1d checked=false} size 212 B
index: 93 value: CompoundButton.SavedState{752b492 checked=false} size 212 B
index: 94 value: CompoundButton.SavedState{c278e63 checked=false} size 212 B
index: 95 value: CompoundButton.SavedState{dcbfa60 checked=false} size 212 B
index: 96 value: CompoundButton.SavedState{c630b19 checked=false} size 212 B
index: 97 value: CompoundButton.SavedState{1e387de checked=false} size 212 B
index: 98 value: CompoundButton.SavedState{4faadbf checked=false} size 212 B
index: 99 value: CompoundButton.SavedState{665c8c checked=false} size 212 B
index: 100 value: CompoundButton.SavedState{c103fd5 checked=false} size 212 B
index: 101 value: CompoundButton.SavedState{a1c43ea checked=false} size 212 B
index: 102 value: CompoundButton.SavedState{bb666db checked=false} size 212 B
index: 103 value: CompoundButton.SavedState{862b578 checked=false} size 212 B
index: 104 value: CompoundButton.SavedState{8220451 checked=false} size 212 B
index: 105 value: CompoundButton.SavedState{b72b4b6 checked=false} size 212 B
index: 106 value: CompoundButton.SavedState{daa95b7 checked=false} size 212 B
index: 107 value: CompoundButton.SavedState{dc9b124 checked=false} size 212 B
index: 108 value: CompoundButton.SavedState{8b1948d checked=false} size 212 B
index: 109 value: CompoundButton.SavedState{ed6642 checked=false} size 212 B
index: 110 value: CompoundButton.SavedState{348d653 checked=false} size 212 B
index: 111 value: CompoundButton.SavedState{e82bb90 checked=false} size 212 B
index: 112 value: CompoundButton.SavedState{42fec89 checked=false} size 212 B
index: 113 value: CompoundButton.SavedState{d6fa48e checked=false} size 212 B
index: 2131427585 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131427586 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131427590 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131427593 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131427598 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131427802 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131427846 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131427848 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131428063 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131428202 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131428413 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131428417 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131428708 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131428779 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131428825 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131428835 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131428906 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131428907 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131428909 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131428910 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131428911 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131429227 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131429229 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131429267 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131429275 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131429278 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131429311 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131429320 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131429738 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131429739 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131429740 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131429898 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131429900 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131430063 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131430064 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131430125 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131430163 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131430164 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131430167 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131430169 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131430170 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131430171 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131430172 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131430345 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131430360 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131430362 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131430428 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131430442 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131430607 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131430664 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131430668 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131430669 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131430703 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131430842 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131430851 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131430853 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131430905 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131430908 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131430909 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131430910 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131431039 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131431050 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131431070 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131431386 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131431572 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131431609 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131432508 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131432857 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131432984 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131433180 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131433181 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131433191 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131433196 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131433204 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131433205 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131433790 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131433829 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434147 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434173 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434226 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434416 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434417 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434418 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434419 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434420 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434421 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434422 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434429 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434430 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434431 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434432 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434433 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434434 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434435 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434443 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434444 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434445 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434446 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434447 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434448 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434449 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434450 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434451 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434468 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434469 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434810 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434828 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434835 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434848 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131434968 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131435021 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131435050 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131435129 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131435286 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131435294 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131435455 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131435466 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131435526 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131435880 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131435998 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131436152 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131436176 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131436177 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131436178 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131436680 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131436789 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131436791 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131436929 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131436931 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131437119 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131437153 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131437154 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131437155 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131437837 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131438026 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131438505 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131438874 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439071 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439124 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439161 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439162 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439163 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439165 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439190 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439210 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439213 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439246 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439648 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439692 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439741 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439790 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439839 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439840 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439962 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439964 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439970 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439973 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439974 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439975 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439976 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439977 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439978 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439979 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439980 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439981 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439982 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439983 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439984 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439985 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131439986 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131440068 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131440074 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131440103 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131440153 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131440171 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131440239 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131440562 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131440686 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131441148 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131441578 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131441589 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131441992 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131442003 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131442375 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131442378 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131442382 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131442383 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131442598 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131442726 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131442795 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131443036 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131443037 value: android.view.AbsSavedState$1@8084af size 68 B
index: 2131442292 value: androidx.recyclerview.widget.RecyclerView$SavedState@203fa43 size 316 B
index: 2131439968 value: androidx.recyclerview.widget.RecyclerView$SavedState size 316 B
index: 2131432685 value: androidx.recyclerview.widget.RecyclerView$SavedState size 316 B
index: 2131435295 value: androidx.recyclerview.widget.RecyclerView$SavedState size 316 B
index: 2131435292 value: androidx.coordinatorlayout.widget.CoordinatorLayout$SavedState@8aa6ca8 size 212 B
index: 2131429908 value: FragmentPager.SavedState{d8000bc position=0} size 176 B
index: 2131435148 value: FragmentPager.SavedState{edabccb position=0} size 176 B
index: 2131435999 value: FragmentPager.SavedState{96fb766 position=0} size 176 B
index: 2131440220 value: androidx.appcompat.widget.Toolbar$SavedState@32fe3f2 size 172 B
index: 2131442599 value: HorizontalScrollView.SavedState{4c428c0 scrollPosition=0} size 128 B
index: 2131435051 value: HorizontalScrollView.SavedState{cc57b9a scrollPosition=0} size 128 B
index: 2131436299 value: android.widget.ProgressBar$SavedState size 112 B
index: 2131436874 value: android.widget.ProgressBar$SavedState@18dab54 size 112 B一共 310 个对象, 全部加起来的话
105 * 212 + 192 * 68 + 4 * 316 + 212 + 3 * 176 + 172 + 128 * 2 + 112 * 2 = 37972 / 1024 = 37kb
原因总结
- View 会保存自己的状态, 用于状态恢复.
- Fragment 会保存所有 View 的状态(一个 Fragment 大约40k).
- Activity 会保存 Activity 下 attach 的所有 Fragment 的状态.
- 如果 Activity 下嵌套 Fragment 过多, 保存状态时容易超过 1MB.
解决方法
不保存 Fragment 的 view 状态, 也不做恢复
即清除 Bundle 中数据
注意这里由于 Fragment 先调用 onSaveInstanceState 后保存 view_state, 所以我们要在 Activity 的 onSaveInstanceState 中清除 Bundle 中的数据
大概代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64class BundleClipHelper {
companion object {
private const val TAG = "BundleClipHelper"
/**
* Bundle 中这两个 key 比较占内存, 暂时只删除这两个 key
*/
private const val BUNDLE_KEY_FRAGMENTS = "android:support:fragments"
private const val BUNDLE_KEY_VIEWS = "android:view_state"
}
/**
* 待清理 Bundle 列表
*/
private val pendingClearBundleList = mutableListOf<Bundle>()
/**
* fragment 生命周期回调
* 在 Fragment 调用 onSaveInstanceState 后记录需要清理的 Bundle
*/
private val fragmentLifecycleCallbacks: FragmentManager.FragmentLifecycleCallbacks =
object : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentSaveInstanceState(fm: FragmentManager, f: Fragment, outState: Bundle) {
super.onFragmentSaveInstanceState(fm, f, outState)
pendingClearBundleList.add(outState)
}
}
/**
* 注册 fragment 生命周期回调
*/
fun register(activity: FragmentActivity?) {
activity?.supportFragmentManager?.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true)
}
/**
* 反注册 fragment 生命周期回调
*/
fun unRegister(activity: FragmentActivity?) {
activity?.supportFragmentManager?.unregisterFragmentLifecycleCallbacks(fragmentLifecycleCallbacks)
}
/**
* 裁剪 Bundle
* 在 Activity 的 onSaveInstanceState 中调用
*/
fun clipBundle(activity: Activity<*>?) {
if (activity == null || !activity.needClipBundleWhenSaveInstanceState()) {
pendingClearBundleList.clear()
return
}
if (pendingClearBundleList.isNotEmpty()) {
Log.i(TAG, "need clear fragment size: " + pendingClearBundleList.size)
pendingClearBundleList.forEach {
it.remove(BUNDLE_KEY_FRAGMENTS)
it.remove(BUNDLE_KEY_VIEWS)
}
pendingClearBundleList.clear()
}
}
}保存 Bundle 到内存, 并在 Activity 创建前替换, 缺点是不适用于首页(首页重启进程的话内存缓存也会丢失). 可以参考 掘金
改为单 Activity 框架