How to create interface between Fragment and adapter?

JavaAndroidInterface

Java Problem Overview


I have fragment with ListView, say MyListFragment, and custom CursorAdapter. I'm setting onClickListener in this adapter for the button in the list row.

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.

Java Solutions


Solution 1 - Java

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. For example

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

since this will refer to your Fragment, which is now an 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.

Solution 2 - Java

Using Eventbus:

Examples:

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

or

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.

Create Callback Interface:

public interface AdapterCallback {
    void onMethodCallback();
}

Passing in Callback/Fragment:

This will implement the interface that we have in our Adapter. In this example, it will be called when the user clicks on an item in the RecyclerView.

In your 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:

In the Fragment, we initiated our Adapter and passed this as an argument to the constructer. This will initiate our interface for our callback method. 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:

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

Solution 3 - Java

Follow the 2 steps below for receive callback from Adapter in Fragment (or Activity)

First: In your 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

Way 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

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

Solution 4 - Java

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.

Solution 5 - Java

a solution for NPE is first to make conctractor in your Fragment like that

public MyFragment MyFragment(){
        return this;
    }

then initialize your listener is adapter like that

Lisener lisener = new MyFragment();

Solution 6 - Java

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,

class MyFragment extends Fragment implements AlertMessageBoxOk {

@Override
public void onOkClick(int resultCode) {

  if(resultCode==5){

  enter code here 

      }
    } 
 }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSabreView Question on Stackoverflow
Solution 1 - JavaA--CView Answer on Stackoverflow
Solution 2 - JavaJared BurrowsView Answer on Stackoverflow
Solution 3 - JavaLinhView Answer on Stackoverflow
Solution 4 - JavaQuanturiumView Answer on Stackoverflow
Solution 5 - Javamohamed morsiView Answer on Stackoverflow
Solution 6 - JavaSaurabh GaddelpalliwarView Answer on Stackoverflow