Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fragment and DialogFragment Lifecycle Relationship

I have Fragment "A" where I have an ImageButton in place. Upon clicking this button a DialogFragment "B" is called to the foreground where Fragment "A" is partially visible in the background. DialogFragment "B" presents the user with a list of choices. Upon clicking a specific choice DialogFragment "B" is dismissed via Dismiss() and Fragment "A" becomes fully visible again.

During this action I need to update the ImageButton on Fragment "A" to represent the user's choice made on DialogFragment "B" (basically a new image for the ImageButton).

Am I correct in thinking the right place to update the ImageButton on Fragment "A" is during OnResume? Does Fragment "A" go into OnPause while FragmentDialog "B" is being shown? Therefore upon returning from DialogFragment "B", Fragment "A" would trigger its OnResume and that's where I should make the update changes to the ImageButton being presented to the user?

I hope my explanation is clear. Any detailed help on where and how I should be updating the ImageButton would be highly appreciated.

like image 463
CBA110 Avatar asked Jul 16 '15 12:07

CBA110


2 Answers

With the addition of ViewModels and LiveData solving this problem just got easier. Create a viewModel which both fragments reference. Put the next line in the OnCreate of the fragments. Can also be in onCreateDialog of the dialogfragment.

myViewModel = ViewModelProviders.of(getActivity()).get(MyViewModel.class);

When the dialog is dismissed, call a method on myViewModel, which updates a LiveData variable:

dialogBuilder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialogInterface, int i) {
            myViewModel.setButtonPressed(PositiveButtonPressed);
        }
    });
    dialogBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialogInterface, int i) {
            myViewModel.setButtonPressed(NegativeButtonPressed)
        }
    });

In the viewModel the method sets a MutuableLiveData variable for example to the image to be shown.

void SetButtonPressed(int buttonPressed){
   if (buttonPressed==positiveButtonPressed){
       imageToBeShown.setValue(image A);
   }
   else{
      imageToBeShown.setValue(image B);
   }
}

Set an observer to LiveData variable in onActivityCreated:

myViewModel.imageToBeShown().observe(getViewLifecycleOwner(), new Observer<Image>() {
        @Override
        public void onChanged(@Nullable Image image) {
            button.setBackground(image);
            }
        }
    });

Of course you can implement a getter method and keep the MutuableLiveData variable private. The observer then just obeserves the getter methode.

like image 137
KvdLingen Avatar answered Sep 29 '22 11:09

KvdLingen


I had same problem when tried with Interface-Callback method but OnResume of Fragment didn't got triggered when DialogFragment was dismissed since we are not switching to other activity.

So here Event Bus made life easy. Event Bus is the easiest and best way to make communication between activities and fragments with only three step, you can see it here

This is nothing but publish/subscribe event bus mechanism. You will get proper documentation here

Add EventBus dependency to your gradle file -
compile 'org.greenrobot:eventbus:x.x.x'
OR
compile 'org.greenrobot:eventbus:3.1.1' (Specific version)

For the above scenario -

Create one custom POJO class for user events -

public class UserEvent {
    public final int userId;

    public UserEvent(int userId) {
        this.userId = userId;
    }
}

Subscribe an event in Fragment A whenever it is posted/published from DialogFragment or from somewhere else -

@Subscribe(threadMode = ThreadMode.MAIN)
public void onUserEvent(UserEvent event) {
    // Do something with userId
    Toast.makeText(getActivity(), event.userId, Toast.LENGTH_SHORT).show();
}

Register or Unregister your EventBus from your Fragment A's lifecycle especially in onStart and onStop respectively -

@Override
public void onStart() {
    super.onStart();
    EventBus.getDefault().register(this);
}

@Override
public void onStop() {
    EventBus.getDefault().unregister(this);
    super.onStop();
}

In the end, on clicking specific item, Publish/Post your event from DialogFragment -

EventBus.getDefault().post(new MessageEvent(user.getId()));
like image 25
Varad Mondkar Avatar answered Sep 29 '22 11:09

Varad Mondkar