Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TIMOB-13392] Android: fix TabGroup fragment memory leaks, fix maps in tabs including when acti... #6008

Closed
wants to merge 7 commits into from

Conversation

mokesmokes
Copy link
Contributor

This fixes and improves the initial commit using the ViewPager for the TabGroup.
Issues solved:

  1. Huge memory leak when the tab group activity was destroyed and later recreated (i.e. as in https://jira.appcelerator.org/browse/TIMOB-17016). The issue was that ever since 3.3.0 we have been keeping references to the fragments in our own data structures, and also never detaching and destroying fragment. So if this cycle happens a few times - memory explodes. This was masked by the crash we had until now.... The main fix was to remove ALL fragment references in our code.
  2. The tab group needed to restore data structures coming back (same situation as in 17016), so that we can point to the correct fragments when coming back, and not blindly create new ones (the leak). So for this we had no choice but update TiLifecycle, and add onSaveInstanceState and onRestoreInstanceState. onSaveInstanceState is now used in the tab group.
  3. We needed the restore state as early as possible (i.e. activity creation), so I had to add the restored Bundle to the windowCreated() calls. The tab group must use this, and it's a good thing - hopefully other window modules and can make use of this stuff and be more intelligent in their handling.
  4. These are the key fixes. The rest of the changes are to accommodate these infrastructure changes.

In general, this is very well tested, since it built on the testing done for the previous commit which was already heavy. Specifically tested: removing and adding tabs, using a map in the tabs, disabling and enabling tabs, doing all the previous then opening a new window (destroying the tab group activity), and then coming back to the tab group - all works splendidly and no memory leak.
Please merge ASAP since this fixes serious issues in the previous commit. Thanks!

@ingo
Copy link
Contributor

ingo commented Sep 2, 2014

Thank you. Is this part of https://jira.appcelerator.org/browse/TIMOB-13392, or is it part of a new ticket?

@mokesmokes
Copy link
Contributor Author

This is a bunch of fixes for that issue. I'm currently writing up the comments for it, hopefully all will be clear in 5 minutes :)

{
// Set the layout proxy here since it's not ready when we indirectly call it inside contextCreated()
setLayoutProxy(window);

// The UIWindow needs to be created before we run the script
activityWindow = new TiUIActivityWindow((TiActivityWindowProxy)window, this, getLayout());
super.windowCreated();
super.windowCreated(savedInstanceState);
}

@Override
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have changes like this in several files to enable activities to save and restore arbitrary data structures. This was absolutely required for the tab group, which needs to store/retrieve the IDs of the fragments in the FragmentManager in order to prevent leaks.

@mokesmokes
Copy link
Contributor Author

See comments in the code for explanation of what was done.

return POSITION_NONE;
while (fragmentTags.size() <= position) {
fragmentTags.add(null);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation is a bit off here

@hieupham007
Copy link
Contributor

Hey Mark, I'm running your updated test case in the ticket as I'm trying to reproduce the memory leak problem. I have developer option 'dont keep activities' on, so the activities are destroyed every time i switch tabs. I'm not seeing any significant movement of the heap via DDMS after scrolling through all 5 tabs ~20-30 times.

@mokesmokes
Copy link
Contributor Author

@hieupham007 put the following code in android/modules/ui/src/java/ti/modules/titanium/ui/widget/tabgroup/TiUIActionBarTab.java in the TabFragment class, open and close window 2 several times (with don't keep activities on) and watch over time how many fragments are created (in the 3.5.0 master).... This is what happens when we create fragments every time, instead of reusing the fragments that are already in the FragmentManager.
I'm also assuming there is a performance hit as we recreate more and more zombie fragments every time we return to the tabgroup.

@Override
public void onCreate(Bundle savedInstanceState) {
  Log.e(TAG, "fragment onCreate called savedInstanceState == null: " + (savedInstanceState == null));
  super.onCreate(savedInstanceState);
}

} else {
transaction = manager.beginTransaction();
}
FragmentTransaction transaction = manager.beginTransaction();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check was not necessary and in fact was crashing the app on occasion due to https://code.google.com/p/android/issues/detail?id=42601 . The crash would occur because tabFragment.getChildFragmentManager() would sometimes be called prior to tabFragment.onActivityCreated occurring (although getSupportFragmentManager works fine at that point). The reason the 3.5.0 master works is that it does not set the ID "tabcontent", so we never called getChildFragmentManager... However testing shows that we don't need it, and the sample app works perfectly without it. If we ever want getChildFragmentManager to be used, then it can only be called after fragment.onActivityCreated (unless Google fixes their bug). Nevertheless, it's not needed at this point.

@mokesmokes
Copy link
Contributor Author

Modified per comments, documented smoothScrollOnTabClick, fixed a map issue - ready to go.

@mokesmokes mokesmokes mentioned this pull request Sep 10, 2014
@mokesmokes
Copy link
Contributor Author

Any update on the review for this? All comments taken care of and no issues found with any test I tried, with latest fixes.

description: |
If true, when clicking the tab the page transition is animated, false otherwise.
platforms: [android]
since: 3.4.0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be since 3.5.0 .

@mokesmokes
Copy link
Contributor Author

@pingwang2011 fixed the doc

@hieupham007
Copy link
Contributor

Functionally tested with KitchenSink and test cases in the ticket. Looks good to me.

@mokesmokes
Copy link
Contributor Author

Can this be merged please, if there are no outstanding issues? Thanks.

@mokesmokes
Copy link
Contributor Author

@ingo @hieupham007 @pingwang2011
Guys, this is a large PR that is currently tested and mergeable on 3.5.0. If unmerged soon it will surely break over time and more work will be required to modify and re-test. This PR fixes changes from my previous PR: #5651 as well as adds functionality requested by other developers (smoothScrollOnTabClick). Please merge..... thanks :)

@yomybaby
Copy link
Contributor

👍 Great work!

@ingo ingo changed the title fix TabGroup fragment memory leaks, fix maps in tabs including when acti... [TIMOB-13392] Android: fix TabGroup fragment memory leaks, fix maps in tabs including when acti... Nov 18, 2014
@hieupham007
Copy link
Contributor

I've created a new PR to resolve conflicts: #6414

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants