【问题标题】:Save selected items in RecyclerView when closing app or switching fragments关闭应用或切换 Fragment 时在 RecyclerView 中保存所选项目
【发布时间】:2018-07-21 13:43:47
【问题描述】:

我的片段中有一个Recycler View,它会在单击某个项目时打开活动,并在长时间单击该项目时突出显示该项目。但是,当我切换片段或关闭我的应用程序并重新打开它时,我希望之前选择的项目保持选中状态。我想这是用Shared Preferences 完成的,但是如何保存所选项目然后再次填充?

这是我的自定义适配器。 TextViewsonBindViewHolder 中被选中:

public class ExampleAdapter extends RecyclerView.Adapter<ExampleAdapter.ExampleViewHolder> {

private ArrayList<Workout> mExampleList;
private OnItemClickListener mListener;

public interface OnItemClickListener {
    void onItemClick(int position);

}

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

public static class ExampleViewHolder extends RecyclerView.ViewHolder {

    public TextView mTextView1,mTextView2,mTextView3,mTextView4;
    CardView mCardView;

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

        mTextView1 = itemView.findViewById(R.id.listTextView1);
        mTextView2 = itemView.findViewById(R.id.listTextView2);
        mTextView3 = itemView.findViewById(R.id.listTextView3);
        mTextView4 = itemView.findViewById(R.id.listTextView4);

        mCardView = itemView.findViewById(R.id.cardView);

        itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(listener != null) {
                    int position = getAdapterPosition();
                    if (position != RecyclerView.NO_POSITION) {
                        listener.onItemClick(position);
                    }
                }
            }
        });
    }
}

public ExampleAdapter(ArrayList<Workout> exampleList) {
    mExampleList = exampleList;
}

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

    ExampleViewHolder evh = new ExampleViewHolder(v, mListener);

    return evh;
}

@Override
public void onBindViewHolder(@NonNull final ExampleViewHolder holder, final int position) {
    Workout workout = mExampleList.get(position);

    holder.mTextView1.setText(workout.getText1());
    holder.mTextView2.setText(workout.getText2());
    holder.mTextView3.setText(workout.getText3());
    holder.mTextView4.setText(workout.getText4());

    holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View view) {
            if(holder.mTextView1.isSelected()) {
                holder.mTextView1.setSelected(false);
                holder.mTextView2.setSelected(false);
                holder.mTextView3.setSelected(false);
                holder.mTextView4.setSelected(false);
            } else {
                holder.mTextView1.setSelected(true);
                holder.mTextView2.setSelected(true);
                holder.mTextView3.setSelected(true);
                holder.mTextView4.setSelected(true);
            }
            return true;
        }
    });

}

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

这是我的片段:

public class HomeFragment extends Fragment implements View.OnClickListener{

private RecyclerView mRecyclerView;
private ExampleAdapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
ArrayList<Workout> exampleList;

MainActivity mainActivity;
DataModel dataModel = new DataModel();

View rootView;

private TextView[] textViews;
private CardView[] cardViews;

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

    rootView = inflater.inflate(R.layout.fragment_home,container,false);

    mainActivity = (MainActivity) getActivity();
    mainActivity.setToolbarName("Workouts");

    textViews = new TextView[16];
    cardViews = new CardView[3];

    for(int i=0; i<textViews.length; i++) {
        {
            String buttonID = "textView" + (i+1);

            int resID = getResources().getIdentifier(buttonID, "id", getActivity().getPackageName());
            textViews[i] = ((TextView) rootView.findViewById(resID));
        }
    }

    updateWeekText();

    textViews[2].setText(roundDecimals(mainActivity.getBenchMax()));
    textViews[4].setText(roundDecimals(mainActivity.getSquatMax()));
    textViews[6].setText(roundDecimals(mainActivity.getDeadliftMax()));
    textViews[8].setText(roundDecimals(mainActivity.getPressMax()));

    Button buttonNextWeek = rootView.findViewById(R.id.buttonNextWeek);
    buttonNextWeek.setOnClickListener(this);

    int week = MainActivity.getWeekNumber();

