先看adapter类
public class ControlPersonAdapter extends RecyclerView.Adapter {
private List controlPerson;
private Context context;
static class ViewHolder extends RecyclerView.ViewHolder{
TextView name;
TextView number;
TextView commandTitle;
TextView command;
TextView startTime;
TextView endTime;
Button edit,delete;
public ViewHolder(View view) {
super(view);
name = (TextView)view.findViewById(R.id.name);
number = (TextView)view.findViewById(R.id.number);
commandTitle = (TextView)view.findViewById(R.id.command_title);
command = (TextView)view.findViewById(R.id.command);
startTime = (TextView)view.findViewById(R.id.start_time);
endTime = (TextView)view.findViewById(R.id.end_time);
edit = (Button)view.findViewById(R.id.edit);
delete = (Button)view.findViewById(R.id.delete);
}
}
public ControlPersonAdapter(List controlPerson){
this.controlPerson = controlPerson;
}
// public void setList(List controlPerson){
// this.controlPerson = controlPerson;
// }
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_control,parent,false);
context = parent.getContext();
ViewHolder holder = new ViewHolder(view);
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
return holder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.name.setText(controlPerson.get(position).name);
holder.number.setText(controlPerson.get(position).number);
holder.command.setText(controlPerson.get(position).command);
holder.startTime.setText(controlPerson.get(position).startTime);
holder.endTime.setText(controlPerson.get(position).endTime);
if(controlPerson.get(position).isInControl){
holder.command.setTextColor(ContextCompat.getColor(context,R.color.car_normal));
holder.commandTitle.setTextColor(ContextCompat.getColor(context,R.color.car_normal));
}
holder.edit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//todo getong 26367 这里要打开新的界面编辑
Toast.makeText(context,"编辑",Toast.LENGTH_SHORT).show();
}
});
holder.delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//todo getong 26367 做删除
Toast.makeText(context,"删除",Toast.LENGTH_SHORT).show();
}
});
}
@Override
public int getItemCount() {
return controlPerson.size();
}
}
我们初始化adapter的代码:
adapter = new ControlPersonAdapter(controlPersonList);
recyclerView.setAdapter(adapter);
刷新dapter的代码:
private void initPerson() {
// controlPersonList.addAll(SharedPreferencesUtil.readControlPerson(getActivity()));//正确方法
controlPersonList = SharedPreferencesUtil.readControlPerson(getActivity());
// adapter.setList(controlPersonList);//很蠢的解决方法
adapter.notifyDataSetChanged();
if(controlPersonList.size() == 0){
nullRecord.setVisibility(View.VISIBLE);
recyclerView.setVisibility(View.GONE);
}else {
nullRecord.setVisibility(View.GONE);
recyclerView.setVisibility(View.VISIBLE);
}
}
理论上从SharedPreferencesUtil中读取值再赋给controlPersonList后,使用adapter.notifyDataSetChanged()刷新一下没问题的,然后我就打断点观察。
从SharedPreferencesUtil读取前:
读取后:
可以看到的是fragment中的变量controlPersonList变化了,但是adapter中的controlPerson没变。理论上两者是动态绑定的,指向同一块地址的,现在出现了指向地址不一样的情况,为刷新失败的原因。
读源码:
public void setAdapter(Adapter adapter) {
// bail out if layout is frozen
setLayoutFrozen(false);
setAdapterInternal(adapter, false, true);
requestLayout();
}
private void setAdapterInternal(Adapter adapter, boolean compatibleWithPrevious,
boolean removeAndRecycleViews) {
if (mAdapter != null) {
mAdapter.unregisterAdapterDataObserver(mObserver);
mAdapter.onDetachedFromRecyclerView(this);
}
if (!compatibleWithPrevious || removeAndRecycleViews) {
removeAndRecycleViews();
}
mAdapterHelper.reset();
final Adapter oldAdapter = mAdapter;
mAdapter = adapter;
if (adapter != null) {
adapter.registerAdapterDataObserver(mObserver);
adapter.onAttachedToRecyclerView(this);
}
if (mLayout != null) {
mLayout.onAdapterChanged(oldAdapter, mAdapter);
}
mRecycler.onAdapterChanged(oldAdapter, mAdapter, compatibleWithPrevious);
mState.mStructureChanged = true;
setDataSetChangedAfterLayout();
}
可见,在setadapter时候添加了一个mObserver观察者。
private class RecyclerViewDataObserver extends AdapterDataObserver {
RecyclerViewDataObserver() {
}
@Override
public void onChanged() {
assertNotInLayoutOrScroll(null);
mState.mStructureChanged = true;
setDataSetChangedAfterLayout();
if (!mAdapterHelper.hasPendingUpdates()) {
requestLayout();
}
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
assertNotInLayoutOrScroll(null);
if (mAdapterHelper.onItemRangeChanged(positionStart, itemCount, payload)) {
triggerUpdateProcessor();
}
}
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
assertNotInLayoutOrScroll(null);
if (mAdapterHelper.onItemRangeInserted(positionStart, itemCount)) {
triggerUpdateProcessor();
}
}
@Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
assertNotInLayoutOrScroll(null);
if (mAdapterHelper.onItemRangeRemoved(positionStart, itemCount)) {
triggerUpdateProcessor();
}
}
@Override
public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
assertNotInLayoutOrScroll(null);
if (mAdapterHelper.onItemRangeMoved(fromPosition, toPosition, itemCount)) {
triggerUpdateProcessor();
}
}
void triggerUpdateProcessor() {
if (POST_UPDATES_ON_ANIMATION && mHasFixedSize && mIsAttached) {
ViewCompat.postOnAnimation(RecyclerView.this, mUpdateChildViewsRunnable);
} else {
mAdapterUpdateDuringMeasure = true;
requestLayout();
}
}
}
再通过观察者类可以发现对item的更新插入都是这里观察者来实现的,观察者观察的是adapter指向的内容,具体也就是adapter中的list,list的有了新的值,但是原来的指向地址的值还没变,所以刷新就无效了。
图示:
oberserber永远观察的都是地址0x0001上的数据。现在list是有值了,但是地址变了。调用notifyDataSetChanged当前没有用了。
解决:
刷新dapter的代码中被我注掉的部分
controlPersonList.addAll(SharedPreferencesUtil.readControlPerson(getActivity()));
adapter.notifyDataSetChanged();
这样就可以把数据放到list1的位置上。
另一行被注掉的方式也能实现更新,去adapter中写一个setlist方法,重新去setList,但是太过愚蠢了。