我的RecyclerView
中的每个项目都由4个EditTexts
组成。
只要没有可回收的物品,我的应用程序就可以更改其中任何EditTexts
中的文本。
但是,无论选择什么,只要回收项目,就只能正确更新项目中的第一个(我是最左边的)Edittext
。
有什么想法可能出问题吗?
这是堆栈的顶部:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: be.ema.moles, PID: 8968
java.lang.NullPointerException: Attempt to invoke virtual method 'int androidx.recyclerview.widget.RecyclerView$ViewHolder.getAdapterPosition()' on a null object reference
at androidx.recyclerview.selection.StableIdKeyProvider.onDetached(StableIdKeyProvider.java:90)
at androidx.recyclerview.selection.StableIdKeyProvider$1.onChildViewDetachedFromWindow(StableIdKeyProvider.java:69)
at androidx.recyclerview.widget.RecyclerView.dispatchChildDetached(RecyclerView.java:7261)
at androidx.recyclerview.widget.RecyclerView.removeDetachedView(RecyclerView.java:4139)
at androidx.recyclerview.widget.RecyclerView$LayoutManager.removeAndRecycleScrapInt(RecyclerView.java:8978)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep3(RecyclerView.java:3997)
at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3652)
at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4194)
at android.view.View.layout(View.java:20672)
...
以下是控制RecyclerView
public class MoleFragment extends Fragment {
RecyclerView moleRecycler = null;
TextView addBtn = null;
Cursor moleCursor = null;
static int moleAdapterPosition = 0;
static String moleId = "";
static String contactId = "";
static String rawContactId = "";
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.moles_layout, container, false);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final Cursor moleCursor = readMoles();
moleRecycler = (RecyclerView) getActivity().findViewById(R.id.moles);
moleRecycler.setHasFixedSize(true);
moleRecycler.setLayoutManager(new LinearLayoutManager(getActivity()));
moleRecycler.setAdapter(new MolesCursorAdapter(getActivity(), moleCursor));
OnItemActivatedListener<Long> moleItemActivatedListener = new OnItemActivatedListener() {
@Override
public boolean onItemActivated(@NonNull ItemDetailsLookup.ItemDetails item, @NonNull MotionEvent e) {
moleAdapterPosition = item.getPosition();
moleCursor.moveToPosition(item.getPosition());
moleId = Long.toString(moleCursor.getLong(0));
return true;
}
};
SelectionTracker moleTracker = new SelectionTracker.Builder<Long>("selectedMoleId",
moleRecycler,
new StableIdKeyProvider(moleRecycler),
new MoleDetailsLookup(),
StorageStrategy.createLongStorage())
.withSelectionPredicate(SelectionPredicates.<Long>createSelectSingleAnything())
.withOnItemActivatedListener(moleItemActivatedListener)
.build();
return ;
}
public Cursor readMoles() {
String[] contactIds = getShownCustomer();
String selection = Data.RAW_CONTACT_ID + "=? AND " + Data.CONTACT_ID + "=? AND " + Data.MIMETYPE + "=?";
String[] selectionArgs = new String[]{contactIds[0], contactIds[1], MOLE_MIME_TYPE};
return moleCursor = getActivity().getContentResolver().query(
Data.CONTENT_URI,
new String[] {
Data._ID,
Data.DATA1,
Data.DATA2,
Data.DATA3,
Data.DATA4},
selection,
selectionArgs,
null
);
}
/**
* Create a new instance of DetailsFragment, initialized to
* show the catches for customer 'contactId'.
*/
public static MoleFragment newInstance(String rawContactId, String contactId) {
MoleFragment f = new MoleFragment();
// Supply index input as an argument.
Bundle args = new Bundle();
args.putString("rawContactId", rawContactId);
args.putString("contactId", contactId);
f.setArguments(args);
return f;
}
public String[] getShownCustomer() {
rawContactId = getArguments().getString("rawContactId", "");
contactId = getArguments().getString("contactId", "");
String[] contactIds = new String[2];
contactIds[0] = getArguments().getString("rawContactId", "");
contactIds[1] = getArguments().getString("contactId", "");
return contactIds;
}
private class MoleDetailsLookup extends ItemDetailsLookup<Long> {
@Nullable
@Override
public ItemDetails<Long> getItemDetails(@NonNull MotionEvent event) {
View view = moleRecycler.findChildViewUnder(event.getX(), event.getY());
if (view != null) {
final RecyclerView.ViewHolder viewHolder = moleRecycler.getChildViewHolder(view);
if (viewHolder instanceof MolesCursorAdapter.ViewHolder) {
final MolesCursorAdapter.ViewHolder moleViewHolder = (MolesCursorAdapter.ViewHolder) viewHolder;
return new ItemDetailsLookup.ItemDetails<Long>() {
@Override
public int getPosition() {
return viewHolder.getAdapterPosition();
}
@Nullable
@Override
public Long getSelectionKey() {
return Long.valueOf(moleViewHolder.position);
}
};
}
}
return null;
}
}
}
这是RecyclerView.Adapater
public class MolesCursorAdapter extends RecyclerView.Adapter<MolesCursorAdapter.ViewHolder> {
private CursorAdapter mCursorAdapter;
private Context mContext;
private ViewHolder holder;
public MolesCursorAdapter(Context context, Cursor c) {
mContext = context;
mCursorAdapter = new CursorAdapter(mContext, c, 0) {
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View v = LayoutInflater.from(context).inflate(R.layout.moles, parent, false);
return v;
}
@Override
public void bindView(View view, final Context context, final Cursor cursor) {
String s = cursor.getString(1);
if (s != null) {
holder.startDate.setText(s.substring(6, 8) + "/" + s.substring(4, 6) + "/" + s.substring(0, 4));
} else {
holder.startDate.setText("");
}
s = cursor.getString(2);
if (s != null) {
s = s.substring(6,8) + "/" + s.substring(4,6) + "/" + s.substring(0,4);
holder.endDate.setText(s);
} else {
holder.endDate.setText("");
}
holder.round.setText(cursor.getString(3));
holder.moleType.setText(cursor.getString(4));
}
};
}
public class ViewHolder extends RecyclerView.ViewHolder implements TextWatcher {
public int position;
public EditText startDate;
public EditText endDate;
public EditText round;
public EditText moleType;
public TextView deleteBtn;
public ViewHolder(View itemView) {
super(itemView);
startDate = (EditText) itemView.findViewById(R.id.startDate);
endDate = (EditText) itemView.findViewById(R.id.endDate);
round = (EditText) itemView.findViewById(R.id.round);
moleType = (EditText) itemView.findViewById(R.id.moleType);
deleteBtn = (TextView) itemView.findViewById(R.id.deleteBtn);
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
String value = s.toString();
ContentValues newValues = new ContentValues();
if (TextUtils.isDigitsOnly(s)) {
newValues.put(ContactsContract.Data.DATA3, value);
} else {
newValues.put(ContactsContract.Data.DATA4, value);
}
updateRepository(newValues);
}
}
@Override
public int getItemCount() {
return mCursorAdapter.getCount();
}
@Override
public long getItemId(int position) {
return Long.valueOf(position);
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
// Passing the binding operation to cursor loader
mCursorAdapter.getCursor().moveToPosition(position);
mCursorAdapter.bindView(holder.itemView, mContext, mCursorAdapter.getCursor());
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
TextWatcher tw = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
String value = s.toString();
ContentValues newValues = new ContentValues();
if (TextUtils.isDigitsOnly(s)) {
newValues.put(ContactsContract.Data.DATA3, value);
} else {
newValues.put(ContactsContract.Data.DATA4, value);
}
updateRepository(newValues);
}
};
View v = mCursorAdapter.newView(mContext, mCursorAdapter.getCursor(), parent);
holder = new ViewHolder(v);
holder.startDate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
// business logic
}
});
holder.endDate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
// business logic
}
});
holder.round.addTextChangedListener(tw);
holder.moleType.addTextChangedListener(tw);
holder.deleteBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String selectionClause = ContactsContract.Data._ID + "=?";
String[] selectionArgs = new String[] {mCursorAdapter.getCursor().getString(0)};
int rowsDeleted = mContext.getContentResolver().delete(
ContactsContract.Data.CONTENT_URI,
selectionClause,
selectionArgs
);
}
});
return holder;
}
}
答案 0 :(得分:0)
我没有通过onCreateViewHolder
方法在ViewHolder中的每个视图上添加ClickListener,而是在每个View上添加了唯一标记。此唯一标记用于一般的(在类级别)ClickListener中执行业务逻辑:
public class MolesCursorAdapter3 extends RecyclerView.Adapter<MolesCursorAdapter3.MolesViewHolder> {
private CursorAdapter mCursorAdapter;
private Context mContext;
public ConstraintLayout holder;
public EditText startDate;
public EditText endDate;
public EditText round;
public EditText moleType;
public TextView deleteBtn;
public class MolesViewHolder extends RecyclerView.ViewHolder implements TextWatcher, View.OnClickListener {
public int position;
public String vhMoledId = "";
public MolesViewHolder(ConstraintLayout itemView) {
super(itemView);
holder = itemView;
startDate = (EditText) itemView.findViewById(R.id.startDate);
startDate.setOnClickListener(this);
endDate = (EditText) itemView.findViewById(R.id.endDate);
endDate.setOnClickListener(this);
round = (EditText) itemView.findViewById(R.id.round);
round.addTextChangedListener(this);
moleType = (EditText) itemView.findViewById(R.id.moleType);
moleType.addTextChangedListener(this);
deleteBtn = (TextView) itemView.findViewById(R.id.deleteBtn);
deleteBtn.setOnClickListener(this);
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
String value = s.toString();
ContentValues newValues = new ContentValues();
if (TextUtils.isDigitsOnly(s)) {
newValues.put(ContactsContract.Data.DATA3, value);
} else {
newValues.put(ContactsContract.Data.DATA4, value);
}
updateRepository(newValues, vhMoledId);
}
@Override
public void onClick(final View v) {
String tag = (String) v.getTag();
String viewTag = tag.substring(0, 3);
final String moleId = tag.substring(3);
switch (viewTag) {
case "del":
// business logic
break;
case "sta":
ConstraintLayout vh = (ConstraintLayout) v.getParent();
endDate = vh.findViewWithTag("end" + moleId);
// business logic
break;
case "end":
vh = (ConstraintLayout) v.getParent();
startDate = vh.findViewWithTag("sta" + moleId);
// business logic
break;
}
}
}
public MolesCursorAdapter3(Context context, Cursor c) {
mContext = context;
mCursorAdapter = new CursorAdapter(mContext, c, 0) {
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View v = LayoutInflater.from(context).inflate(R.layout.moles, parent, false);
return v;
}
@Override
public void bindView(View itemView, final Context context, final Cursor cursor) {
ConstraintLayout vh = (ConstraintLayout) itemView;
String moleId = cursor.getString(0);
startDate = (EditText) vh.findViewById(R.id.startDate);
startDate.setTag("sta" + moleId);
endDate = (EditText) vh.findViewById(R.id.endDate);
endDate.setTag("end" + moleId);
round = (EditText) vh.findViewById(R.id.round);
moleType = (EditText) vh.findViewById(R.id.moleType);
deleteBtn = (TextView) vh.findViewById(R.id.deleteBtn);
deleteBtn.setTag("del" + moleId);
String s = cursor.getString(1);
if (s != null) {
startDate.setText(s.substring(6, 8) + "/" + s.substring(4, 6) + "/" + s.substring(0, 4));
} else {
startDate.setText("");
}
s = cursor.getString(2);
if (s != null) {
s = s.substring(6,8) + "/" + s.substring(4,6) + "/" + s.substring(0,4);
endDate.setText(s);
} else {
endDate.setText("");
}
round.setText(cursor.getString(3));
moleType.setText(cursor.getString(4));
}
};
}
@Override
public MolesCursorAdapter3.MolesViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
ConstraintLayout molesLayout = (ConstraintLayout) LayoutInflater.from(parent.getContext()).inflate(R.layout.moles, parent, false);
MolesViewHolder vh = new MolesViewHolder(molesLayout);
return vh;
}
@Override
public void onBindViewHolder(@NonNull MolesViewHolder holder, int position) {
// Passing the binding operation to cursor loader
mCursorAdapter.getCursor().moveToPosition(position);
mCursorAdapter.bindView(holder.itemView, mContext, mCursorAdapter.getCursor());
holder.vhMoledId = mCursorAdapter.getCursor().getString(0);
holder.position = position;
}
@Override
public int getItemCount() {
return mCursorAdapter.getCount();
}
@Override
public long getItemId(int position) {
return Long.valueOf(position);
}
public void updateRepository(ContentValues newValues, String moleId) {
final String selection = ContactsContract.Data.MIMETYPE + " = ? AND " + ContactsContract.Data._ID + " = ?";
final String[] selectionArgs = new String[]{MOLE_MIME_TYPE, moleId};
int rowsUpdated = mContext.getContentResolver().update(
ContactsContract.Data.CONTENT_URI,
newValues,
selection,
selectionArgs
);
}
}