My Android app is handling configuration changes manually (for reasons I cannot change) and need to re-inflate a GridLayout with different rows and columns depending on the orientation. My solution works great on the Nexus 5 emulator, but often fails on my Galaxy S6 phone.
Working screenshots from emulator:
This sometimes works on my phone, but about half of the time this is what happens after rotating from landscape to portrait:
It seems like the old layout padding and margin values are being used instead of the new values that are created when the layout is re-inflated. Furthermore, this appears to be a timing issue (see the Hack at the end of my question).
Code
Here is the fragment's layout that uses a GridLayout where columnCount
and rowCount
change based on the orientation:
fragment_my.xml
<android.support.v7.widget.GridLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:grid="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
grid:columnCount="@integer/col_count"
grid:rowCount="@integer/row_count"
grid:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="80sp"
grid:layout_gravity="center"
grid:layout_columnWeight="1"
grid:layout_rowWeight="1"
android:text="A"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="80sp"
grid:layout_gravity="center"
grid:layout_columnWeight="1"
grid:layout_rowWeight="1"
android:text="B"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="80sp"
grid:layout_gravity="center"
grid:layout_columnWeight="1"
grid:layout_rowWeight="1"
android:text="C"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="80sp"
grid:layout_gravity="center"
grid:layout_columnWeight="1"
grid:layout_rowWeight="1"
android:text="D"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="80sp"
grid:layout_gravity="center"
grid:layout_columnWeight="1"
grid:layout_rowWeight="1"
android:text="E"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="80sp"
grid:layout_gravity="center"
grid:layout_columnWeight="1"
grid:layout_rowWeight="1"
android:text="F"/>
</android.support.v7.widget.GridLayout>
res/values/ints.xml
<resources>
<integer name="row_count">3</integer>
<integer name="col_count">2</integer>
</resources>
res/values-land/ints.xml
<resources>
<integer name="row_count">2</integer>
<integer name="col_count">3</integer>
</resources>
Here's the relevant parts of my fragment that creates a FrameLayout for the parent view and reloads fragment_my.xml when the orientation changes.
private FrameLayout mFrameLayout;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
mFrameLayout = new FrameLayout(getContext());
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_my, mFrameLayout, true);
}
@Override
public void onConfigurationChanged(Configuration newConfig)
{
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE ||
newConfig.orientation == Configuration.ORIENTATION_PORTRAIT)
{
// Get rid of previous GridLayout
mFrameLayout.removeAllViews();
// Reload GridLayout with new row/col values
LayoutInflater inflator = LayoutInflater.from(getContext());
inflator.inflate(R.layout.fragment_my, mFrameLayout, true);
}
super.onConfigurationChanged(newConfig);
}
Hack
Here's a hack I can use to "fix" the problem on my phone: delay 100 milliseconds before inflating:
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
mFrameLayout.removeAllViews();
LayoutInflater inflator = LayoutInflater.from(getContext());
inflator.inflate(R.layout.fragment_my, mFrameLayout, true);
}
}, 100);
This is obviously not ideal as it relies on some timing issue that may vary from phone to phone. Seems like I need to be notified when some internal configuration has completed before I re-inflate, but I can't seem to find any callbacks that do this.
Any help would be greatly appreciated.
Update
I believe the problem is a bug within the GridLayout. You can see a related question I asked elsewhere dealing with a resizing of the GridLayout that resulted in a similar problem. I have replaced my GridLayout with a ConstraintLayout and had no problems.