如何保存RecyclerView行项目的状态?

7
我有一个RecyclerView,它从SQL数据库中填充数据。现在,每行中都有一个SeekBar,当移动时,在同一行内的TextView中显示进度。问题是,当我向上或向下滚动RecyclerView然后返回到第一个更改的行时,SeekBar将返回到其默认位置。如何使其保存新位置?在普通的活动/片段中,我使用生命周期方法“onPause”来保存/恢复状态。在这里,我们有onAttachedToRecyclerView,我认为它应该解决我的问题,但我不知道具体如何操作。
编辑:以下是我正在测试此问题的完整简单应用程序文件。
MainActivity.class
public class MainActivity extends AppCompatActivity {
    private List<Score> scoreList = new ArrayList<>();
    private RecyclerView recyclerView;
    private MyAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);

    mAdapter = new MyAdapter(scoreList);
    RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
    recyclerView.setLayoutManager(mLayoutManager);
    recyclerView.setItemAnimator(new DefaultItemAnimator());
    recyclerView.setAdapter(mAdapter);

    prepareScoreData();
}

private void prepareScoreData() {
    Score score = new Score("title", 5);
    scoreList.add(score);

    for(int i= 0; i<1000; i++){
        score = new Score("title", 5);
        scoreList.add(score);
    }

    mAdapter.notifyDataSetChanged();
}
}

MyAdapter

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private List<Score> scoresList;

public class MyViewHolder extends RecyclerView.ViewHolder {
    TextView title, scoreView;
    SeekBar seekbar;

    public MyViewHolder(View view) {
        super(view);
        title = (TextView) view.findViewById(R.id.title);
        scoreView = (TextView) view.findViewById(R.id.score);
        seekbar = (SeekBar) view.findViewById(R.id.seekbar);
    }
}


public MyAdapter(List<Score> scoresList) {
    this.scoresList = scoresList;
}

@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View itemView = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.item, parent, false);

    return new MyViewHolder(itemView);
}


@Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
    final Score score = scoresList.get(position);
    holder.title.setText(score.getTitle());

    if (!score.getProgressed()) {
        holder.seekbar.setProgress(0) ;
    } else {
        holder.seekbar.setProgress(score.getSeekbarProgress());
    }

    holder.seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {

        @Override
        public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
            holder.scoreView.setText(String.valueOf(i));
            score.setSeekbarProgress(i);
            score.setProgressed(true);
        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {
        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
        }
    });
}

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

分数类

public class Score {
private String title;
int seekbarProgress;
boolean progressed;

public Score() {
}

public Score(String title,int seekbarProgress) {
    this.title = title;
    this.seekbarProgress = seekbarProgress;
}

public void setProgressed(boolean progressed) {
    this.progressed = progressed;
}



public void setTitle(String title) {
    this.title = title;
}

public void setSeekbarProgress(int seekbarProgress) {
    this.seekbarProgress = seekbarProgress;
}

public String getTitle() {
    return title;
}

public int getSeekbarProgress() {
    return seekbarProgress;
}

public boolean getProgressed() {
    return progressed;
}
}

主活动布局

    <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.moaness.tut_recyclerview.MainActivity">

    <!-- A RecyclerView with some commonly used attributes -->
    <android.support.v7.widget.RecyclerView
        android:id="@+id/my_recycler_view"
        android:scrollbars="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
    </RelativeLayout>

item.xml

    <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:focusable="true"
    android:paddingLeft="16dp"
    android:paddingRight="16dp"
    android:paddingTop="60dp"
    android:paddingBottom="60dp"
    android:layout_marginBottom="10dp"
    android:clickable="true"
    android:background="#f2f2f2"
    android:orientation="vertical">

    <TextView
        android:id="@+id/title"
        android:text="title"
        android:textColor="@color/title"
        android:textSize="16dp"
        android:paddingTop="16dp"
        android:textStyle="bold"
        android:layout_alignParentTop="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/score"
        android:text="score"
        android:layout_below="@+id/title"
        android:textSize="16dp"
        android:paddingBottom="16dp"
        android:textStyle="bold"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <SeekBar
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/score"
        android:id="@+id/seekbar"
        />

</RelativeLayout>