    exampleList = new ArrayList<>();
    if(week == 1 || week == 2 || week == 3 || week == 4){
        exampleList.add(new Workout("Day 1", "C-S", "C-B", "Rack Pulls"));
        exampleList.add(new Workout("Day 2", "2ct Paused Squat", "C-P", "Pendlay Row"));
        exampleList.add(new Workout("Day 3", "C-D", "Floor Press", "Leg Press"));
    } else {
        exampleList.add(new Workout("Day 1", "C-S", "C-B", "2ct Paused Deadlift"));
        exampleList.add(new Workout("Day 2", "Pin Squat", "C-P", "Pendlay Row"));
        exampleList.add(new Workout("Day 3", "C-D", "2ct Paused Bench", "303 Tempo Squat"));
    }

    buildRecyclerView();

    return rootView;
}

public void buildRecyclerView() {
    mRecyclerView = rootView.findViewById(R.id.recyclerView);
    mRecyclerView.setHasFixedSize(true);
    mLayoutManager = new LinearLayoutManager(getContext());
    mAdapter = new ExampleAdapter(exampleList);

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

    mAdapter.setOnItemClickListener(new ExampleAdapter.OnItemClickListener() {
        @Override
        public void onItemClick(int position) {
            if (position == 0) {
                startActivity(new Intent(getActivity(),ActivityDay1.class));
            }
            if (position == 1) {
                startActivity(new Intent(getActivity(),ActivityDay2.class));
            }
        }
    });
}

@Override
public void onClick(View view) {
    switch (view.getId()) {
        case R.id.buttonNextWeek:
            createDialog();
            break;
    }
}

private void updateWeekText() {
    textViews[9].setText("Current week: "+String.valueOf(mainActivity.getWeekNumber()));
}

private void createDialog(){
    int nextWeek = mainActivity.getWeekNumber()+1;

    AlertDialog.Builder builder;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        builder = new AlertDialog.Builder(getContext(), android.R.style.Theme_Material_Dialog_Alert);
    } else {
        builder = new AlertDialog.Builder(getContext());
    }
    builder.setTitle("Start week "+nextWeek+"?")
            .setMessage("Are you sure?")
            .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    mainActivity.setWeekNumber(mainActivity.getWeekNumber()+1);
                    updateWeekText();
                }
            })
            .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    // do nothing
                }
            })
            .setIcon(R.drawable.ic_navigate_next_black_24dp)
            .show();
}

public String roundDecimals(double a){
    NumberFormat nf = new DecimalFormat("##.###");
    return nf.format(a);
}

我将不胜感激。
如果需要更多代码,请告诉我。

【问题讨论】:

    标签: java android android-recyclerview sharedpreferences


    【解决方案1】:

    您需要先修复 Adapter 实现中的一些错误。

    isCompleted 布尔字段添加到您的 Workout 类中。使用当前的适配器实现,您的“选定”状态仅通过滚动 recyclerView 就会变得混乱,因为您不存储值,只需更改 ViewHolder 状态。

    LongLickListener 的正文移动到ViewHolder 的新方法中:

    void setSelected(boolean selected){
        mTextView1.setSelected(selected);
        mTextView2.setSelected(selected);
        mTextView3.setSelected(selected);
        mTextView4.setSelected(selected);
    }
    

    现在您可以将您的LongClickListener 更改为:

    @Override
    public boolean onLongClick(View view) {
        workout.isCompleted = !workout.isCompleted;
        holder.setSelected(workout.isCompleted);
        return true;
    }
    

    这种方式的锻炼完成状态实际上存储在您的数据列表中。为确保视图状态正确,请将此行添加到您的onBindViewHolder

    holder.setSelected(workout.isCompleted);
    

    否则之前绑定到“已完成”锻炼的 ViewHolder 在显示“未完成”锻炼时会错误地显示。

    至于存储所选项目 - 这有点棘手,因为它主要是持久性/数据库设计问题。

    • 您的Workout 项目只是锻炼的定义吗?
    • 它们会反复出现吗?
    • 用户可以添加/删除锻炼定义吗?
    • 是否有已完成锻炼的历史记录?还是每天重置?

    您至少需要为每个锻炼定义一些稳定的ID 以正确持久化它们,然后我建议使用原始SQLiteRoomRealm 研究数据库实现。

    【讨论】:

    • 这很有意义,谢谢@Pawel!但我不明白void setSelected(boolean selected)-method 应该放在哪里。我不断得到一个空对象引用。
    • @Ferhnovic 修复了我的小错误。这应该是您的 ExampleViewHolder 类的方法。
    猜你喜欢
    • 1970-01-01
    • 2018-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-20
    • 1970-01-01
    相关资源
    最近更新 更多