Android-如何阻止片段自动恢复其状态?

时间:2019-04-27 10:33:42

标签: android android-fragments

我创建了一个全新的项目来演示我的问题。基本上,我的片段有两个RadioButton。在onCreateView上,我总是使用radioButtonFirst.setChecked(true);。但是,如果我检查radioButtonSecond,然后按“返回”按钮进行导航,然后再次打开它,它将自动检查radioButtonSecond。这种行为破坏了我的逻辑。

MainActivity.java

public class MainActivity extends AppCompatActivity {
    private WeirdFragment weirdFragment;
    private FragmentManager fragmentManager;
    private FragmentTransaction fragmentTransaction;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        weirdFragment = new WeirdFragment();
        fragmentManager = getSupportFragmentManager();
    }
    public void openFragment(View v){
        fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.add(R.id.container, weirdFragment);
        fragmentTransaction.addToBackStack(null);
        fragmentTransaction.commit();
    }
}

WeirdFragment.java

public class WeirdFragment extends Fragment {
    private RadioButton radioButtonFirst;
    private RadioButton radioButtonSecond;
    private Button buttonReturn;
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_weird, container, false);
        radioButtonFirst = view.findViewById(R.id.radio_button_first);
        radioButtonSecond = view.findViewById(R.id.radio_button_second);
        buttonReturn = view.findViewById(R.id.button_return);

        radioButtonFirst.setChecked(true);

        // I decide to set a listener right here, to see what happened to my radio button. So this listener will be removed in my real project.
        radioButtonSecond.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                Log.v("weird", "i got here");
            }
        });
        buttonReturn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getFragmentManager().beginTransaction().remove(WeirdFragment.this).commit();
            }
        });
        return view;
    }
}

activity_main.xml

<Button
    android:id="@+id/button_open"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:onClick="openFragment"
    android:text="Open"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

<FrameLayout
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintTop_toBottomOf="@id/button_open" />

fragment_weird.xml

<RadioGroup
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    app:layout_constraintTop_toTopOf="parent">

    <RadioButton
        android:id="@+id/radio_button_first"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:checked="true"
        android:text="First" />

    <RadioButton
        android:id="@+id/radio_button_second"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="Second" />
</RadioGroup>

<Button
    android:id="@+id/button_return"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Return"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintStart_toStartOf="parent" />

我在log语句中设置了一个断点。当用户操作触发该断点时,堆栈跟踪将如下所示:

onCheckedChanged:31, WeirdFragment$1 (com.peanut.myweirdradiobutton)
setChecked:154, CompoundButton (android.widget)
toggle:113, CompoundButton (android.widget)
toggle:78, RadioButton (android.widget)
performClick:118, CompoundButton (android.widget)
run:19866, View$PerformClick (android.view)
handleCallback:739, Handler (android.os)
dispatchMessage:95, Handler (android.os)
loop:135, Looper (android.os)
main:5254, ActivityThread (android.app)
invoke:-1, Method (java.lang.reflect)
invoke:372, Method (java.lang.reflect)
run:903, ZygoteInit$MethodAndArgsCaller (com.android.internal.os)
main:698, ZygoteInit (com.android.internal.os)

但是当断点被突然触发时,stracktrace看起来像这样:

onCheckedChanged:31, WeirdFragment$1 (com.peanut.myweirdradiobutton)
setChecked:154, CompoundButton (android.widget)
onRestoreInstanceState:522, CompoundButton (android.widget)
dispatchRestoreInstanceState:13740, View (android.view)
dispatchRestoreInstanceState:2893, ViewGroup (android.view)
dispatchRestoreInstanceState:2893, ViewGroup (android.view)
restoreHierarchyState:13718, View (android.view)
restoreViewState:494, Fragment (android.support.v4.app)
moveToState:1486, FragmentManagerImpl (android.support.v4.app)
moveFragmentToExpectedState:1784, FragmentManagerImpl (android.support.v4.app)
moveToState:1852, FragmentManagerImpl (android.support.v4.app)
executeOps:802, BackStackRecord (android.support.v4.app)
executeOps:2625, FragmentManagerImpl (android.support.v4.app)
executeOpsTogether:2411, FragmentManagerImpl (android.support.v4.app)
removeRedundantOperationsAndExecute:2366, FragmentManagerImpl (android.support.v4.app)
execPendingActions:2273, FragmentManagerImpl (android.support.v4.app)
run:733, FragmentManagerImpl$1 (android.support.v4.app)
handleCallback:739, Handler (android.os)
dispatchMessage:95, Handler (android.os)
loop:135, Looper (android.os)
main:5254, ActivityThread (android.app)
invoke:-1, Method (java.lang.reflect)
invoke:372, Method (java.lang.reflect)
run:903, ZygoteInit$MethodAndArgsCaller (com.android.internal.os)
main:698, ZygoteInit (com.android.internal.os)

