Home » Android » android – Best practice for updating arguments of a fragment?

android – Best practice for updating arguments of a fragment?

Posted by: admin April 23, 2020 Leave a comment

Questions:

I know about the “newInstance”-Pattern (Best practice for instantiating a new Android Fragment). But how do I update these arguments of a fragment for example if another fragment changes data?

I know about callback-methods between Fragments/Activitys, but these callbacks won’t update the arguments?!

For example: on creation of the fragment I pass an URI to the it with the bundle.
Then another fragment changes this URI via changeUri(Uri uri) method callback on the first fragment.
If then the fragment gets recreated (for example due to screen rotation) it will use the first URI from the arguments bundle instead of the later updated uri, correct?

What is the best practice to solve this? Do I have to manually store it in the savedInstanceState and on usage decide whether to use the instanceState or arguments-bundle?

I’m looking for a standard way of handling the arguments of my fragments, so I think I’m going with such an approach (pseudo-code):

private Uri arg1;

public static Fragment newInstance(Uri arg1) {
  create bundle
  create fragment instance
  set bundle to fragment
  return fragment
}

private void onCreate(Bundle savedInstance) {
  if(savedInstance != null) {
    arg1 = savedInstance.uri
  }
}

private Uri getUri() {
  if(arg1 == null) {
    arg1 = getArguments.uri
  }
  if(arg1 == null) {
    arg1 = defaultValue
  }
}

So I have a simply unified way to access my argument. And don’t have to use the if-else-hassle, every time I need that argument.

What do you think about it?

How to&Answers:

You can’t change arguments once its set and Fragment is added to Activity, I used a similar approach you defined yourself.

First, I checked the Bundle passed to onCreate(), if its not null I use it, but if its null then I use arguments. And I save whatever is the newest data in onSaveInstanceState().

For more details: Is it possible to pass arguments to a fragment after it's been added to an activity?

Answer:

You save state the same way you would do for Activities in the Fragment’s onSaveInstanceState callback. If you have updated the URI since the last onCreate(), you would store the updated URI in the Bundle, and would receive this back in onCreate(). Saving state is exactly what this is designed for, and by changing the URI, all you’ve done is changed state.

Answer:

I just change the value in the bundle.

Example:

synchronized (fragment.getArguments()) {
    fragment.getArguments().putInt(KEY, new Value);
}

And update content with new Argument

Answer:

Best practice for updating arguments of a fragment: Why we need to add argument By NewInstance() method & why it is best practices for fragment?

Fragment can be think of as a modular section of an activity. This means when we create a fragment we need to make it modular & independent.

Suppose you need a fragment which need a argument to operate.We can also write it

MyFragmentClass mFrag = new MyFragmentClass();
Bundle bundle = new Bundle();
bundle.putString("key", value);
mFrag.setArguments(bundle);

It also works fine & you can get argument onCreate method. Here is the difference that you also can make an instance of fragment without argument and add it to fragment manager but your fragment needs argument to operate. Adding newInstance method in fragment forces developer to add argument while creation. That’s why it is said best practices.

In your problem you can use setRetainInstance(boolean retain) which prevent your fragment not to destroy when activity is destroyed.

Answer:

Depending on the way you are using your fragments may determine how effective that strategy will be.

For instance, if you have many fragments in the common tab/view pager pattern and are managing them with a FragmentStatePagerAdapter there may be the opportunity for your activity or other fragments to reference a fragment instance that no longer exists causing a null pointer exception.

A way that you could get around this, if you don’t want to write callbacks, is to use Intents and BroadcastReceivers (which may be a little overkill and hard to manage but if done correctly can save a lot of headache in my experience) to send and receive broadcasts to and from the parent activity.

The beautiful thing about intents is that they can be tuned to work at specific times and accept a wide range of data extras including bundles and parcel-able objects.

Answer:

Incase you want to reuse a fragment but need to update the arguments, you need to use fragment.getArguments().putAll(bundle);

    private static void setInspireByDoArguments(DoOptionsFragment fragment, long doId) {
    Bundle bundle = new Bundle();
    bundle.putLong(Constants.EXTRA_DO_ID, doId);
    bundle.putInt(Constants.EXTRA_DO_OPTIONS_DIALOG_MODE, MODE_GET_INSPIRE_BY_DO);
    if (fragment.getArguments() != null) {
        fragment.getArguments().putAll(bundle);
    } else
        fragment.setArguments(bundle);
}

 //This is how I managed to Check if the fragment exist and update the arguments.

 public static void showDoInspireDialog(FragmentManager fragmentManager, long doId, DoOptionsFragment.DoOptionCallBack callBack) {
    DoOptionsFragment doOptionsFragment = (DoOptionsFragment) fragmentManager.findFragmentByTag("do_options_fragment");
    if (doOptionsFragment == null) {
        doOptionsFragment = DoOptionsFragment.getInspiredByDoInstance(doId, callBack);
        fragmentManager.beginTransaction()
                .add(doOptionsFragment, "do_options_fragment")
                .commit();
    } else {
        doOptionsFragment.setCallBack(callBack);
        setInspireByDoArguments(doOptionsFragment, doId);
        doOptionsFragment.showInspireByDoDialog(doId);
    }
}

  public static DoOptionsFragment getInspiredByDoInstance(long doId, DoOptionsFragment.DoOptionCallBack callBack) {
    DoOptionsFragment doOptionsFragment = new DoOptionsFragment();
    setInspireByDoArguments(doOptionsFragment, doId);
    doOptionsFragment.setCallBack(callBack);
    return doOptionsFragment;
}