bluelinelabs / bluelinelabs/Conductor
Controller.saveViewState causes problems with nested Controllers and common view IDs
- Dominant language
- Java
- Stars
- 3.9k
- Forks
- 338
- PR merge metrics
- No merged PRs in 30d
Description
I'm running into an issue where my app crashes on rotation with:
```
java.lang.IllegalArgumentException: Wrong state class, expecting View State but received class android.support.v7.widget.RecyclerView$SavedState instead. This usually happens when two views of different type have the same id in the same hierarchy.
```
The view hierarchy has a root controller with a viewpager that is hosting controllers of its own. The first child controller hosts a custom ViewGroup that wraps a RecyclerView but is treated as if it is a RecyclerView by callers. The second controller hosts a plain old RecyclerView. Both of these views have an id of ```recycler_view```. Obviously renaming the ID of one of these will solve the bug but I think that there's still a problem with how nested Controller's view state is saved that is causing this issue.
```
--------------------------------------------
| Parent Controller |
| -------------------------------------- |
| | Child | Child | |
| | Controller | Controller | |
| | 1 | 2 | |
| -------------------------------------- |
--------------------------------------------
```
Currently when controllers are saved, ```saveHierarchyState``` is called on the controller's root view which recurses the view tree under said controller. This works great for Child Controllers 1 and 2 in the diagram but when Parent Controller saves its hierarchy this includes the views under its children's control. If those children have conflicting view IDs then the saved state of 2 will overwrite 1 producing the error I experienced above. It also means that save/restore work is duplicated since the Child and Parent Controllers call the same save/restore methods on the views belonging to the children.
I've created a repro of the problem [here](https://github.com/jhorvat/ViewInstanceStateRepro). The crash in the repro can be avoided by either changing the ID of one of the views with ```recycler_view``` as their ID or swapping the order of ```frame_container``` and ```recycler_container``` in the ```LinearLayout```.
Contributor guide
Research direction
Start with Controller.saveViewState and the saveHierarchyState/save-restore flow described in the issue. Reproduce the nested-controller rotation crash using the linked ViewInstanceStateRepro, then verify that parent and child controllers do not duplicate ownership of descendant view state and that rotation no longer fails with conflicting recycler_view IDs.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, java
- Domain
- mobile
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100