How to Pass or Send Data from Recyclerview Adapter to Fragment

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

Passing data from RecyclerView to Fragment?

Its for your fragment

YourFragment : Fragment() {
OnItemClickListener listener = new OnItemClickListener(){
@Override
public void onItemClick(View view, int position){
//this called if item at adapter clicked
}
}

....
//whatever lifecycle you choose for initialize adapter
onCreateView(){
adapter = new YourAdapter(listener);
}

public interface OnItemClickListener{
public void onItemClick(View view, int position);
}

}

and this for your adapter

private OnItemClickListener listener; 

YourConstructorAdapter(OnItemClickListener listener){
this.listener = listener;
}

@Override
public void onBindViewHolder(@NonNull final MyViewHolder holder, int position) {
holder.text1.setText(String.valueOf(text1.get(position)));
holder.text2.setText(String.valueOf(text2.get(position)));
holder.text3.setText(String.valueOf(text3.get(position)));

holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// this code calling method from fragment
listener.onItemClick(v, position);
}
});

I'm highly recommend migrate to kotlin and use higher-order function, its very simple.

How to pass data from Recyclerview to Fragment

thank you guys for the answer,I solved the problem using an interface with String values to connect the adapter with the fragment that contains the recyclerview and the other fragment here is what I did exactly :
this is the interface

public interface FragmentCommunication {
void respond(int position,String name,String job);
}

and this is the adapter

public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.MyViewHolder> {
private LayoutInflater inflater;
private List<Information> mList;
private FragmentCommunication mCommunicator;

public RecyclerAdapter(Context context, List<Information> list,FragmentCommunication communication) {
inflater = LayoutInflater.from(context);
mList = list;
mCommunicator=communication;
}

@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.single_row, parent, false);
MyViewHolder holder = new MyViewHolder(view,mCommunicator);
return holder;
}

@Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {

final Information current = mList.get(position);
holder.name.setText(current.name);
holder.job.setText(current.job);

FragmentB fragmentB=new FragmentB();
Bundle bundle=new Bundle();
bundle.putString("NAME",current.name);
bundle.putString("JOB",current.job);
fragmentB.setArguments(bundle);

}

@Override
public int getItemCount() {
return mList.size();
}

public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView name;
TextView job;
FragmentCommunication mComminication;

public MyViewHolder(View itemView, FragmentCommunication Communicator) {
super(itemView);
name = (TextView) itemView.findViewById(R.id.tv_name);
job = (TextView) itemView.findViewById(R.id.tv_gob);
mComminication=Communicator;
name.setOnClickListener(this);
}

@Override
public void onClick(View view) {
mComminication.respond(getAdapterPosition(),mList.get(getAdapterPosition()).name,mList.get(getAdapterPosition()).job);
}
}
}

the fragment that contains the recyclerview

public class RecyclerViewFragment extends Fragment {
RecyclerView mRecyclerView;
RecyclerAdapter mRecyclerAdapter;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view= inflater.inflate(R.layout.recycler_fragment,container,false);

mRecyclerView= (RecyclerView) view.findViewById(R.id.recycler);
mRecyclerAdapter=new RecyclerAdapter(getActivity(),getData(),communication);
mRecyclerView.setAdapter(mRecyclerAdapter);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));

return view;
}

public static List<Information> getData() {
List<Information>data=new ArrayList<>();
String[] names={"ahmed","mohammed"};
String[] jobs={"sacsd","csscs"};

for (int i=0;i<names.length;i++){
Information current=new Information();
current.name=(names[i]);
current.job=(jobs[i]);
data.add(current);
}
return data;
}

FragmentCommunication communication=new FragmentCommunication() {
@Override
public void respond(int position,String name,String job) {
FragmentB fragmentB=new FragmentB();
Bundle bundle=new Bundle();
bundle.putString("NAME",name);
bundle.putString("JOB",job);
fragmentB.setArguments(bundle);
FragmentManager manager=getFragmentManager();
FragmentTransaction transaction=manager.beginTransaction();
transaction.replace(R.id.dumper,fragmentB).commit();
}

};

}

