附加到上一个片段的 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)
但是调用了第二个Fragment
的onItemClickListener
,而不是第一个。第二个 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;
}
}
为什么要调用第二个 Fragment
的 onItemClickListener
而不是第一个?第二个 Fragment
的 LauncherAdapter
是否也以某种方式附加到第一个 Fragment
的 RecyclerView
?不能在一个 Context
中包含两个相同 Adapter
的实例吗?
不要将您的侦听器声明为静态的。变化
private static OnItemClickListener sListener;
到
private OnItemClickListener mListener;
你做静态的可能是为了可以从你的 ViewHolder
访问。为了克服它,将它传递给两个构造函数,Adapter
和 ViewHolder
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
我有一个 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)
但是调用了第二个Fragment
的onItemClickListener
,而不是第一个。第二个 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;
}
}
为什么要调用第二个 Fragment
的 onItemClickListener
而不是第一个?第二个 Fragment
的 LauncherAdapter
是否也以某种方式附加到第一个 Fragment
的 RecyclerView
?不能在一个 Context
中包含两个相同 Adapter
的实例吗?
不要将您的侦听器声明为静态的。变化
private static OnItemClickListener sListener;
到
private OnItemClickListener mListener;
你做静态的可能是为了可以从你的 ViewHolder
访问。为了克服它,将它传递给两个构造函数,Adapter
和 ViewHolder
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