48

I am building a tablet app. In this app there is one activity with two fragments. First fragment is a "known" list fragment which is showing a simple one item layout list from a database query, the second fragment shows the details about the selected record (from the list fragment). The think with the second fragment is that its type depends from the records being showed in the list. For example if the records are customers then the selected customer's details are shown, if they are inventory items the selected item's details are shown etc. In order to communicate with the Details Fragment I've created an interface which every detail fragment class implements. The list fragment is "fixed" in the activity from the layout xml. The detail fragment however is created during the activity's creation like this:

super.onCreate(savedInstanceState);
setContentView(R.layout.act_hlpfiles_host);

...

FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.laydetailsfragment, FragmentsPool.getHelperFileFragment(501), "recordDetails");
fragmentTransaction.commit();

myDetailsFragment = getFragmentManager().findFragmentByTag("recordDetails");

...

myListFragment = (frg_hlpfiles_lstrecords) getFragmentManager().findFragmentById(R.id.frg_lstrecords);

....
}

The problem with this code is that myDetailsFragment is always null. This is because the fragmentTransaction.commit() does not run immediately but it happens on the main thread the next time that thread is ready (as the android documentation states).

If I create the detail fragment in onStart() and instantiate the list fragment in onCreate everything works ok.

So the question is: How can I be sure that the fragmentTransaction.commit() has commit the transaction so I can do some work with the added fragment? Furthermore is there any way to wait until the commit happens and then continue with the rest of the code?

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
ChD Computers
  • 3,135
  • 3
  • 23
  • 33

4 Answers4

107

Try running fragmentManager.executePendingTransactions() after committing your transaction but before finding by tag and see if that works for you.

Pratik Butani
  • 60,504
  • 58
  • 273
  • 437
Mark D
  • 3,317
  • 1
  • 26
  • 27
  • 2
    Hey Mark! Gues what! It is working. Now I 've got another question for you, can you tell me why I read 3 - 4 times FragmentTransaction's documentation to find a solution for this but I never looked at FragmentManager's documents? :-) – ChD Computers Aug 31 '11 at 00:44
  • 2
    I'm glad that worked. The documentation could stand to be more cohesive and intuitive... – Mark D Aug 31 '11 at 16:53
10

In Android API 24 FragmentTransaction has synchronous .commitNow() method. It's in the reference now: https://developer.android.com/reference/android/app/FragmentTransaction.html#commitNow()

On the contrary, .commit() works asynchronously. It just schedules a commit of the transaction.

Ostap Andrusiv
  • 4,827
  • 1
  • 35
  • 38
  • where did you find source about .commitNow() new method – prGD Jun 09 '16 at 08:37
  • @prGD there were multiple rumors of that, someone spotted that in source code and they finally announced that on Google I/O 2016. – Ostap Andrusiv Jun 09 '16 at 12:39
  • @prGD it's available from API 24. It's in the reference: [https://developer.android.com/reference/android/app/FragmentTransaction.html#commitNow()](https://developer.android.com/reference/android/app/FragmentTransaction.html#commitNow()) – Ostap Andrusiv Sep 27 '16 at 11:33
  • How would one utilize this, when calling `DialogFrament.Show()` – Zapnologica Apr 04 '18 at 10:22
1

I was facing a similar issue.

I think the key learning here is using commitNow() instead of commit() with getSupportFragmentManager. This will disallow the main thread from executing until the fragment has been destroyed. It is imperative when building interfaces and using a shared activity. I should know it had me stumped for a while!

Here is a sample code example: getSupportFragmentManager().beginTransaction().remove(getSupportFragmentManager().findFragmentById(R.id.fragment_frame)).commitNow();

Sol Sadek
  • 11
  • 3
0

"....so I can do some work with the added fragment? Furthermore is there any way to wait until the commit happens and then continue with the rest of the code?"

It all depends on what work you want to do. From your question I see that most of your work code should be in your fragment code anyway, for example when an inventory item is selected.

On the callback when a selection list item is selected (in order to change the details fragment) you'll be able to get hold of the details fragment comfortably enough anyway.

Furthermore, you already have the fragment from the return of FragmentsPool.getHelperFileFragment(501), so I don't see why you need to get the fragment via its tag.

I'm interested to know what work you need to do in onCreate with your added details fragment.

PJL
  • 18,735
  • 17
  • 71
  • 68
  • First of all Thank you for your answer. Actually most of the work is done within the activity code (new record, save, delete etc). Your suggested approach is quite right but my app is a little more complicated, the reason I want the details fragment via the tag is because sometimes I need to know the last details fragment that was displayed before it changes with a new one with FragmentsPool.getHelperFileFragment() in order to create the backstack. In onCreate I just initialize the first "look" of the activity based on one ListID. The code in my question is simplified and not complete – ChD Computers Sep 02 '11 at 20:18