如何在 Fragment 和适配器之间创建接口?
Posted
技术标签:
【中文标题】如何在 Fragment 和适配器之间创建接口?【英文标题】:How to create interface between Fragment and adapter? 【发布时间】:2013-03-04 20:58:40 【问题描述】:我有带有ListView
的片段,比如MyListFragment
和自定义CursorAdapter
。
我在此适配器中为列表行中的按钮设置onClickListener
。
public class MyListAdapter extends CursorAdapter
public interface AdapterInterface
public void buttonPressed();
...
@Override
public void bindView(final View view, final Context context, final Cursor cursor)
ViewHolder holder = (ViewHolder) view.getTag();
...
holder.button.setOnClickListener(new OnClickListener()
@Override
public void onClick(View v)
// some action
// need to notify MyListFragment
);
public MyListFragment extends Fragment implements AdapterInterface
@Override
public void buttonPressed()
// some action
我需要在按下按钮时通知片段。如何调用这个接口?
请帮忙。
【问题讨论】:
【参考方案1】:创建一个新的构造函数和一个实例变量:
AdapterInterface buttonListener;
public MyListAdapter (Context context, Cursor c, int flags, AdapterInterface buttonListener)
super(context,c,flags);
this.buttonListener = buttonListener;
当适配器被制作时,实例变量将被赋予正确的引用来保持。
从点击调用片段:
public void onClick(View v)
buttonListener.buttonPressed();
在制作Adapter
时,您还必须将片段传递给适配器。例如
MyListAdapter adapter = new MyListAdapter (getActivity(), myCursor, myFlags, this);
因为this
将引用您的片段,现在是AdapterInterface
。
请记住,在 Fragment 的方向发生变化时,它很可能会被重新创建。如果您的适配器未重新创建,它可能会保留对不存在对象的引用,从而导致错误。
【讨论】:
第一部分的代码应该放在哪里?适配器接口按钮监听器;我尝试将它粘贴在我的适配器中,但这引发了错误。谢谢 太棒了! +1 用于构造函数中的 AdapterInterface buttonListener。谢谢。【参考方案2】:使用事件总线:
例子:
https://github.com/kaushikgopal/RxJava-android-Samples/tree/master/app/src/main/java/com/morihacky/android/rxjava/rxbus
或
https://github.com/greenrobot/EventBus
使用接口:
我理解当前的答案,但需要一个更清晰的示例。这是我使用 Adapter
(RecyclerView.Adapter) 和 Fragment
的示例。
创建Callback
接口:
public interface AdapterCallback
void onMethodCallback();
传入Callback
/Fragment
:
这将实现我们在Adapter
中的interface
。在这个例子中,当用户点击RecyclerView
中的一个项目时,它会被调用。
在你的Fragment
:
public class MyFragment extends Fragment implements AdapterCallback
private MyAdapter mMyAdapter;
@Override
public void onMethodCallback()
// do something
@Override
public void onCreate(final Bundle savedInstanceState)
super.onCreate(savedInstanceState);
this.mMyAdapter = new MyAdapter(this); // this class implements callback
在您的适配器中使用Callback
:
在Fragment
中,我们启动了Adapter
并将其作为参数传递给构造函数。这将为我们的回调方法启动我们的interface
。你可以看到我们使用我们的回调方法来处理用户点击。
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>
private AdapterCallback mAdapterCallback;
public MyAdapter(AdapterCallback callback)
this.mAdapterCallback = callback;
@Override
public void onBindViewHolder(final MyAdapter.ViewHolder viewHolder, final int i)
// simple example, call interface here
// not complete
viewHolder.itemView.setOnClickListener(new OnClickListener()
@Override
public void onClick(View v)
mAdapterCallback.onMethodCallback();
);
或在您的适配器中使用Fragment
:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>
private AdapterCallback mAdapterCallback;
public MyAdapter(Fragment fragment)
try
this.mAdapterCallback = ((AdapterCallback) fragment);
catch (ClassCastException e)
throw new ClassCastException("Fragment must implement AdapterCallback.");
@Override
public void onBindViewHolder(final MyAdapter.ViewHolder viewHolder, final int i)
// simple example, call interface here
// not complete
viewHolder.itemView.setOnClickListener(new OnClickListener()
@Override
public void onClick(View v)
try
mAdapterCallback.onMethodCallback();
catch (ClassCastException exception)
// do something
);
【讨论】:
我为 FragmentActivity 尝试了以下操作.. 但我得到了 NPE:pastebin.com/wc2ByiFz - 如果我不使用回调并且只记录值一切都很好。 @TheDevMan NPE 在哪里?我在我的应用程序中使用这种接口方法。 是的,请阅读我的示例。你必须在你的片段中implements AdapterCallback
。
@Skizo 谢谢!我认为这是可靠的先到先得哈。我很高兴我的回答有所帮助。
EventBus 需要死掉。【参考方案3】:
按照以下 2 个步骤接收来自 Adapter
的回调到 Fragment (or Activity)
第一:在你的Adapter
public class ListAdapter extends RecyclerView.Adapter < RecyclerListAdapter.ItemViewHolder >
...
private ListAdapterListener mListener;
public interface ListAdapterListener // create an interface
void onClickAtOKButton(int position); // create callback function
public RecyclerListAdapter(Context mContext, ArrayList < Items > listItems, ListAdapterListener mListener) // add the interface to your adapter constructor
...
this.mListener = mListener; // receive mListener from Fragment (or Activity)
...
public void onBindViewHolder(final ItemViewHolder holder, final int position)
holder.btnOK.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
// use callback function in the place you want
mListener.onClickAtOKButton(position);
);
...
...
第二种:在你的Fragment (or Activity)
中,实现回调方法有两种方式
方式 1
public MyListFragment extends Fragment
...
public void onViewCreated(View view, @Nullable Bundle savedInstanceState)
...
ListAdapter adapter = new ListAdapter(getActivity(), listItems, new ListAdapter.ListAdapterListener()
@Override
public void onClickAtOKButton(int position)
Toast.makeText(getActivity(), "click ok button at" + position, Toast.LENGTH_SHORT).show();
);
...
方式 2
public MyListFragment extends Fragment implements ListAdapter.ListAdapterListener
...
public void onViewCreated(View view, @Nullable Bundle savedInstanceState)
ListAdapter adapter = new ListAdapter (getActivity(), listItems, this);
...
@Override
public void onClickAtOKButton(int position)
Toast.makeText(getActivity(), "click ok button at" + position, Toast.LENGTH_SHORT).show();
【讨论】:
在方式 1 中,如果片段被销毁并且 onClickAtOkButton() 从某个线程调用,则使用匿名类实现。内存泄漏的可能性有多大【参考方案4】:这与 Activity 和 Fragment 的通信方式非常相似。在适配器的构造函数中,传递片段的引用,将其转换为接口,然后在 onClick 方法上调用 yourReference.buttonPressed()。
【讨论】:
【参考方案5】:NPE 的解决方案是首先在你的 Fragment 中像这样制作承包商
public MyFragment MyFragment()
return this;
然后初始化你的监听器就是这样的适配器
Lisener lisener = new MyFragment();
【讨论】:
【参考方案6】:制作一个这样的构造函数:
public MyAdapter(Activity activity,AlertMessageBoxOk alertMessageBoxOk)
this.mActivity = activity;
mAlertMessageBoxOk = alertMessageBoxOk;
使用任何事件从适配器调用接口
mAlertMessageBoxOk.onOkClick(5);
之后像这样为您的片段实现 AlertMessageBoxOk 接口,
class MyFragment extends Fragment implements AlertMessageBoxOk
@Override
public void onOkClick(int resultCode)
if(resultCode==5)
enter code here
【讨论】:
以上是关于如何在 Fragment 和适配器之间创建接口?的主要内容,如果未能解决你的问题,请参考以下文章