所以我可以看到它是onRestoreInstanceState检查我的radioButtonSecond。但是我不知道如何预防。我正在考虑的事情:

  1. 在onViewStateRestored中执行我的逻辑。但这不是一个干净的解决方案。
  2. 每次需要打开片段时都要重新创建片段。但是,在创建新片段时,我的初始化阶段成本很高,我不应该这样做。

在我的真实项目中,此片段就像我的应用程序中的某项设置一样,它具有“取消”和“确定”按钮。因此,我希望片段每次打开时都处于默认状态,因为我认为,例如,用户可能配置了很多东西,但是按“取消”,则可以看到所有视图都处于默认状态状态,而不是已配置的状态(可能是这种想法导致了我的问题,这是一种很好的用户体验吗?)

那么,如何防止未经我允许的片段恢复其状态?

2 个答案:

答案 0 :(得分:2)

如果我对您的理解正确,那么您想在用户离开RadioButton之前重置Fragment的状态,以准备重新进入Fragment的情况在以后的某个时间。

由于您希望在用户离开RadioButton后每次重新输入Fragment时都要检查第一个Bundle,但是(我想)不是当用户刚离开您的应用程序半小时然后返回时要继续从中断处继续,您应使用 savedInstanceState RadioButton来确保private boolean isFirstButtonChecked = true;的状态取决于情况:

让我们介绍一个字段OnCheckedChangeListener

保留RadioButton来跟踪isFirstButtonChecked = radioButtonFirst.isChecked(); 的使用状态

boolean

除此之外,在true中将OnClickListener设置为buttonReturn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { isFirstButtonChecked = true; getFragmentManager().beginTransaction().remove(WeirdFragment.this).commit(); } });

onSaveInstanceState()

现在您可以在 @Override public void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); outState.putBoolean("FIRST_RB_STATE", isFirstButtonChecked); } @Override public void onViewStateRestored(@Nullable Bundle savedInstanceState) { super.onViewStateRestored(savedInstanceState); isFirstButtonChecked = savedInstanceState == null ? true : savedInstanceState.getBoolean("FIRST_RB_STATE"); radioButtonFirst.setChecked(isFirstButtonChecked); } 中保存所需的状态:

Fragment

我知道这意味着要添加很多代码。但是由于您每次都不愿意从头开始重新创建RadioButton,因为我认为它包含的不仅仅是两个super.onViewStateRestored(null);。因此,让运行时为您工作而不是为之苦苦挣扎,使此方法更安全,而不仅仅是在相应方法中调用foreach (DataRow rows in dtbl.Rows) { // Create Datagridview DataGridView datagridview = new DataGridView(); // Create link labels LinkLabel linkLabel = new LinkLabel(); // Add event handler to the link labels linkLabel.Click += new EventHandler(this.linkLabel_Click); this.Controls.Add(datagridview); this.Controls.Add(linkLabel); } // Event handler private void linkLabel_Click(object sender, EventArgs e) { // This doesnt work because "datagridview" doesnt exist, but I just have no idea how to get this to interact with the dynamically created datagridviews. int rowIndex = datagridview.Rows.Add(); DataGridViewRow row = datagridview.Rows[rowIndex]; row.Cells[0].Value = "5"; datagridview.CurrentCell = row.Cells[0]; } I expect each link label to add a new row to the datagridview it was created with in the for loop. But I just don't how to code it.

答案 1 :(得分:0)

self.aPIManager.registerDeviceId(deviceTokenStr,onSuccess:{
        getRegister in
},
    onError: { message in
        AppUtility.hideLoading(self.window!)
})

}

问题: 您总是在调用同一个weirdFragment对象。 因此,如果您上次选择第二个单选按钮并返回,下一次它将显示第二个选择的第二个按钮。

解决方案: 始终在openFragment函数中创建一个新的对象weirdfragment对象。