Skip to content

Commit 4502719

Browse files
authored
uplift(release): fix(message-list): recycler view in stale state (#10459, #10478) (#10503)
2 parents 2eb900e + 4e7a081 commit 4502719

File tree

2 files changed

+49
-15
lines changed

2 files changed

+49
-15
lines changed

legacy/ui/legacy/src/main/res/layout/message_list.xml

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,51 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<androidx.drawerlayout.widget.DrawerLayout
33
xmlns:android="http://schemas.android.com/apk/res/android"
4-
xmlns:app="http://schemas.android.com/apk/res-auto"
54
xmlns:tools="http://schemas.android.com/tools"
65
android:id="@+id/navigation_drawer_layout"
76
android:layout_width="match_parent"
87
android:layout_height="match_parent"
98
tools:context="com.fsck.k9.activity.MainActivity"
109
>
1110

12-
<androidx.coordinatorlayout.widget.CoordinatorLayout
11+
<!--
12+
As the navigation of Message List (MessageHomeActivity) is based on the ViewSwitcher,
13+
which just toggle the visibility of existing views rather than creating/destroying the
14+
Fragments, the Fragment's lifecycle methods, such as onViewCreated, are not properly called.
15+
16+
Modern layouts (ConstraintLayout, CoordinatorLayout) optimize measurement during visibility
17+
toggles and WindowInsets updates, sometimes causing a transient layout pass with incorrect bounds.
18+
The RecyclerView incorrectly treats this pass as a successful update and marks its state as "clean".
19+
Consequently, it fails to trigger onBindViewHolder when the view is fully restored, leaving the
20+
UI stuck displaying the previous stale state instead of the new data.
21+
22+
RelativeLayout is used to enforce strict vertical dependencies. By using layout_below, it
23+
ensures the Toolbar is measured before the container. This prevents the race condition and forces
24+
the RecyclerView to recognize its actual bounds, ensuring the adapter binds correctly without
25+
performance-heavy requestLayout() calls.
26+
27+
Until we move this screen to use a modern navigation system, or rewrite it using Jetpack Compose,
28+
we need to use this workaround.
29+
-->
30+
<RelativeLayout
1331
android:id="@+id/coordinator_layout"
1432
android:layout_width="match_parent"
1533
android:layout_height="match_parent"
16-
android:orientation="vertical"
1734
>
1835

1936
<com.google.android.material.appbar.AppBarLayout
2037
android:id="@+id/app_bar_layout"
2138
style="@style/Widget.App.AppBarLayout"
2239
android:layout_width="match_parent"
2340
android:layout_height="wrap_content"
41+
android:layout_alignParentTop="true"
2442
>
2543

2644
<include
2745
android:id="@+id/toolbar"
2846
layout="@layout/message_list_toolbar"
2947
android:layout_width="match_parent"
3048
android:layout_height="wrap_content"
31-
android:layout_alignParentTop="true"
3249
/>
3350

3451
</com.google.android.material.appbar.AppBarLayout>
@@ -37,7 +54,7 @@
3754
android:id="@+id/content_container"
3855
android:layout_width="match_parent"
3956
android:layout_height="match_parent"
40-
app:layout_behavior="@string/appbar_scrolling_view_behavior"
57+
android:layout_below="@id/app_bar_layout"
4158
>
4259

4360
<ProgressBar
@@ -58,23 +75,23 @@
5875

5976
<androidx.fragment.app.FragmentContainerView
6077
android:id="@+id/message_list_container"
61-
android:layout_width="fill_parent"
62-
android:layout_height="fill_parent"
78+
android:layout_width="match_parent"
79+
android:layout_height="match_parent"
6380
tools:layout="@layout/message_list_fragment"
6481
/>
6582

6683
<androidx.fragment.app.FragmentContainerView
6784
android:id="@+id/message_view_container"
68-
android:layout_width="fill_parent"
69-
android:layout_height="fill_parent"
85+
android:layout_width="match_parent"
86+
android:layout_height="match_parent"
7087
tools:layout="@layout/message"
7188
/>
7289

7390
</com.fsck.k9.view.ViewSwitcher>
7491

7592
</FrameLayout>
7693

77-
</androidx.coordinatorlayout.widget.CoordinatorLayout>
94+
</RelativeLayout>
7895

7996
<include layout="@layout/navigation_drawer_content" />
8097

legacy/ui/legacy/src/main/res/layout/split_message_list.xml

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,44 @@
88
android:layout_height="match_parent"
99
tools:context="com.fsck.k9.activity.MainActivity"
1010
>
11+
<!--
12+
As the navigation of Message List (MessageHomeActivity) is based on the ViewSwitcher,
13+
which just toggle the visibility of existing views rather than creating/destroying the
14+
Fragments, the Fragment's lifecycle methods, such as onViewCreated, are not properly called.
1115
12-
<androidx.coordinatorlayout.widget.CoordinatorLayout
16+
Modern layouts (ConstraintLayout, CoordinatorLayout) optimize measurement during visibility
17+
toggles and WindowInsets updates, sometimes causing a transient layout pass with incorrect bounds.
18+
The RecyclerView incorrectly treats this pass as a successful update and marks its state as "clean".
19+
Consequently, it fails to trigger onBindViewHolder when the view is fully restored, leaving the
20+
UI stuck displaying the previous stale state instead of the new data.
21+
22+
RelativeLayout is used to enforce strict vertical dependencies. By using layout_below, it
23+
ensures the Toolbar is measured before the container. This prevents the race condition and forces
24+
the RecyclerView to recognize its actual bounds, ensuring the adapter binds correctly without
25+
performance-heavy requestLayout() calls.
26+
27+
Until we move this screen to use a modern navigation system, or rewrite it using Jetpack Compose,
28+
we need to use this workaround.
29+
-->
30+
<RelativeLayout
1331
android:id="@+id/coordinator_layout"
1432
android:layout_width="match_parent"
1533
android:layout_height="match_parent"
16-
android:orientation="vertical"
1734
>
1835

1936
<com.google.android.material.appbar.AppBarLayout
2037
android:id="@+id/app_bar_layout"
2138
style="@style/Widget.App.AppBarLayout"
2239
android:layout_width="match_parent"
2340
android:layout_height="wrap_content"
41+
android:layout_alignParentTop="true"
2442
>
2543

2644
<include
2745
android:id="@+id/toolbar"
2846
layout="@layout/message_list_toolbar"
2947
android:layout_width="match_parent"
3048
android:layout_height="wrap_content"
31-
android:layout_alignParentTop="true"
3249
/>
3350

3451
</com.google.android.material.appbar.AppBarLayout>
@@ -37,7 +54,7 @@
3754
android:id="@+id/content_container"
3855
android:layout_width="match_parent"
3956
android:layout_height="match_parent"
40-
app:layout_behavior="@string/appbar_scrolling_view_behavior"
57+
android:layout_below="@id/app_bar_layout"
4158
>
4259

4360
<ProgressBar
@@ -86,7 +103,7 @@
86103

87104
</FrameLayout>
88105

89-
</androidx.coordinatorlayout.widget.CoordinatorLayout>
106+
</RelativeLayout>
90107

91108
<include layout="@layout/navigation_drawer_content" />
92109

0 commit comments

Comments
 (0)