Fragment communication - Fragment to fragment - android

I need help on understanding how the following scenario works and how to achieve the result.
I have a class called ShoppingCart.
It has a method called addItemsToShoppingCartFromPreviousOrder.
Now I have a fragment called PreviousOrderFragment with onCreateView method which is using the RecyclerView. Its a list of previous orders.
I have multiple lists. Now I want to know how to call the addItemsToShoppingCartFromPreviousOrder method from ShoppingCart into my fragment.
so that when the user clicks a list, it will add to the cart.

You need do that:
In you Adapter of RecycleView put:
private ItemListener mListener;
...
public void setmListener(ItemListener mListener) {
this.mListener = mListener;
}
...
public interface ItemListener {
void onItemSelected(Item item);
}
Item = The item selected
them...
In your ViewHolder of Adapter put that:
public class Holder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView tv_id;
public TextView tv_url;
public TextView tv_login;
public Holder (View itemView) {
super(itemView);
tv_id = (TextView) itemView.findViewById(R.id.tv_id);
tv_url = (TextView) itemView.findViewById(R.id.tv_url);
tv_login = (TextView) itemView.findViewById(R.id.tv_login);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if (mListener != null) {
Integer position = Integer.valueOf(getLayoutPosition());
mListener.onUserSelected(mList.get(position));
}
}
}
OBS: That ViewHolder is a InnerClass of Adapter
Them all you need do is:
In your fragment
mRecycleViewAdapter.setmListener(this)
Them make your fragment:
public class MyFragment extends Fragment implements MyRecycleViewAdapter.ItemListener
And override :
#Override
public void onItemSelected(Item item) {
//call addItemsToShoppingCartFromPreviousOrder
}
Here is a example,
see SearchFragment.java and UsersListAdapter.java

1- Create a interface call it for ex. OnItemClicked
Interface OnItemClick{
void onItemClicked(/*pass your selected object*/);
}
2- make the fragment implement this interface
Class PreviousOrderFragment extends Fragment implements OnItemClicked{
void onItemClicked(/*pass your selected object*/){
/** here you have the select object when item clicked from the activity **/
addItemsToShoppingCartFromPreviousOrder();
}
}
3- Take an instance from the fragment in the Activity
Class YOUR_Activity extends Activity {
PreviousOrderFragment fragment = new PreviousOrderFragment ();
/// in the onClick event
public onClick(View v){
fragment.onItemClicked(/**pass the selected object*/);
}
}

see this answer, Already explained all the possible ways to make communication between fragments.
But a good way is to use EventBus when you have complicated communication between Many Activities and Fragments, It's much easy and fast,and a better approach then any of this described in above linked answer.

Related

Option menu in recycler view adapter

I would like to like to ask you how I call a method in activity from adapter recycler view.
In function buildRecyclerView there is set up the adapter:
private void buildRecyclerView() {
offerAdapter = new OfferAdapter();
recyclerView.setAdapter(offerAdapter);
}
In class OfferAdapter.java there is created submenu for each item and with onMenuItemClickListener:
#Override
public void onBindViewHolder(NoteHolder holder, int position) {
PopupMenu popup = new PopupMenu(mCtx, holder.button);
popup.inflate(R.menu.menu);
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
// TODO here I want to call delete item in MyOfferFragment.java
}
The main question: How I can call from *onMenuItemClickListnere* the function in *MyOfferFragment*.
Thank you very much in advance
You can pass a listener object in the constructor which implements by fragment OR activity
/**
* item click interface of adapter
*/
public interface OfferAdapterListener {
void onItemClick(int position)
}
This interface implent by fragment
/**
* On item clicked Implement Method from adapter listener.
*
* #param position
*/
#Override
public void onItemClick(int position) {
// Here you can call that method
}
then you pass this listener in the constructor of the adapter.
private void buildRecyclerView() {
offerAdapter = new OfferAdapter(this);
recyclerView.setAdapter(offerAdapter);
}
In the constructor, you can assign like this
private OfferAdapterListener mOfferAdapterListener;
public OfferAdapter(OfferAdapterListener mOfferAdapterListener) {
this.mOfferAdapterListener = mOfferAdapterListener
}
}
Now you can use this listener by setting click listener on anyViwe like this
holder.button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mOfferAdapterListener.onItemClick(position);
}
});
It returns to call the method of onItemClick which implements this method.
OR
You can pass activity or fragment context in the constructor like above and call it through by it reference like this
((MainActivity) mActivity).methodName(arguments);
Here is mActivity reference context which you pass through in constructor.
You can add the MyOfferFragment to your adapter constructor.
private void buildRecyclerView() {
offerAdapter = new OfferAdapter(this); // Adding fragment to constructor
recyclerView.setAdapter(offerAdapter);
}
In OfferAdapter.java:
private MyOfferFragment mFragment; // field variable
OfferAdapter (MyOfferFragment fragment){
mFragment = fragment;
}
You can then access MyOfferFragment methods via mFragment:
mFragment.deleteItem();
However, I think it is a more conventional way to just move methods related to RecyclerView into the adapter if possible. You can refer to this if you want to delete an item from RecyclerView: Android RecyclerView addition & removal of items