每次行视图离开并重新进入视图时,它都会从您提供的任何方法/数据重新填充。您需要将seekbar数据保存到本地数据库(如SQL),然后在填充行的逻辑中包含该逻辑。 - TWL
我不敢相信这种硬编码风格是这里唯一的方法 :( 对于像这样的小数据更改,一定有更简单的方法。 - Bialy
请提供代码片段以帮助我们更好地理解您的问题! - Smit
1个回答

13
如果您正在使用recyclerview,则需要维护每行的状态,这意味着如果您在recyclerview项的任何阶段(即在recyclerview适配器类中)使用条件(即if)进行检查,则还需要处理else。我可以发送给您代码片段,以便您对recyclerview适配器有一个很好的了解。
public class ContactsAdapter extends RecyclerView.Adapter<ContactsAdapter.ViewHolder> {
    List<ViewHolder> holders = new ArrayList<ViewHolder>();
    private ArrayList<ContactModel> arrayList = new ArrayList<>();
    private Context context;
    private LayoutInflater inflater;

    public void clearAdapter() {
        arrayList.clear();
        notifyDataSetChanged();
    }

    public ContactsAdapter(Context context, ArrayList<ContactModel> arrayList) {
        this.context = context;
        this.arrayList = arrayList;
    }

    public void setList(ArrayList<ContactModel> listSearch) {
        this.arrayList = listSearch;
        notifyItemRangeChanged(0, listSearch.size());
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    inflater = LayoutInflater.from(parent.getContext());
        View view = inflater.inflate(R.layout.custom_row_for_contacts, parent, false);
        ViewHolder viewHolder = new ViewHolder(view);
        holders.add(viewHolder);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(final ViewHolder holder, final int position) {
        final ContactModel current = this.arrayList.get(position);
        holder.txtDriverName.setText(current.getName());
        holder.txtDriverPhone.setText(current.getPhone());
        if (current.getImgUrl().length() > 0) {
            String urlLicenceThumb = UrlEndPoints.parentUrl + current.getImgUrl();
            Glide.with(context).load(urlLicenceThumb).error(R.mipmap.ic_launcher).into(holder.imgDriver);
        } else {
           Glide.with(context).load(R.mipmap.ic_launcher).into(holder.imgDriver);
        }
    }

    public void delete(int position) {
        arrayList.remove(position);
        notifyItemRemoved(position);
    }

    @Override
    public int getItemCount() {
        return (null != arrayList ? arrayList.size() : 0);
    }

    class ViewHolder extends RecyclerView.ViewHolder {
        private TextView txtDriverName, txtDriverPhone;
        private CircleImageView imgDriver;
        private Button btnInvite;
        private CheckBox chkAdd;

        public ViewHolder(View itemView) {
            super(itemView);
            chkAdd = (CheckBox) itemView.findViewById(R.id.chkAdd);
            imgDriver = (CircleImageView) itemView.findViewById(R.id.imgDriver);
            txtDriverName = (TextView)itemView.findViewById(R.id.txtDriverName);
            txtDriverPhone = (TextView)     itemView.findViewById(R.id.txtDriverPhone);
            btnInvite = (Button) itemView.findViewById(R.id.btnInvite);
        }
    }
}

是的,请,一个代码片段会更好。非常感谢。 - Bialy
如果(current.isChecked()){//---某些条件       holder.chkAdd.setText("已选中");} else {       holder.chkAdd.setText("未选中"); } - Maddy
1
太棒了,您为我解决了一个重大的误解,因为RecyclerView在没有预定义值的情况下会从顶部行到下面的行“缓存”值。现在问题仍然存在,当我更改滚动条的值时,向下滚动然后返回顶部时,它会返回到0 :( - Bialy
我有和你一样的问题,我有一个联系人列表需要放在recyclerview中,每个联系人都有一个复选框。当我滚动屏幕后勾选框会出现问题。我已经通过我的适配器解决了这个问题,我已经向你展示了如何在模型类对象中保存状态(在本例中是当前对象),你需要保存该对象中的复选框值。 - Maddy
1
@Baily,你能否提供一些关于你如何解决这个问题的线索?我也遇到了同样的问题。http://stackoverflow.com/questions/40142216/save-state-of-the-item-selected-in-recyclerview-when-multiple-items-selected/40142339?noredirect=1#comment67706536_40142339 - Gaurav Sarma
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接