this is the fragmentB where I get the Strings from the Adapter

public class FragmentB extends Fragment {
TextView textview;
TextView textview2;
String name;
String job;

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
name=getArguments().getString("NAME");
job=getArguments().getString("JOB");

}

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view= inflater.inflate(R.layout.fragment_b,container,false);

textview= (TextView) view.findViewById(R.id.getName);
textview2= (TextView) view.findViewById(R.id.getJob);
textview.setText(name);
textview2.setText(job);


return view;

}


}

Pass the data from Recyclerview adapter to Fragment

You're passing 4 parameters from the fragment but your constructor is expecting 3. So you need to add Context as your first parameter in the adapter.

UPDATE:

You are passing this instance inside an anonymous class which is OnClickListener which does not implement the interface. So instead of this, pass ReceiveFragment.this, this way you are referencing your fragment which implements the interface:

recyclerViewAdapter = new ReceiverRecyclerViewAdapter(getActivity(),subjects, emails, ReceiveFragment.this);

how to pass data from adapter to fragments in kotlin via bundle?

Your code for the Adapter is alright, it seems. Firstly, whenever you have a lambda parameter, it must be set to the last of the list.

class ProductAdapter(
private val items: List<ProductResultData
private val onItemClick: (ProductResultData) -> Unit
)

// In your activity/fragment
binding.recyclerView.adapter = ProductAdapter(list) { item ->
Bundle().apply {
putParcelable("PRODUCT_ITEM", item)
}.also {
val yourFrag = YourFragment()
yourFrag.args = it
replaceFragment(yourFrag)
}
}

And make sure your ProductResultData implements Parcelable interface.

How can I pass data from a recycler view button to fragment? [ kotlin or java]

With kotlin, you can use High Order function to call callback instead of creating interface like java.

Create a high order function in the Adapter's constructor. Then when you set click then you invoke and get that invoked data in view. As follows:

// You should change the class name to uppercase. Like `TvTitleAdapter`
class tvTitleAdapter (
val context: Context,
val TITLE_LIST : ArrayList<TvTitlesViewModel>,
private val onClick: ((tvTitleName: String) -> Unit)? = null // Pass the param you want. Here I try to pass String with name tvTitleName.
) : RecyclerView.Adapter<tvTitleAdapter.ViewHolder>() {

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
...
holder.tvTitleButton.setOnClickListener {
when(position){
0 -> {
onClick?.invoke(`your title`) // Pass your title in invoke.
}
else -> return@setOnClickListener
}
}
}
}

In the initialization of TvTitleAdapter, you declare the onClick param. It will listen to the callback when you call invoke().

class TvTitlesFragment : Fragment() {

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
...
val adapter = tvTitleAdapter(
requireContext(),
TV_TITLE,
onClick = { tvTitleName ->
// This code opens the `Second Fragment` with `tvTitleName` passed by the `newInstance()` function.
requireActivity().supportFragmentManager
.beginTransaction()
.replace(R.id.your_fragment_container, SecondFragment.newInstance(tvTitleName))
.commit()
}
)
}
}
class SecondFragment : Fragment() {

...
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
...
// Get data from `TvTitlesFragment`
val tvTitleName = argument?.getString(KEY_TV_TITLE_NAME)

// Set data to your title
binding.tvTitle.text = tvTitleName
}

companion object {
private const val KEY_TV_TITLE_NAME = "KEY_TV_TITLE_NAME"

// Create `SecondFragment` with bundle so you can send data from certain fragment to `SecondFragment`.
fun newInstance(tvTitleName: String) : SecondFragment = SecondFragment().apply {
val bundle = bundleOf(KEY_TV_TITLE_NAME to tvTitleName)
arguments = bundle
}
}
}

How to send data from a adapter class to a fragment?



Related Topics



Leave a reply



Submit