Preserve open tabs
- Always preserve tabs opened by the user.
- When changing languages, open a new main page tab in the foreground.
- Add Gson library and update ProGuard configuration. The new library increases the size of the release APK by ~50KiB.
Initial research in Phab T103954 suggested that the AOSP Browser
implementation was favorable. Upon further research, converting Bundles
to Parcels and writing them to disk is highly discouraged in the Parcel
Parcel is not a general-purpose serialization mechanism. This class
(and the corresponding Parcelable API for placing arbitrary objects into a Parcel) is designed as a high-performance IPC transport. As such, it is not appropriate to place any Parcel data in to persistent storage: changes in the underlying implementation of any of the data in the Parcel can render older data unreadable.
This made the Browser approach ultimately unfavorable. Alternatives
considered included Java serialization, databases, a custom file format,
It was unfortunate that Bundles could not be used as a large portion of
app state that is desirable to preserve has mixed responsibilities with
Bundles and Parcelable marshalling, which is encouraged in many official
examples. This influenced the consideration of alternatives. Additional
recording mechanisms leveraged in the app include databases and
Java serialization is a classic choice. However, Effective Java
dedicates a chapter to the dangers and encourages very judicial usage of
Allowing a class's instances to be serialized can be as simple as
adding the words "implements Serializable" to its declaration. Because this is so easy to do, there is a common misconception that serialization requires little effort on the part of the programmer. The truth is far more complex. While the immediate cost to make a class serializable can be negligible, the long-term costs are often substantial. A major cost of implementing Serializable is that it decreases the flexibility to change a class's implementation once it has been released. When a class implements Serializable, its byte-stream encoding (or serialized form) becomes part of its exported API. Once you distribute a class widely, you are generally required to support the serialized form forever, just as you are required to support all other parts of the exported API. If you do not make the effort to design a custom serialized form, but merely accept the default, the serialized form will forever be tied to the class's original internal representation. In other words, if you accept the default serialized form, the class's private and package-private instance fields become part of its exported API, and the practice of minimizing access to fields loses its effectiveness as a tool for information hiding.
In the interest of avoiding such an initial investment, as well as long
term costs, Java serialization was not chosen.
Although a scalable choice, most databases on Android have uncomfortable
lifecycles, even considering wrappers such as SQLiteOpenHelper, that
frequently introduce bugs, especially when used in conjunction with
Activity and Fragment lifecycles.
A custom file format was briefly considered, but it was immediately more
favorable to prefer established formats such as JSON.
SharedPreferences in themselves, support (all?) Java primitives, and
could be used. They're favorable because they supply an asynchronous
write mechanism which may be used from the main thread, i.e., no
worrying lifecycles, and are commonly used in general. However,
marshallers and unmarshallers would still need to be built.
Gson supports reflection based to and fro JSON serialization without the
need to write marshallers and unmarshallers. This is two edged sword in
that there are still the versioning concerns of Serializable, but Gson
supplies annotations to avoid these issues.
Gson used in conjunction with SharedPreferences supplies a full