Card View Click on card to move to next activity

I am working on a project in android and i just learn about card view class.
I made a card who generates a toast when user clicks on it.
But i also want my card to call another activity when user clicks on it.
I am posting part of my code below.
btnProceed.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
showToast("Proceed to the next step");
Intent intent = new Intent(MyLocationUsingLocationAPI.this, click_picture.class);
startActivity(intent);
}
});
I have made changes in my code as you said but when i click on proceed button my app crashes.What is wrong with code?
the main idea here is to define your actionClickListener
1. create a custom recycleView Adapter
public class AdapterCustomList extends RecyclerView.Adapter<RecyclerView.ViewHolder>
2. define onItemClickListener interface
public interface OnItemClickListener {
void onItemClick( whateverArgsYouWant );
}
3. make an attribute of the interface and define a setter for it
private OnItemClickListener mOnItemClickListener;
public void setOnItemClickListener(final OnItemClickListener mItemClickListener) {
this.mOnItemClickListener = mItemClickListener;
}
4. append a listener to each item while its created in the adapter class
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
...
OriginalViewHolder vItem = (OriginalViewHolder) holder;
vItem.baseCard.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (mOnItemClickListener != null) {
mOnItemClickListener.onItemClick( whateverArgsYouWant );
}
}
});
}
this method will be called when items of recycle view is created (in case you use card view inside a recycle view)
5. use your onClickListener in the Activity you want
AdapterCustomList mAdapter = new AdapterCustomList (getActivity(), recyclerView,yourListItemsHere));
recyclerView.setAdapter(mAdapter);
// on item list clicked
mAdapter.setOnItemClickListener(new AdapterPostList.OnItemClickListener() {
#Override
public void onItemClick( whateverArgsYouWant ) {
...
statements
...
}
});

Update RecyclerView from Dialog

how to update recyclerview from a dialog which is in another class?
My dialog is as a separate class which is called from mainActivity. When I do changes in database, I would like to update recyclerview, which is on mainActivity.
Dialog:
public class Dialog {
DatabaseExecutor databaseExecutor = new DatabaseExecutor();
private final Activity activity;
private final List<Passenger> passengers;
private final int position;
public Dialog (final Activity activity, final List<Passenger> passengers, final int position){
this.activity = activity;
this.passengers = passengers;
this.position = position;
}
public void showDialog (){
final BottomSheetDialog dialog = new BottomSheetDialog(activity);
dialog.setContentView(R.layout.custom_dialog);
final AppCompatImageView dial, message, info, paid, edit, delete;
final AppCompatTextView name;
name = dialog.findViewById(R.id.dialog_name);
paid = dialog.findViewById(R.id.dialog_paid);
name.setText(passengers.get(position).getName());
if(passengers.get(position).isPaid())
paid.setImageResource(R.drawable.money_paid_72);
else
paid.setImageResource(R.drawable.money_unpaid_72);
paid.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Passenger passenger = passengers.get(position);
if (!passengers.get(position).isPaid()){
passenger.setPaid(true);
passenger.setTumblr(R.drawable.money_paid);
passenger.setUser(R.drawable.user_icon);
paid.setImageResource(R.drawable.money_paid_72);
}
else {
passenger.setPaid(false);
passenger.setTumblr(R.drawable.money_unpaid);
passenger.setUser(R.drawable.user_icon_unpaid);
paid.setImageResource(R.drawable.money_unpaid_72);
}
databaseExecutor.updatePassenger(activity, passenger);
}
});
dialog.show();
}
}
P.s. when this dialog was in mainActivity, I just called populateData method and it worked. But how to refresh it from this Dialog class?
You can use callback with dialog in MainActivity,
public interface DialogCallback {
public void onDialogCallback();
}
Your Dialog constructor should be,
DialogCallback callback;
public Dialog (final Activity activity, final List<Passenger> passengers, final int position, DialogCallback callback){
this.activity = activity;
this.passengers = passengers;
this.position = position;
this.callback = callback;
}
In your Dialog button click use below code,
paid.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Passenger passenger = passengers.get(position);
if (!passengers.get(position).isPaid()){
passenger.setPaid(true);
passenger.setTumblr(R.drawable.money_paid);
passenger.setUser(R.drawable.user_icon);
paid.setImageResource(R.drawable.money_paid_72);
}
else {
passenger.setPaid(false);
passenger.setTumblr(R.drawable.money_unpaid);
passenger.setUser(R.drawable.user_icon_unpaid);
paid.setImageResource(R.drawable.money_unpaid_72);
}
databaseExecutor.updatePassenger(activity, passenger);
callback.onDialogCallback(); // Add this line
}
});
In your MainActivity use below code,
Dialog dialog = new Dialog(this, passengers, position, new DialogCallback() {
#Override
public void onDialogCallback() {
// Update recycler view code here
}
});
dialog.showDialog();
In Dialog :
Have an interface
public interface onDialogFinishCallback
{
void refreshRecyclerView();
}
Now implement the above in your activity.
before dismiss the dialog or after the db change operation call
callback.refreshRecyclerView
A direct solution would be to call method on activity you passed to the dialog. There refresh data of recyclerview and notifyDataSetChanged() or appropriate.
A more general and imo better, architecture-related solution is to use Room or similar db, where you can observe data for changes. Let's say data in the db is changed anywhere. All the places where this data is observed (like with LiveData), data is refreshed. If you also use Paging library, data is refreshed and animated in recyclerview too.
Dialog shouldn't refresh RecyclverView directly. Instead you should pass listener from activity. Activity can refresh recycler if needed with notifyDataSetChanged.
Usually dialog should be 'dumb' ui and you shouldn't give it too much control, especially not over elements that are not shown inside dialog. Such approach will make your dialogs more reusable and easy to maintain.
Write an interface in your dialog
public interface onClickInterface{
public void updateRecyclerView(int position);
}
declare new variable for this interface in your dialog class
private onClickInterface mOnClickInterface;
then call method updateRecyclerView() from dialog class where you want to update recyclerview
mOnClickInterface.updateRecyclerView(position);
then implement your MainActivity for this interface and override this method
#override
public void updateRecyclerView(int position){
//alter your list which you are passing to your adapter
Passenger passenger = passengers.get(position);
passenger.setPaid(true);
rAdapter.notifyDatasetChanged();
}

