简体   繁体   English

如何在 Fragment 和适配器之间创建接口?

[英]How to create interface between Fragment and adapter?

I have fragment with ListView , say MyListFragment , and custom CursorAdapter .我有ListView片段,比如MyListFragment和自定义CursorAdapter I'm setting onClickListener in this adapter for the button in the list row.我在此适配器中为列表行中的按钮设置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
    }
}

I need to notify fragment when the button is pressed.按下按钮时我需要通知片段。 How to invoke this interface?如何调用这个接口?

Help, please.请帮忙。

Make a new constructor and an instance variable: 创建一个新的构造函数和一个实例变量:

AdapterInterface buttonListener;

public MyListAdapter (Context context, Cursor c, int flags, AdapterInterface buttonListener)
{
  super(context,c,flags);
  this.buttonListener = buttonListener;
}

When the Adapter is made, the instance variable will be given the proper reference to hold. 制作适配器后,实例变量将被赋予适当的保持参考。

To call the Fragment from the click: 要从点击中调用片段:

public void onClick(View v) {
   buttonListener.buttonPressed();
}

When making the Adapter , you will have to also pass your Fragment off to the Adapter. 制作Adapter ,您还必须将片段传递给适配器。 For example 例如

MyListAdapter adapter = new MyListAdapter (getActivity(), myCursor, myFlags, this);

since this will refer to your Fragment, which is now an AdapterInterface . 因为this将引用你的Fragment,它现在是一个AdapterInterface

Keep in mind that on orientation of the Fragment changes, it will most likely be recreated. 请记住,在片段方向更改时,很可能会重新创建。 If your Adapter isn't recreated, it can potentially keep a reference to a nonexistent object, causing errors. 如果未重新创建适配器,则可能会保留对不存在的对象的引用,从而导致错误。

Using Eventbus: 使用Eventbus:

Examples: 例子:

https://github.com/kaushikgopal/RxJava-Android-Samples/tree/master/app/src/main/java/com/morihacky/android/rxjava/rxbus https://github.com/kaushikgopal/RxJava-Android-Samples/tree/master/app/src/main/java/com/morihacky/android/rxjava/rxbus

or 要么

https://github.com/greenrobot/EventBus https://github.com/greenrobot/EventBus

Using Interfaces: 使用接口:

I understand the current answer but needed a more clear example. 我理解当前的答案,但需要一个更清晰的例子。 Here is an example of what I used with an Adapter (RecyclerView.Adapter) and a Fragment . 以下是我使用Adapter (RecyclerView.Adapter)和Fragment的示例。

Create Callback Interface: 创建Callback接口:

public interface AdapterCallback {
    void onMethodCallback();
}

Passing in Callback / Fragment : 传入Callback / Fragment

This will implement the interface that we have in our Adapter . 这将实现interface ,我们在我们的Adapter In this example, it will be called when the user clicks on an item in the RecyclerView . 在此示例中,将在用户单击RecyclerView的项目时调用它。

In your Fragment : 在你的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
    }
}

Use the Callback in your Adapter: 使用适配器中的Callback

In the Fragment , we initiated our Adapter and passed this as an argument to the constructer. Fragment ,我们启动了我们的Adapter并将其作为参数传递给constructer。 This will initiate our interface for our callback method. 这将启动我们的回调方法interface You can see that we use our callback method for user clicks. 您可以看到我们使用回调方法进行用户点击。

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();
            }
        });
    }
}

or Use the Fragment in your Adapter: 或使用适配器中的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
                }
            }
        });
    }
}

Follow the 2 steps below for receive callback from Adapter in Fragment (or Activity) 按照以下2个步骤接收来自Fragment (or Activity) Adapter回调

First: In your Adapter 第一: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);
            }
        });
        ...
    }
    ...
}

Second: In your Fragment (or Activity) , there are 2 ways for implement callback method 第二:Fragment (or Activity) ,有两种实现回调方法的方法

Way 1 方式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();
             }
         });
         ...
     }
 }

Way 2 方式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();     
    }          
}

This is very similar to the way an activity and a fragment should communicate. 这与活动和片段的通信方式非常相似。 In the constructor of your adapter, pass a reference of your fragment, cast it to your interface and just call yourReference.buttonPressed() on your onClick method. 在适配器的构造函数中,传递片段的引用,将其强制转换为接口,然后在onClick方法上调用yourReference.buttonPressed()。

a solution for NPE is first to make conctractor in your Fragment like that NPE的解决方案是首先在你的Fragment中制作这样的conctractor

public MyFragment MyFragment(){
        return this;
    }

then initialize your listener is adapter like that 然后初始化你的监听器是这样的适配器

Lisener lisener = new MyFragment();

Make a constructor like that: 做一个这样的构造函数:

  public MyAdapter(Activity activity,AlertMessageBoxOk alertMessageBoxOk) {

  this.mActivity = activity;

  mAlertMessageBoxOk = alertMessageBoxOk;

}

call the interface from adapter use any event 从适配器调用接口使用任何事件

mAlertMessageBoxOk.onOkClick(5);

after that implement AlertMessageBoxOk interface to your fragment like this, 之后,像你这样实现AlertMessageBoxOk接口到你的片段,

class MyFragment extends Fragment implements AlertMessageBoxOk {

@Override
public void onOkClick(int resultCode) {

  if(resultCode==5){

  enter code here 

      }
    } 
 }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM