RecyclerView:回收物品时绑定不正确

时间:2019-06-01 17:17:54

标签: android-recyclerview

我的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;
}

}

1 个答案:

答案 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
    );
}

}