How to Create Interface Between Fragment and Adapter

How to create interface between Fragment and adapter?

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.

How to create an interface between a fragment and an adapter

In place where you declare adapter or in the constructor of adapter, initiate the listener.

In the fragment side,

class Test extends Fragment {
AdapterClass adapter = new AdapterClass();
adapter.setListner(..)
view.setAdapter(adapter);


@Override
public void onCartRowClicked(View view, DownloadProgressView downloadProgressView, int position) {

}
}

In Adapter class

class AdapterClass {

private AgroInfoAdapterListener listner;

public setListner(AgroInfoAdapterListener listner) {
this.listner = listner;
}


public interface AgroInfoAdapterListener {

void onCartRowClicked(View view, DownloadProgressView downloadProgressView, int position);

}

private void applyClickEvents(final AgroInfoAdapter.ViewHolder holder, final int position) {
holder.button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {

}
});
}

}

How to communicate with fragment from my adapter class

Update
If you are looking for a solution in Kotlin

class ExampleFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val adapter = MyAdapter(){
Log.d("zzzz", "$it ")
}
}
}


class MyAdapter (val onClick : (value: String) -> Unit): RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
holder.itemView.setOnClickListener {
onClick("something")
}
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
TODO("Not yet implemented")
}

override fun getItemCount(): Int {
TODO("Not yet implemented")
}
}

JAVA
The following code may help you.

    public class ExampleFragment extends Fragment implements MyAdapter.SuccessResponse{

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View contentView = inflater.inflate(R.layout.my_layout, container, false);
MyAdapter myAdapter = new MyAdapter(getActivity(), 0);
myAdapter.successResponse = this;
return contentView;
}

@Override
public void onSuccess() {

}
}


class MyAdapter extends ArrayAdapter{
SuccessResponse successResponse;

public MyAdapter(Context context, int resource) {
super(context, resource);
}

public interface SuccessResponse{
void onSuccess();
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
//ur views
linearLayout.setOnClickListener(new View.OnClickListener{
@Override
public void onClick (View view){
if(successResponse!=null)
successResponse.onSuccess();
}
})
}
}

Android communication between fragment and baseadapter

Create an interface from your adapter to your fragment.

In your adapter create the interface and pass it in your adapter's constructor

class MyAdapter extends BaseAdapter {

public interface IProcessFilter {
void onProcessFilter(String string1, String string2)
}

private IProcessFilter mCallback;

public MyAdapter(Context context, String string1, String string2, IProcessFilter callback) {
mCallback = callback;
}

public View getView( final int position, View convertView, ViewGroup parent)
{
holder.checkBox.setOnClickListener( new View.OnClickListener() {
public void onClick(View v) {
mCallback.onProcessFilter("string1", "string2");
}
}
}
}

Last thing, implement it in your fragment like this

public class MyFragment extends Fragment implements IProcessFilter {
...
...
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

View view = inflater.inflate(R.layout.my_fragment_layout, container, false);
no_of_filter = (TextView) view.findViewById(R.id.no_of_filter_tv);

MyAdapter custom_adapter = new MyAdapter(context, "string 1", "string 2", this);
}

@Override
public void onProcessFilter(String string1, String string2) {
// Process the filter
}
}

How to pass data from adapter to fragment?

If you want to use an interface, you just need to define one with a function to receive your data, make the fragment implement it, then pass the fragment to the adapter as an implementation of that interface:

data class UserData(val email: String, val phone: String)

class UserAdapter(
private val userList: ArrayList<UserModel>,
val context: Context,
val handler: UserAdapter.Callbacks // added this here, so you're passing it in at construction
) : RecyclerView.Adapter<UserAdapter.UserViewHolder>() {

...

private fun doWhatever(email: String, phone: String) {
// pass the data to the handler (which will probably be your Fragment)
handler.handleUserData(UserData(email, phone))
}

// nested inside the UserAdapter class to keep things tidy
interface Callbacks {
fun handleUserData(data: UserData)
}
}

Then in the Fragment:

// add the Callbacks interface type
class TutorChatFragment : Fragment(), UserAdapter.Callbacks {
override fun onCreateView(
inflater: LayoutInflater,
@Nullable container: ViewGroup?,
@Nullable savedInstanceState: Bundle?
): View {
...
userRecyclerView.layoutManager = LinearLayoutManager(context)

// set up the adapter here, passing this fragment as the Callbacks handler
userRecyclerView.adapter = UserAdapter(userArrayList, context, this)
...
}

// interface implementation
override fun handleUserData(data: UserData) {
// whatever
}
}

And that's it. You're not hardcoding a dependency on that particular Fragment type, just the interface, and this fragment implements it so it can pass itself.


A more Kotliny way to do it is to ignore interfaces and just pass a function instead

class UserAdapter(
private val userList: ArrayList<UserModel>,
val context: Context,
val handler: (UserData) -> Unit // passing a function that takes a UserData instead
) : RecyclerView.Adapter<UserAdapter.UserViewHolder>() {

...

private fun doWhatever(email: String, phone: String) {
// call the handler function with your data (you can write handler.invoke() if you prefer)
handler(UserData(email, phone))
}
}
// no interface this time
class TutorChatFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
@Nullable container: ViewGroup?,
@Nullable savedInstanceState: Bundle?
): View {
...
userRecyclerView.layoutManager = LinearLayoutManager(context)

// pass in a handler function
userRecyclerView.adapter = UserAdapter(userArrayList, context) { userData ->
handleUserData(userData)
}
// or if you're just passing it to that function down there,
// you could do UserAdapter(userArrayList, context, ::handleUserData)
// and pass the function reference
...
}

// might be convenient to still do this in its own function
private fun handleUserData(data: UserData) {
// whatever
}
}

Ideally you should be doing what I've done there - create the adapter once during setup, and have a function on it that allows you to update it. Your code creates a new one each time you get data. You do this the same way in both though

Your other option is using a view model that the adapter and fragment both have access to, but this is how you do the interface/callback approach



Related Topics



Leave a reply



Submit