Skip to content
This repository was archived by the owner on Feb 26, 2023. It is now read-only.
This repository was archived by the owner on Feb 26, 2023. It is now read-only.

@FragmentById does not work on child of fragment. #1302

Closed

Description

@mwinters-stuff

In API 21+ and possibly earlier, i have only seen this when using api 21. The call getFragmentManager().getFragmentById wont get fragments that are children of a fragment, thus when using FragmentById as a child fragment of a EFragment you will get null.

when finding fragment that is a child of a fragment, getChildFragmentManager().findFragmentById()....

Activity

  1. dodgex commented on Jan 2, 2015

    @dodgex
    Member

    yeah you are right. it seems that we have to call getChildFragmentManager()... but i also think, that we might need to have an option to decide if the getFragmentManager() should be used or if the getChildFragmentManager() should be used. as for not all fragment injecting annotations use the getFragmentManager() and if we just change that behaviour this would result in a breaking change.

    i think to support this we have to add a parameter @FragmentById and @FragmentByTag to let the generated code use the correct manager. i think i would call it useChildFragmentManager or something like that with a default value of false so that it keeps working for existing applications and then the user can set it to true to allow the usage of getChildFragmentManager().

    @WonderCsabo @yDelouis any better ideas?

  2. WonderCsabo commented on Jan 3, 2015

    @WonderCsabo
    Member

    Yeah, a boolean flag would be the most flexible. Although getChildFragmentManager() is only available in API level 17 and in never revision of the support lib. If it is not available in the actual API Fragment we should just invalidate, but what should happen if it is available in the API, but the app has a lower miSdkVersion?

  3. dodgex commented on Jan 3, 2015

    @dodgex
    Member
    • if not in the api (due to lower target than 17): invalidate
    • if native fragment on minsdk < 17 but with target >= 17: invalidate (as it cant be used on every possible target/device)
    • if support fragment but old revision: add a note to the javadoc that this feature requires support-v7 rev >= x and let it fail on compile time if we can't (in)validate here.

    did i forgot a case?

  4. WonderCsabo commented on Jan 3, 2015

    @WonderCsabo
    Member

    I think it would be better invalidating than generating non-compilable code (we can check whether a method exists, like here).

  5. dodgex commented on Jan 3, 2015

    @dodgex
    Member

    yeah. where possible invalidate. but imo users should use up to date android support libs anyway

  6. WonderCsabo commented on Jan 4, 2015

    @WonderCsabo
    Member

    BTW, we also have to validate that the user only set that parameter to true if the enclosing class is a Fragment.

  7. dodgex commented on Jan 4, 2015

    @dodgex
    Member

    yeah. i missed to mention that in my first comment but thought about that too.

  8. WonderCsabo commented on Jan 8, 2015

    @WonderCsabo
    Member

    @yDelouis do you agree with the proposed enhancement?

  9. yDelouis commented on Jan 12, 2015

    @yDelouis
    Contributor

    I'm okay with this.

  10. WonderCsabo commented on Jan 12, 2015

    @WonderCsabo
    Member

    OK. Guys, i have other priorities, feel free to implement this.

  11. self-assigned this
    on Feb 23, 2015
  12. WonderCsabo commented on Feb 23, 2015

    @WonderCsabo
    Member

    I am wondering about one thing: currently EFragments uses the context Activity's FragmentManager. This is the same with Fragment.getFragmentManager() if the EFragment is directly atteched to the Activity. However, if it is nested, the two are not the same, since the second returns the parent Fragment's getChildFragmentManager(). I think it makes more sense to use Fragment.getFragmentManager(). @yDelouis @dodgex ?

  13. 1 remaining item

  14. WonderCsabo commented on May 31, 2015

    @WonderCsabo
    Member

    I started to implement this feature, and this came into my mind: does this feature actually make sense?

    I mean if you want to use getChildFragmentManager(), then you obviously used that to add the Fragments. But when you added the Fragments for example in onCreate(), then you already had the chance to store it in fields, so it is totally unnecessary to make AA inject them later. @wintersandroid what is the use case here? 😕

  15. mgod commented on Jun 3, 2015

    @mgod

    My use case is loading embedded nested fragments from the layout xml for a fragment. It seems like it should just fall back on getChildFragmentManager if we're on API >= 17 and the getFragmentManager wasn't able to find a fragment?

  16. WonderCsabo commented on Jun 3, 2015

    @WonderCsabo
    Member

    @mgod does it work that way?

    The fallback is a definitely no go, since it could be a source of bugs. We should leverage this decision to the client, with the proposed childFragment flag.

  17. mgod commented on Jun 3, 2015

    @mgod

    With the current AA, all of my Fragments are null if I build them in the layout for another fragment. As a really dumb work around, this fixes the issue and gives me non-null fragments when I need them:

        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            if (Build.VERSION.SDK_INT >= 17 && myFragment == null) {
                myFragment = (MyFragment)getChildFragmentManager().findFragmentById(R.id.myFragment);
            }
        }

    I think the childFragment flag would work well, assuming it would continue to use the regular fragment manager in API < 17.

  18. WonderCsabo commented on Jun 3, 2015

    @WonderCsabo
    Member

    Can you share the Fragment layout (skeleton) as well?

  19. mgod commented on Jun 3, 2015

    @mgod

    Here's a cut down version of the layout:

    <LinearLayout >
    
        <RelativeLayout
            <!-- cut out a bunch of pretty standard layout -->
        </RelativeLayout>
    
        <fragment
            android:id="@+id/myFragment"
            android:name="com.foo.views.MyFragment_"  />
    
    </LinearLayout>
  20. WonderCsabo commented on Jun 3, 2015

    @WonderCsabo
    Member

    Thanks. I will test this first.

  21. mgod commented on Jun 3, 2015

    @mgod

    Thanks @WonderCsabo! If it helps at all, I started running into the problem of the null fragments when I set my target API to 21 from 20. I also started seeing the issue in my robolectric tests after updating to robolectric 3.0-rc3 from 2.4.

  22. mwinters-stuff commented on Jun 3, 2015

    @mwinters-stuff
    Author

    My use-case is having a fragment in a view pager, where on a landscape tablet, there is two children (master/detail) and on phone or portrait there is only the master detail..

    It would be ideal to just have the fragments loaded from the XML layouts, currently I have code in the @AfterInject to create the child fragments into frame layouts on the master fragment..

    So Ideally..

    (this is rough hand written code, I may have the fragment xml syntax wrong)

    [fragment_dual_balances.xml in layout]
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:baselineAligned="false"
        android:orientation="horizontal" xmlns:android="http://schemas.android.com/apk/res/android">
        <Fragment
            android:name=".FragmentBalances"
            android:id="@+id/fragmentBalances"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </LinearLayout>
    
    [fragment_dual_balances.xml in layout-sw600dp-land]
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:baselineAligned="false"
        android:orientation="horizontal" >
    
        <Fragment
            android:name=".FragmentBalances"
            android:id="@+id/fragmentBalances"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1" />
    
        <Fragment
            android:name=".FragmentGraph"
            android:id="@+id/fragmentDataGraph"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            tools:ignore="InconsistentLayout" />
    </LinearLayout>
    
    

    Then in my FragmentDualBalances.java

    @EFragment(R.layout.fragment_dual_balances)
    public class FragmentDualBalances extends FragmentPagerBase implements FragmentBalances.BalancesCallback {
      @FragmentById(R.id.fragmentBalances)
      FragmentBalances fragmentBalances;
    
      @FragmentById(R.id.fragmentDataGraph)
       FragmentDataGraph fragmentDataGraph;
    
      @AfterViews
      void onAfterViews() {
        if(fragmentDataGraph != null) {
          fragmentDataGraph.setCallback(this, accountId, mGraphTag);
        }
        fragmentBalances.setCallback(this);
      }
    
    }
    

    At the moment, in the above xml files the fragments are changed to FrameLayouts and my FragmentDualBalances.java is this

    @EFragment(R.layout.fragment_dual_balances)
    public class FragmentDualBalances extends FragmentPagerBase implements FragmentBalances.BalancesCallback {
      @ViewById(R.id.fragmentBalances)
      FrameLayout frameLayout;
    
      private FragmentBalances fragmentBalances;
    
      @ViewById(R.id.fragmentDataGraph)
      FrameLayout frameDataGraph;
    
      private FragmentDataGraph fragmentDataGraph;
    
      @InstanceState
      String mGraphTag = "";
    
      @FragmentArg
      @InstanceState
      Integer accountId;
    
    
      @AfterViews
      void onAfterViews() {
        FragmentTransaction fragmentTransaction = getChildFragmentManager().beginTransaction();
        if (frameLayout != null && fragmentBalances == null) {
          fragmentBalances = (FragmentBalances) getChildFragmentManager().findFragmentById(frameLayout.getId());
          if(fragmentBalances == null) {
            fragmentBalances = FragmentBalances_.builder().accountId(accountId).build();
          }
          fragmentTransaction.replace(frameLayout.getId(), fragmentBalances);
        }
    
        if (frameDataGraph != null && fragmentDataGraph == null) {
          fragmentDataGraph = (FragmentDataGraph) getChildFragmentManager().findFragmentById(frameDataGraph.getId());
          if(fragmentDataGraph == null) {
            fragmentDataGraph = FragmentDataGraph_.builder().accountId(accountId).build();
          }
    
          fragmentTransaction.replace(frameDataGraph.getId(), fragmentDataGraph);
        }
    
        if(fragmentDataGraph != null) {
          fragmentDataGraph.setCallback(this, accountId, mGraphTag);
        }
        fragmentBalances.setCallback(this);
    
        fragmentTransaction.commit();
      }
    }
    
    
  23. WonderCsabo commented on Jun 3, 2015

    @WonderCsabo
    Member

    Thanks guys! I have to be honest, i forgot that we can load the Fragments into a Fragment from XML, so those Fragments will be child Fragments. In that case, this is indeed a valid use-case. I will test it, and then continue my implementation.

  24. WonderCsabo commented on Sep 21, 2015

    @WonderCsabo
    Member

    Done.

  25. Mehly commented on Sep 14, 2016

    @Mehly

    Is this issue really solved? I am currently running AA 4.1.0 and @FragmentById still returns null when using nested fragments?

  26. mgod commented on Sep 14, 2016

    @mgod

    @Mehly I think this got removed from the final AA because nested fragments are only supposed to be supported when the fragment is loaded dynamically. I think they happened to work ok for a while, but start having problems in later Android versions. See the PR for more details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions