Saving listeners correctly when changing orientation

Consider the following scenario:

  • I have Activity

    with UI elements that fire DialogFragment

    when clicked
  • DialogFragment

    has a listener interface

    that Activity

    provides an implementation. Let's say for example Activity

    is an image editor and DialogFragment

    picks contrast - there will be a dialog box OnContrastChangedListener

    that Activity

    implements
  • Activity

    implemented this interface

    to update views in my UI. Continuing with the image editor example, Activity

    implement OnContrastChangedListener

    to update its preview - something like this:

    contrastDialog.setOnContrastChangedListener(new OnContrastChangedListener {
        @Override
        public void OnContrastChanged(int newContrast) {
            getPreviewView().updateWithContrast(newContrast);            
        }
    });
    
          

  • The orientation changes and everything is recreated and the listener is saved and restored correctly using the recommended techniques here (the listener is saved in Fragment

    and restored when the lifecycle restores the state).

The problem is that the listener interface is now broken . The function getPreviewView()

now returns null

, although when called elsewhere in Activity

it returns the correct value

Sorry for the poor terminology (my knowledge of compilation and bytecode is limited), but I can understand what happened. The frontend was compiled with a version getPreviewView()

that returned a preview view that was destroyed on orientation change and has since been released / garbage collected / now null

.

My question is, is there a way in Java to make the compilation of an interface pending value / function change - like a keyword volatile

in C (I expect not)? In that case, what's the best approach to get around this situation? I have considered the following:

  • Create DialogFragment

    (and it interface

    ) in code that reruns when recreated Activity

    . It's okay for things like OnClickListeners

    for Buttons

    , as they are definitely created. But this one DialogFragment

    is only created when the button is pressed, so this approach means every dialog for the screen is created every time Activity

    - it seems wasteful as they might not even be executed
  • Create all possible interfaces

    for Activity

    each time and store them in member variables, then use these interfaces

    when the request DialogFragments

    should be created by the event. The same comments as above - seem wasteful, making everything possible interface

    just in case it is running.
  • Keep some of the hacky open dialog member variables in action that define the re-creation interfaces

    . Hacky and creates a connection between Activity

    and DialogFragment

    , which is not a big practice.

As you can see, all options involve leisure, somewhat wasteful - is there a way to reuse an existing implementation interface

?

EDIT: Options 1 and 2 won't work because they need a reference to an existing one Dialog

. This can all be done, but it increasingly relies on the hack option along with the variables of the current "Dialogue", getting DialogFragment

help FragmentManager

when restarting the activity, applying it appropriately based on the variable "current dialog", recreating the listener. Is there a less messy way?

+3


source to share


2 answers


The method onAttach

onDetach

is good and I like to use it, sometimes when I know there will be more developers in the code, I will not even throw it blindly, but I do the validation like this:

if(activity instanceof MyInterface){
   interface = (MyInterface) activity;
} else{
   thrown new RuntimeException("Dear colleague, this fragment was meant to have the activity implementing MyInterface or else a bunch of other stuff won't work, please go back to your code and add the interface");
}

      

but as a different resort, you can also re-install the interface when the fragment is recreated. For example, in actiononCreate



if(savedInstanceState != null){
    mDialogFrag = getSupportFragmentManager().findFragmentByTag(MyDialogFrag.TAG);
    if(mDialogFrag != null)
       mDialogFrag.setListener(... the interface   ...);
}

      

I know this is also not the best separation of objects, but the fact of the matter is that the getPreviewView()

current activity NEEDS the current activity to work properly, so you MUST pass this reference again when everything is destroyed. n restored.

They are just different ways to do it.

+1


source


If an activity will always have an interface implementation, is it possible to set a listener in the DialogFragment onAttach ()? This will ensure that when it is destroyed and recreated, it will have the most recent reference, for example:



public void onAttach(Activity activity) {
    super.onAttach(activity);
    contrastChangedListener = (OnContrastChangedListener)activity;
}

public void onDetach() {
    super.onDetach();
    contrastChangedListener = null;

}

      

0


source







All Articles