Как работает Parcelable?
Я хотел сохранить сложный объект Java во время поворота экрана, поэтому я сделал объект Parcelable и реализовал необходимые методы:
- в методе writeToParcel(Parcel dest, int flags) я сохранил некоторые значения в "dest".
- в методе Parcelable.Creator createFromParcel(источник Parcel) я получил значения из "источника" в правильном порядке и возвратил соответствующий объект.
Затем в onSaveInstanceState фрагмента я сохранил Parcelable:
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable("myObject", myObject);
}
и получил мой объект в onCreate фрагмента:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyObject myObject = savedInstanceState.getParcelable("myObject");
}
Это сработало отлично.
Затем я сделал тест:
- Удалил весь мой код в методе writeToParcel.
- Возвращено значение null в методе createFramParcel.
Когда я запустил приложение, я получил ТОЧНЫЙ ЖЕ РЕЗУЛЬТАТ! Я получил объект со всеми соответствующими значениями в нем.
Почему это сработало? Parcelable создает "Parcelable объекты" автоматически?
1 ответ
Да, так что это связано с тем, как Bundle обрабатывает внутреннее кэширование и распределение. Когда вы звоните putParcelable()
, он запускает следующий код:
public void putParcelable(@Nullable String key, @Nullable Parcelable value) {
unparcel();
mMap.put(key, value);
mFdsKnown = false;
}
Таким образом, в основном, данные в Bundle
не сразу записывается в Parcel
- mMap
является ArrayMap<String, Object>
и он содержит кэш всех объектов в Bundle
как они вставлены или удалены.
В какой-то момент, writeToParcel()
будет вызван на Bundle
в этот момент все в mMap
записывается в mParcelledData
,
Таким образом, в основном, когда вы делаете изменение конфигурации, Bundle
до сих пор не было написано Parcel
таким образом, тот же экземпляр объекта, который вы передали, все еще сохраняется в Bundle
"s mMap
(так что ваш объект также никогда не имел writeToParcel()
вызвано - вы можете подтвердить это, утверждая, что объект до и после изменения конфигурации имеет одинаковый System.identityHashCode()
).
Вы можете увидеть заметки об этом в BaseBundle
:
// Invariant - exactly one of mMap / mParcelledData will be null
// (except inside a call to unparcel)
ArrayMap<String, Object> mMap = null;
/*
* If mParcelledData is non-null, then mMap will be null and the
* data are stored as a Parcel containing a Bundle. When the data
* are unparcelled, mParcelledData willbe set to null.
*/
Parcel mParcelledData = null;
Так что, если вы должны были написать свой Parcelable
возражать против пакета сохранения состояния и помещать приложение в фоновом режиме до тех пор, пока процесс не прекратится (или я полагаю, что вы можете форсировать это, запустив adb shell am kill <application_id>
), а затем возобновить, вы столкнетесь с проблемой, когда ваши данные не правильно распределены.