在旋转时分配正确的 android 片段
Assign the right android fragment on rotate
我最近一直在开发一个小型 Android 应用程序,但我遇到了一个很难解决的错误。
因为我使用的是 BottomNavigationView,所以我必须像这样初始化我的 Home 片段:
@Override
protected void onStart(){
super.onStart();
FragmentTransaction f = fm.beginTransaction();
f.replace(R.id.content, homeFragment).commit();
}
替换发生在这个 FrameLayout 上:
<FrameLayout
android:id="@+id/content"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="visible"
app:layout_constraintBottom_toTopOf="@+id/navigation"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0" />
但这会引发一个小错误:如果我旋转设备,片段将设置回我的 homeFragment,而不管当前的片段。
因为我不能直接打电话给我
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
//
}
我尝试了一些转变:
- 我试过使用布尔值 isFragmentInitialized
- 我尝试将 onNavigation 函数分散到外部私有 setFragment 函数中,该函数检查 selected 菜单项并应用相应的片段
- 我试过直接从 homeFragment 开始,而不是我正在使用的线性视图
但是这些解决方案并没有带来好运:
最后一个在你转动屏幕和 select home
后崩溃
其他的只是导致与我的标准初始化相同的情况。
您可以执行此操作的一种方法是创建一个变量来存储片段标记,在处理底部导航的开关盒中,您可以在该变量中保存适当的标记。然后实现 onSaveInstanceState
函数并将该标记写入您的外州。最后,监听 onCreate
中保存的实例状态并启动适当的片段。像这样:
String fragmentTag;
String FRAGMENT-TAG-KEY = "fragment-tag";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// recovering the instance state
if (savedInstanceState != null) {
String fragmentTag = savedInstanceState.getString("FRAGMENT-TAG-KEY");
switch (fragmentTag){
case "FragmentA": {
//launch this fragment.
break;
}
case "FragmentB": {
//launch this fragment.
break;
}
}
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putString(FRAGMENT-TAG-KEY, fragmentTag);
super.onSaveInstanceState(outState);
}
bottomNavigationView.setOnNavigationItemSelectedListener(
new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.action_home: {
fragmentTag = "FragmentA";
}
case R.id.action_fragmentb: {
fragmentTag = "FragmentA";
}
}
return true;
}
});
如果特定片段需要存储数据,您可以将其存储在本地并重新加载。否则,您可能必须将数据发送回 activity,然后将其传递到您的片段中。可能是这样的情况,你可以存储片段的实例并在片段中实现 outstate,然后在片段中的 onActivityCreated
中你可以恢复你的实例状态。我不确定您的其余代码是什么样子,所以我只能推测您可能会如何存储片段的数据(如果有的话)。
只有在用户第一次导航到您的 Activity
时才会导致您的代码 运行 的最简单方法是将您的代码从 onStart()
移动到 onCreate()
并将其包装在 if
语句中,该语句检查 savedInstanceState
是否为空(只有在 activity 第一次启动时才为真)。
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate();
// the rest of your onCreate() etc...
if (savedInstanceState == null){
FragmentTransaction f = fm.beginTransaction();
f.replace(R.id.content, homeFragment).commit();
}
}
您可以仅在 activity 第一次启动时将此技术用于您想要 运行 的任何内容,而不仅仅是 FragmentTransaction
s。虽然片段是这个技巧的一个非常常见的用例。
我最近一直在开发一个小型 Android 应用程序,但我遇到了一个很难解决的错误。
因为我使用的是 BottomNavigationView,所以我必须像这样初始化我的 Home 片段:
@Override
protected void onStart(){
super.onStart();
FragmentTransaction f = fm.beginTransaction();
f.replace(R.id.content, homeFragment).commit();
}
替换发生在这个 FrameLayout 上:
<FrameLayout
android:id="@+id/content"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="visible"
app:layout_constraintBottom_toTopOf="@+id/navigation"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0" />
但这会引发一个小错误:如果我旋转设备,片段将设置回我的 homeFragment,而不管当前的片段。
因为我不能直接打电话给我
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
//
}
我尝试了一些转变:
- 我试过使用布尔值 isFragmentInitialized
- 我尝试将 onNavigation 函数分散到外部私有 setFragment 函数中,该函数检查 selected 菜单项并应用相应的片段
- 我试过直接从 homeFragment 开始,而不是我正在使用的线性视图
但是这些解决方案并没有带来好运:
最后一个在你转动屏幕和 select home
后崩溃
其他的只是导致与我的标准初始化相同的情况。
您可以执行此操作的一种方法是创建一个变量来存储片段标记,在处理底部导航的开关盒中,您可以在该变量中保存适当的标记。然后实现 onSaveInstanceState
函数并将该标记写入您的外州。最后,监听 onCreate
中保存的实例状态并启动适当的片段。像这样:
String fragmentTag;
String FRAGMENT-TAG-KEY = "fragment-tag";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// recovering the instance state
if (savedInstanceState != null) {
String fragmentTag = savedInstanceState.getString("FRAGMENT-TAG-KEY");
switch (fragmentTag){
case "FragmentA": {
//launch this fragment.
break;
}
case "FragmentB": {
//launch this fragment.
break;
}
}
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putString(FRAGMENT-TAG-KEY, fragmentTag);
super.onSaveInstanceState(outState);
}
bottomNavigationView.setOnNavigationItemSelectedListener(
new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.action_home: {
fragmentTag = "FragmentA";
}
case R.id.action_fragmentb: {
fragmentTag = "FragmentA";
}
}
return true;
}
});
如果特定片段需要存储数据,您可以将其存储在本地并重新加载。否则,您可能必须将数据发送回 activity,然后将其传递到您的片段中。可能是这样的情况,你可以存储片段的实例并在片段中实现 outstate,然后在片段中的 onActivityCreated
中你可以恢复你的实例状态。我不确定您的其余代码是什么样子,所以我只能推测您可能会如何存储片段的数据(如果有的话)。
只有在用户第一次导航到您的 Activity
时才会导致您的代码 运行 的最简单方法是将您的代码从 onStart()
移动到 onCreate()
并将其包装在 if
语句中,该语句检查 savedInstanceState
是否为空(只有在 activity 第一次启动时才为真)。
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate();
// the rest of your onCreate() etc...
if (savedInstanceState == null){
FragmentTransaction f = fm.beginTransaction();
f.replace(R.id.content, homeFragment).commit();
}
}
您可以仅在 activity 第一次启动时将此技术用于您想要 运行 的任何内容,而不仅仅是 FragmentTransaction
s。虽然片段是这个技巧的一个非常常见的用例。