How to receive callback from Activity class into ListView Adapter class in android?

I have Activity with a custom Listview and button. Now
I want to implement Activity button callback in adapter class.
How its possible in Android ?
Please give me suggestion.
FIRST SOLUTION OWN LISTENER
It should be done by Listeners, create Listener interface in Activity, next implement interface in Adapter class. Set Adapter object as listener of Activity and last thing run Listener methods when You want to do something in Adapter.
class Activity{
private Listener listener;
//your activity listener interface
public interface Listener{
onButtonClick();
}
private void setListener(Listener listener){
this.listener=listener;
}
//example method
private void youMethod(){
YourAdapter adapter=new YourAdapter();//YourAdapter class implements Listener
//here You say that adapter is You listener
setListener(adapter);
//bind button
Button button = (Button)findViewById(R.id.buttonName);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v)
{
//run listener after button click
buttonIsClicked();
//or
//listener.onButtonClick();
}
});
}
private void buttonIsClicked(){
//here use method
listener.onButtonClick();
}
}
//EXAMPLE ADAPTER
class YourAdapter implements Activity.Listener{
//...adapter code
void onButtonClick(){
//your code on button click
}
}
SECOND SOLUTION ADAPTER AS ONCLICKLISTENER
class Activity{
//example method
private void youMethod(){
YourAdapter adapter=new YourAdapter();
//bind button
Button button = (Button)findViewById(R.id.buttonName);
//set adapter as onClickListener
button.setOnClickListener(adapter);
}
}
//EXAMPLE ADAPTER
class YourAdapter implements OnClickLstener{
//...adapter code
public void onClick(View v)
{
//adpater code after click
}
}
THIRD SOLUTION - IT CAN BE DONE WITHOUT INTERFACE ( NOT GOOD PRACTICE )
Just add method to Your adapter and use it:
button.setOnClickListener(new OnClickListener() {
public void onClick(View v)
{
//use adapter
adapter.onButtonClick();
}
});
//EXAMPLE ADAPTER WITHOUT INTERFACE
class YourAdapter{
//...adapter code
void onButtonClick(){
//your code on button click
}
}

How to avoid double selection on a RecyclerView OnClickListener?

I have a list using RecyclerView and a OnClickListener to handle the item clicks.
I used the same solution from:
Why doesn't RecyclerView have onItemClickListener()? And how RecyclerView is different from Listview?
public static class ViewHolder extends RecyclerView.ViewHolder implements OnClickListener {
public TextView txtViewTitle;
public ImageView imgViewIcon;
public ViewHolder(View itemLayoutView) {
super(itemLayoutView);
itemLayoutView.setOnClickListener(this);
txtViewTitle = (TextView) itemLayoutView.findViewById(R.id.item_title);
imgViewIcon = (ImageView) itemLayoutView.findViewById(R.id.item_icon);
}
#Override
public void onClick(View v) {
// start a new fragment
}
}
The problem is that if I quickly select two items, it will execute the onClick() two times and on this case, starting two new fragments.
Am I doing something wrong? What is the best approach to avoid this? Is a simple boolean flag enough for all the cases?
UPDATE:
This is a "pack selection screen", which you will select which pack you want to play. Then it will show a new fragment with all the puzzles from the selected pack.
Thanks!
You are doing right about the onClick. Try this:
#Override
public void onClick(View v) {
if(fragment is playing) {
return;
}
// start a new fragment
}

Categories

Resources