【问题标题】:Save selected items in RecyclerView when switching Fragments切换 Fragments 时在 RecyclerView 中保存所选项目
【发布时间】:2018-07-25 08:25:39
【问题描述】:

我有一个包含 3 个片段选项卡的活动,您可以在它们之间切换。这些片段中的每一个都有一个 RecyclerView,单击时在其中选择/突出显示项目。这是通过我的自定义 RecyclerView 适配器中的onBindViewHolder 中的holder.setSelected(true) 完成的。

问题是当我在三个片段之间切换时,所选项目在看不见时被删除。我尝试将 RecyclerView 的状态保存在 onPause 并在 onResume 中恢复它,但这不起作用。

如何正确保存和检索所选项目?

这是我的自定义 RecyclerView 适配器(interface OnItemClickListener 在我当前的版本中没有使用):

public class ExerciseAdapter extends RecyclerView.Adapter<ExerciseAdapter.ExerciseViewHolder> {

private String[] mExampleList;
private OnItemClickListener mListener;

public interface OnItemClickListener {

}

public void setOnItemClickListener(OnItemClickListener listener) {
    mListener = listener;
}

public static class ExerciseViewHolder extends RecyclerView.ViewHolder {

    private TextView mTextView1;
    private ImageView mImageView;
    CardView mCardView;

    public ExerciseViewHolder(View itemView, final OnItemClickListener listener) {
        super(itemView);

        mTextView1 = itemView.findViewById(R.id.textViewExercise);
        mImageView = itemView.findViewById(R.id.imageView);
    }

    void setSelected(boolean selected){
        mTextView1.setSelected(selected);
    }
}

public ExerciseAdapter(String[] exampleList) {
    mExampleList = exampleList;
}

@NonNull
@Override
public ExerciseViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.exercise_item,parent,false);

    ExerciseViewHolder evh = new ExerciseViewHolder(v, mListener);

    return evh;
}

@Override
public void onBindViewHolder(@NonNull final ExerciseViewHolder holder, final int position) {

    holder.mTextView1.setText(mExampleList[position]);

    holder.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            holder.setSelected(true);
            Day1Activity.setTimer();

        }
    });

    holder.mImageView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            holder.setSelected(false);
        }
    });

}

@Override
public int getItemCount() {
    return mExampleList.length;
}

这是包含 RecyclerView 的片段之一:

public class Frag1 extends Fragment {

private RecyclerView mRecyclerView;
private ExerciseAdapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;


private View rootView;

DataModel dataModel = new DataModel();

String[] exercises = dataModel.C_lifts();

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    rootView = inflater.inflate(R.layout.frag1_layout, container, false);

   buildRecyclerView();

    return rootView;
}

private void buildRecyclerView() {
    mRecyclerView = rootView.findViewById(R.id.recyclerView);
    mRecyclerView.setHasFixedSize(true);
    mLayoutManager = new LinearLayoutManager(getContext());
    mAdapter = new ExerciseAdapter(exercises);

    mRecyclerView.setLayoutManager(mLayoutManager);
    mRecyclerView.setAdapter(mAdapter);

}

使用 ViewPager 处理 Fragments 的 Activity:

public class Day1Activity extends AppCompatActivity {

private static CountDownTimer countDownTimer;
private static TextView textViewTimer;

private static final String TAG = "Activity";

private SectionsPageAdapter mSectionsPageAdapter;
private ViewPager mViewPager;


@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.day1_layout);

    mSectionsPageAdapter = new SectionsPageAdapter(getSupportFragmentManager());

    mViewPager = findViewById(R.id.viewPagerContainer);
    setupViewPager(mViewPager);

    TabLayout tabLayout = findViewById(R.id.tabs);
    tabLayout.setupWithViewPager(mViewPager);

    Toolbar toolbar = findViewById(R.id.toolBar);
    setSupportActionBar(toolbar);
    textViewTimer = findViewById(R.id.textViewTimer);
}

private void setupViewPager(ViewPager viewPager) {
    int weekNumber = MainActivity.getWeekNumber();

    String frag1Title = "C-S";
    String frag2Title = "C-B";
    String frag3Title;
    if(weekNumber < 5) {
        frag3Title = "Rack Pulls";
    } else {
        frag3Title = "2ct Paused Deadlift";
    }

    SectionsPageAdapter adapter = new SectionsPageAdapter(getSupportFragmentManager());
    adapter.addFragment(new Frag1(),frag1Title);
    adapter.addFragment(new Frag2(),frag2Title);
    adapter.addFragment(new Frag3(),frag3Title);
    viewPager.setAdapter(adapter);

}

public static void setTimer() {
    if (countDownTimer != null) {
        countDownTimer.cancel();
    }

    countDownTimer = new CountDownTimer(240*1000, 1000) {

        public void onTick(long millisUntilFinished) {
            textViewTimer.setText("Seconds remaining: " + millisUntilFinished/1000);
        }

        public void onFinish() {
            textViewTimer.setText("Time is up!");
        }

    }.start();
}

非常感谢任何帮助!谢谢

【问题讨论】:

    标签: android android-fragments android-recyclerview


    【解决方案1】:

    将选定的项目保存到SparseBooleanArray,其中 key 是项目 positionvaluetruefalse 取决于选择。

    Fragment 被重新创建时,您必须将此数组保存在某个地方以便以后重用它。当 Fragment 被分离时,您可以将其保存在 onSaveInstanceState() 中,当您返回 Fragment 时,只需检查保存的实例是否具有您存储的数组并将其传递给 RecyclerView 适配器以在 onBindViewHolder()

    【讨论】:

    • 这很有意义。我现在查看了SpareseBooleanArray,并在我的适配器中创建了一个带有 setter 和 getter 的数组,这样我就可以将它保存在我的 Fragment 中:ExerciseAdapter.setItemStateArray((SparseBooleanArray) bundle.getParcelable("myBooleanArray"));。并检索:bundle.putParcelable("myBooleanArray", new SparseBooleanArrayParcelable(ExerciseAdapter.getmItemsStateArray()));。然而,问题是,在片段之间切换时永远不会调用onSaveInstanceState。我该如何解决这个问题?
    • 您使用的是 ViewPager 还是 Tabs?顺便提一句。通过在 onStop() 和 onDestroyView() 中记录某些内容来检查您的 Fragments 是否重新创建
    • 如果它们不是每次都重新创建,您可以将数组保存在 Fragment 的私有字段中。另一个建议:将此数组保存在 onPause() 方法的 SharedPreferences 中,然后在 onResume() 方法中重用它。这将确保即使您的应用在后台被系统杀死,您也可以重新创建选定的项目。
    • 我已经记录了它,可以看到它只在我在 Fragments 之间切换时调用 onStop()。我现在按照您的建议创建了一个私有数组字段,效果很好。但是,我仍然需要将此数组传递给我的 RecyclerView 适配器,但我不知道该怎么做,因为该项目是在 onBindViewHolder 中使用 holder.setSelected(true) 而不是位置选择的。
    • 好吧,如果 onStop() 被调用,那意味着当你回到这个 Fragment 时肯定会调用 onCreateView()。在 onCreateView() 中,您可以传递该数组并在 onBindViewHolder() 中使用它,如下所示:例如holder.setSelected(array.get(position, false));array 是一个保存了布尔值的数组,position 用于 onBindViewHolder() 参数,我们使用 false 表示没有保存的新行被添加到数组中的将不会被选中,因此如果 get 方法在布尔数组中找不到键,则调用 false。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-06
    • 1970-01-01
    • 2017-07-21
    相关资源
    最近更新 更多