附加到上一个片段的 RecyclerView 适配器

RecyclerView Adapter Attached to Previous Fragment

我有一个 Activity 有一个 Fragment 和一个 RecyclerView。单击其中一个 RecyclerView 项目时,将在原始项目之上添加一个新的 Fragment 并添加到返回堆栈中。这个新 Fragment 与之前的 Fragment 具有相同的 layout,并使用相同 Adapter 的不同实例。当按下后退按钮时出现问题,从堆栈中弹出第二个 Fragment,并且再次单击第一个 Fragment 中的一个项目,应用程序崩溃并显示 NullPointerException

12-22 08:50:53.283 20747-20747/com.example.app E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.app, PID: 20747
    java.lang.NullPointerException: Attempt to invoke virtual method 'void com.example.app.ui.activity.MainActivity.revealFragment(android.support.v4.app.Fragment)' on a null object reference
        at com.example.app.ui.fragment.CampusFragment.onItemClickListener(SecondFragment.java:115)
        at com.example.app.ui.adapter.LauncherAdapter$ViewHolder.onClick(LauncherAdapter.java:68)
        at android.view.View.performClick(View.java:4780)
        at android.view.View$PerformClick.run(View.java:19866)
        at android.os.Handler.handleCallback(Handler.java:739)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:135)
        at android.app.ActivityThread.main(ActivityThread.java:5254)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)

但是调用了第二个FragmentonItemClickListener,而不是第一个。第二个 Fragment 不再附加,因此 onItemClickListener 中的 getActivity() 生成 NullPointerException,但第二个 Fragment 根本不应该被调用。 Fragment 类 都有一个 RecyclerView 的设置方式相同:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_main, container, false);

    mAdapter = new LauncherAdapter(getContext(), mDataSet);
    mAdapter.setOnItemClickListener(this);
    GridLayoutManager layoutManager = new GridLayoutManager(getContext(), 2);
    ItemTouchHelper touchHelper = new ItemTouchHelper(onItemTouch());

    RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.recycler);
    recyclerView.setLayoutManager(layoutManager);
    recyclerView.setAdapter(mAdapter);
    touchHelper.attachToRecyclerView(recyclerView);

    return view;
}

为每个创建一个新的LauncherAdapter

public class LauncherAdapter extends RecyclerView.Adapter<LauncherAdapter.ViewHolder> implements ItemTouchHelperAdapter {

    public interface OnItemClickListener {
        void onItemClickListener(@StringRes int title);
    }

    private static OnItemClickListener sListener;

    private Context mContext;

    private List<LauncherCard> mDataset;

    public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        private int mId;

        public ImageView iconView;
        public TextView titleView;

        public ViewHolder(View itemView) {
            super(itemView);

            iconView = (ImageView) itemView.findViewById(R.id.icon);
            titleView = (TextView) itemView.findViewById(R.id.title);

            itemView.setOnClickListener(this);
        }

        public void setId(@StringRes int id) {
            mId = id;
        }

        @Override
        public void onClick(View view) {
            sListener.onItemClickListener(mId);
        }
    }

    public LauncherAdapter(Context context, List<LauncherCard> dataset) {
        mContext = context;
        mDataset = dataset;
    }

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

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        holder.iconView.setImageResource(mDataset.get(position).getDrawable());
        holder.titleView.setText(mDataset.get(position).getId());
        holder.setId(mDataset.get(position).getId());
    }

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

    @Override
    public void onItemMove(int fromPosition, int toPosition, String saveLocation) {
        if (fromPosition < toPosition) {
            Collections.rotate(mDataset.subList(fromPosition, toPosition + 1), -1);
        } else {
            Collections.rotate(mDataset.subList(toPosition, fromPosition + 1), + 1);
        } notifyItemMoved(fromPosition, toPosition);

        SharedPreferences.Editor editor = mContext.getSharedPreferences("recycler_positions", Context.MODE_PRIVATE).edit();
        editor.putString(saveLocation, new Gson().toJson(mDataset)).apply();
    }

    @Override
    public void onItemDismiss(int position) {
        // Not utilized
    }

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

为什么要调用第二个 FragmentonItemClickListener 而不是第一个?第二个 FragmentLauncherAdapter 是否也以某种方式附加到第一个 FragmentRecyclerView?不能在一个 Context 中包含两个相同 Adapter 的实例吗?

不要将您的侦听器声明为静态的。变化

private static OnItemClickListener sListener;

private OnItemClickListener mListener;

你做静态的可能是为了可以从你的 ViewHolder 访问。为了克服它,将它传递给两个构造函数,AdapterViewHolder

public LauncherAdapter(Context context, List<LauncherCard> dataset,  OnItemClickListener listener) {
    mContext = context;
    mDataset = dataset;
    mListener = listener;
}

public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
    private int mId;

    public ImageView iconView;
    public TextView titleView;
    private OnItemClickListener mListener;
    public ViewHolder(View itemView, OnItemClickListener listener) {
        super(itemView)
        mListener = listener; 
    }

并在 onClick

中使用 mListener