0

I'm trying to change activity's style in runtime.

But I faced with increasing used memory during recreating activity.

For changing style i define some themes and initialize int array for them inside activity:

private int themes[] = new int[]{R.style.AppThemeOrange, R.style.AppThemeTeal,...};

For setting next theme i saved theme id in preferences and restarted activity. Then inside onCreate method i set theme from preferences:

setTheme(PreferencesManager.getInstance().getAppTheme());

Here is my method for changing theme:

public void changeTheme() {
    PreferencesManager.getInstance().setAppTheme(themes[(getCurrentThemePos() + 1) % themes.length]);
    recreate();
}

After every recreating activity allocated memory heap increased by some value 0.1-0.2mb. So if i change app theme many times i'll get Out Of Memory error. Here is my memory monitor:

memory monitor screen

Only after 1 minute changing themes i increased memory heap from 10 to 25 mb. I tried to replace recreate() with relaunching activity using intent, but the result was the same:

public void changeTheme() {
    PreferencesManager.getInstance().setAppTheme(themes[(getCurrentThemePos() + 1) % themes.length]);
    Intent intent = new Intent(getApplicationContext(), UsersActivity.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    finish();
}

Also i tried all available values launchMode in AndroidManifest. No effect. I changed all occurences of "this" to "getApplicationContext()". Left only root layout in xml file. Here is a similar problem. But there are two activities there. In my case if i use

Intent i = new Intent(getApplicationContext(), UsersActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(i);

activity doesn't recreates, because it is already visible, and onCreate() isn't called and theme isn't changed. Also i tried to call System.gc(); in onDestroy(), but memory usage increased anyway.

Here is fragment of my styles.xml file:

<style name="ChangebleTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:windowAnimationStyle">@style/WindowAnimationTransition</item>
    <item name="android:editTextStyle">@style/EditTextStyle</item>
    <item name="editTextStyle">@style/EditTextStyle</item>
    <item name="android:buttonStyle">@style/ButtonStyle</item>
    <item name="buttonStyle">@style/ButtonStyle</item>
    <item name="android:checkboxStyle">@style/CheckboxStyle</item>
    <item name="checkboxStyle">@style/CheckboxStyle</item>
    <item name="switchStyle">@style/SwitchStyle</item>
    <item name="alertDialogProTheme">@style/Theme.AlertDialogPro.Material.Light</item>
</style>

<style name="AppThemeOrange" parent="ChangebleTheme">
    <item name="main_theme_color">@color/colorAccentOrange</item>
    <item name="main_theme_color_dark">@color/colorAccentDarkOrange</item>
    <item name="colorAccent">@color/colorAccentOrange</item>
    <item name="colorPrimaryDark">@color/colorAccentDarkOrange</item>
    <item name="android:navigationBarColor">@color/colorAccentOrange</item>
    <item name="ab_divider_style">@style/AppThemeOrange.ActionBarDivider</item>
</style>

<style name="AppThemeTeal" parent="ChangebleTheme">
    <item name="main_theme_color">@color/colorAccentTeal</item>
    <item name="main_theme_color_dark">@color/colorAccentDarkTeal</item>
    <item name="colorAccent">@color/colorAccentTeal</item>
    <item name="colorPrimaryDark">@color/colorAccentDarkTeal</item>
    <item name="android:navigationBarColor">@color/colorAccentTeal</item>
    <item name="ab_divider_style">@style/AppThemeTeal.ActionBarDivider</item>
</style>

QUESTION:

Can somebody show me what i'm doing wrong and how can i prevent increasing memory usage? Or maybe there is better way to change style of app in runtime?

Thanks in advance!

Community
  • 1
  • 1
MatWay
  • 66
  • 9
  • 1
    In Android it's super easy to leak Activities. Are you using any AsyncTasks or Handlers? Do you have any Singletons that hold a Context? – CaseyB Jun 21 '16 at 15:20
  • 1
    Does the memory footprint also grow in the same unbounded way if you simply rotate the device, without calling your theme switching code? Also, since you are restarting the same Activity, I guess you can get by with just `android:launchMode="singleTop"`, and you don't need `Intent.FLAG_ACTIVITY_REORDER_TO_FRONT`. Does that help? – kenny_k Jun 21 '16 at 15:30
  • Thanks for your fast replies! @CaseyB I really use AsyncTasks and Handlers in my code, but for testing i comented all code leaving only `setTheme` and `setContentView` methods. @theFunkyEngineer Rotating device cause the same situation. Thanks to your answers i tried to create fully new project for testing. When i use default created xml layout, after recreating activity memory grows, but after few times returns to the beginning state(about 11mb). When i put my previous xml layout to new project - problem returns. So i think i have bad layout managing. I'll update my question with more info! – MatWay Jun 22 '16 at 11:01

1 Answers1

0

Thanks all for your help!

During detail code review i found 2 things that caused memory leak:

1) In my xml file i used 3rd party view (AVLoadingIndicatorView) wich doesn't remove animators in onDetachedFromWindow() method. Also i found that some another 3rd party progress bars don't clear animations after detaching.

2) I had handler inside adapter ( that's all my inattention :( ) which i don't stop and clear before destroying activity.

MatWay
  • 66
  • 9