android - findFragmentByTag null for Fragment A, if setRetain(true) on Fragment B -


my problem involves activity hosting 3 support fragments. 1 normal programmatic fragment (let's call home fragment). 1 portrait fragment added on top of home fragment when device orientated, , 1 'headless', continue async task regardless of configuration changes. simple, working off this nice example.

public class headlesscustomerdetailfetchfragment extends fragment{ private requestcustomerdetails mrequest; private asyncfetchcustomerdetails masyncfetchcustomerdetails;  @override public void oncreate(bundle savedinstancestate) {     super.oncreate(savedinstancestate);     setretaininstance(true);      mrequest = (requestcustomerdetails)getactivity(); }  public void startfetching(string scannedbarcode) {     if(masyncfetchcustomerdetails != null && masyncfetchcustomerdetails.getstatus() == asynctask.status.running) return;      if(masyncfetchcustomerdetails == null || masyncfetchcustomerdetails.getstatus() == asynctask.status.finished)         masyncfetchcustomerdetails = new asyncfetchcustomerdetails(getactivity(), mrequest, mpartner, scannedbarcode); }  public void stopfetching() {     if(masyncfetchcustomerdetails != null && masyncfetchcustomerdetails.getstatus() != asynctask.status.running) return;     masyncfetchcustomerdetails.cancel(true); } 

}

in activity's oncreate() create , add headless fragment if necessary.

 mheadlesscustomerdetailfetchfragment = (headlesscustomerdetailfetchfragment)getsupportfragmentmanager()             .findfragmentbytag(headlesscustomerdetailfetchfragment.class.getsimplename());  if(mheadlesscustomerdetailfetchfragment == null) {          mheadlesscustomerdetailfetchfragment = headlesscustomerdetailfetchfragment.instantiate(this, headlesscustomerdetailfetchfragment.class.getname());     getsupportfragmentmanager().begintransaction()             .add(mheadlesscustomerdetailfetchfragment, mheadlesscustomerdetailfetchfragment.getclass().getsimplename())             .commit();     getsupportfragmentmanager().executependingtransactions();         id = null;     } 

i launch async task (via startfetching() function) after 6 second delay (for testing) kicked off in oncreateview() of portrait fragment added when orientation changes portrait. orientation change detected in activity's oncreate():

if (savedinstancestate == null) {     // initial stuff home fragment }  else {     getsupportfragmentmanager().popbackstackimmediate(null, fragmentmanager.pop_back_stack_inclusive);     if (getresources().getconfiguration().orientation == configuration.orientation_portrait) {         //launch portrait fragment         fragmentlauncher.launchportraitfragment(this);     } 

when task finished, return activity , attempt update ui of active portrait fragment, fragment manager cannot find it, findfragmentbytag() returns null.

to clear:

  • the tag correct
  • the fragment found if not orientate device, , instead kick off async task somewhere else, during activity's onresume() example.
  • if not tell headless fragment retain - thereby losing benefit of not recreating it, portrait fragment correctly found.
  • debugging can see 3 fragments in manager if headless 1 not set retain itself. if is, can only see headless fragment.

maybe retaining fragment aggressively kills other fragments not retained or effect?

the root of problem how maintain reference activity inside headless fragment.
not clear provided code how update ui after completion of asynctask, lets assume use mrequest first code snippet. give mrequest constructor when need new asynctask , use reference after asynctask completes.
ok, when have no screen rotation between moment when activity created , when ui updated. because use reference activity still active.
not ok if rotate screen. have new activity every time after rotation. mrequest assigned once when create headless fragment in first call of activity’s oncreate(). contains reference first instance of activity not active after rotation. there 2 instances of activity after rotation in case: first - referenced mrequest , second - visible , active. can confirm logging reference of activity inside oncreate: log.i(tag, "oncreate: this=" + this); , inside activity’s method updates ui after async task: log.i(tag, "updating ui: this=" + this);
besides first activity in destroyed state. fragments detached activity , non retained fragments destroyed. that’s why findfragmentbytag returns null.
if headless fragment not set retain itself, activity’s oncreate() recreates in every call. mrequest references last created activity fragments. in case findfragmentbytag returns not null.

avoid problem suggest:

  1. use weak reference store reference of activity. this:
    private weakreference<requestcustomerdetails> mrequest;
  2. create method in headlesscustomerdetailfetchfragment update reference.
    public void updateresultprocessor(requestcustomerdetails requestcustomerdetails) { mrequest = new weakreference(requestcustomerdetails); // update ui if there stored result of asynctask (see p.4b) }
  3. call method activity's oncreate() every time.
  4. when asynctask finishes:
    a) if mrequest.get() not null update ui.
    b) if mrequest.get() null store result inside headless fragment , use in p.2.

    weak reference allow gc process destroyed activity , set null inside weak reference. null inside weak reference signal there no ui , nothing update. storing result of asynctask in headless fragment allow use result updating ui after recreation.

    hope help. sorry english. if unclear try explain.

Comments

Popular posts from this blog

java - Static nested class instance -

c# - Bluetooth LE CanUpdate Characteristic property -

JavaScript - Replace variable from string in all occurrences -