我试图在片段中保存复选框的状态。我有一个测试,以确保在方向更改时恢复复选框状态。测试失败,因为未恢复复选框状态。但是,当我在测试期间单步执行代码时,它似乎按照我期望的方式工作。 enabledFields
在onPause()
,onSaveInstanceState()
和onCreate()
中具有正确的值。设置filterOptions
的正确元素进行检查。但是,它并未在屏幕上显示为已选中状态。我在这里缺少什么?
一些线索:
我有两个单独的测试,如下所示:testSaveInstanceStateBrand()
和testSaveInstanceStateTeam()
。在testSaveInstanceStateBrand()
中,方向更改后不会选中复选框。另一方面,在testSaveInstanceStateTeam()
中,选中所有复选框。由于我只在一个复选框上调用setChecked()
,因此似乎为所有CheckBox
绘制了相同的FilterOptionView
实例,但在Java代码中,每个FilterOptionView
都有引用自己的CheckBox
。
@RunWith(AndroidJUnit4.class)
public class FilterCardsTest {
@Rule
public ActivityTestRule<FragmentTestActivity> activityTestRule =
new ActivityTestRule<>(FragmentTestActivity.class);
private static final int[] IDS =
{R.id.brand, R.id.year, R.id.number, R.id.player_name, R.id.team};
private FragmentTestActivity activity = null;
private UiDevice device;
@Before
public void setUp() throws Exception {
activity = activityTestRule.getActivity();
activity.replaceFragment(new FilterCards());
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
}
@After
public void tearDown() throws RemoteException {
device.setOrientationNatural();
}
@Test
public void testSaveInstanceStateBrand() throws RemoteException {
this.testSaveInstanceState(R.id.brand);
}
@Test
public void testSaveInstanceStateTeam() throws RemoteException {
this.testSaveInstanceState(R.id.team);
}
private void testSaveInstanceState(int filterId) throws RemoteException {
this.testCheckBox(filterId);
device.setOrientationLeft();
onView(withId(filterId))
.check(matches(isChecked()));
onView(allOf(withParent(withId(filterId)), instanceOf(EditText.class)))
.check(matches(isEnabled()));
for (int id : IDS) {
if (id != filterId) {
onView(withId(id)).check(matches(isNotChecked()));
}
}
}
}
public class FilterCards extends Fragment {
private static final String INPUT_EXTRA = "input";
private static final String[] EXTRAS = {BRAND_EXTRA, YEAR_EXTRA, NUMBER_EXTRA,
PLAYER_NAME_EXTRA, TEAM_EXTRA};
@InjectViews({R.id.brand, R.id.year, R.id.number, R.id.player_name, R.id.team})
List<FilterOptionView> filterOptions;
private ArrayList<Integer> enabledFields = new ArrayList<>();
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.filter_cards, container, false);
ButterKnife.inject(this, view);
// restore input fields state
if (savedInstanceState != null) {
ArrayList<Integer> enabledFields = savedInstanceState
.getIntegerArrayList(INPUT_EXTRA);
Log.d(TAG, "enabledField=" + enabledFields);
if (enabledFields != null) {
for (int i : enabledFields) {
filterOptions.get(i).setChecked(true);
}
}
}
return view;
}
@Override
public void onPause() {
super.onPause();
enabledFields.clear();
for (int i = 0; i < filterOptions.size(); i++) {
if (filterOptions.get(i).isChecked()) {
enabledFields.add(i);
}
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putIntegerArrayList(INPUT_EXTRA, enabledFields);
}
}
public class FilterOptionView extends CheckableLinearLayout {
private TextView label;
private EditText edit;
public FilterOptionView(Context context) {
this(context, null);
}
public FilterOptionView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FilterOptionView(final Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
label = new TextView(context);
edit = new EditText(context);
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.FilterOptionView,
0, 0);
int[] set = {android.R.attr.enabled, android.R.attr.inputType, android.R.attr.singleLine};
TypedArray b = context.getTheme().obtainStyledAttributes(attrs, set, 0, 0);
try {
boolean enabled = a.getBoolean(0, true);
mCheckBox.setChecked(enabled);
label.setEnabled(enabled);
edit.setEnabled(enabled);
int labelWeight = a.getInt(R.styleable.FilterOptionView_labelWeight, 0);
ViewGroup.LayoutParams labelParams = new LinearLayout.LayoutParams(
0, LayoutParams.WRAP_CONTENT, labelWeight);
label.setLayoutParams(labelParams);
int editWeight = a.getInt(R.styleable.FilterOptionView_editWeight, 0);
ViewGroup.LayoutParams editParams = new LinearLayout.LayoutParams(
0, LayoutParams.WRAP_CONTENT, editWeight);
edit.setLayoutParams(editParams);
label.setText(a.getString(R.styleable.FilterOptionView_label));
label.setTextSize(a.getDimension(R.styleable.FilterOptionView_labelTextSize, 1.0f));
edit.setHint(a.getString(R.styleable.FilterOptionView_hint));
edit.setInputType(b.getInt(1, 0));
edit.setSingleLine(b.getBoolean(2, true));
} finally {
a.recycle();
}
this.addView(label);
this.addView(edit);
mCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
label.setEnabled(isChecked);
edit.setEnabled(isChecked);
edit.requestFocus();
// TODO: Should not be the responsibility of FilterOptionView
if (context instanceof ActionBarActivity) {
((ActionBarActivity) context).supportInvalidateOptionsMenu();
}
}
});
}
@Override
public void setChecked(boolean checked) {
super.setChecked(checked);
label.setEnabled(checked);
edit.setEnabled(checked);
edit.requestFocus();
}
public Editable getText() {
return edit.getText();
}
}
public class CheckableLinearLayout extends LinearLayout implements Checkable {
@InjectView(R.id.checkmark) CheckBox mCheckBox;
public CheckableLinearLayout(Context context) {
this(context, null);
}
public CheckableLinearLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CheckableLinearLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
View root = View.inflate(context, R.layout.checkable_linear_layout, this);
ButterKnife.inject(this, root);
}
public void setChecked(boolean checked) {
mCheckBox.setChecked(checked);
}
public boolean isChecked() {
return mCheckBox.isChecked();
}
@Override
public void toggle() {
mCheckBox.toggle();
}
}