J'ai lu que le réglage de .setOnRetainInstance(true)
sur des fragments présentant une interface utilisateur peut entraîner des fuites de mémoire.
Quelqu'un pourrait-il s'il vous plaît expliquer pourquoi et comment cela se produirait? Je n'ai trouvé aucune explication détaillée nulle part.
Dans une Fragment
avec interface utilisateur, vous enregistrez souvent quelques View
s en tant qu'état d'instance pour accélérer l'accès. Par exemple, un lien vers votre EditText
afin que vous n'ayez pas à le faire findViewById
tout le temps.
Le problème est que View
conserve une référence au contexte Activity
. Maintenant, si vous conservez une View
, vous conservez également une référence à ce contexte.
Ce n'est pas un problème si le contexte est toujours valide mais que le cas typique de conservation est le redémarrage de l'activité. Très souvent pour une rotation d'écran par exemple. La récréation d'activité créera un nouveau contexte et les anciens contextes sont censés être récupérés. Mais il ne peut pas être nettoyé maintenant car votre Fragment
a toujours une référence à l’ancien.
L'exemple suivant montre comment ne pas le faire
public class LeakyFragment extends Fragment {
private View mLeak; // retained
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mLeak = inflater.inflate(R.layout.whatever, container, false);
return mLeak;
}
@Override
public void onDestroyView() {
super.onDestroyView();
// not cleaning up.
}
}
Pour résoudre ce problème, vous devez effacer toutes les références à votre interface utilisateur dans onDestroyView
. Une fois que l'instance Fragment
est réutilisée, il vous sera demandé de créer une nouvelle interface utilisateur sur onCreateView
. Il est également inutile de conserver l'interface utilisateur après onDestroyView
. L'interface utilisateur ne sera pas utilisée.
Dans cet exemple, le correctif consiste à remplacer onDestroyView
par
@Override
public void onDestroyView() {
super.onDestroyView();
mLeak = null; // now cleaning up!
}
Et en plus de conserver des références à View
s, vous ne devez évidemment pas conserver de références à Activity
(par exemple, de onAttach
- clean sur onDetach
) ou de tout Context
(sauf s'il s'agit du contexte Application
.
Faites attention lorsque vous conservez certains objets associés à l'activité.
Attention: Bien que vous puissiez renvoyer un objet, vous ne devez jamais transmettre un objet lié à l'activité, tel qu'un Drawable, un Adapter, un View ou autre objet associé à un contexte. Si vous le faites, toutes les vues et ressources de l'instance d'activité d'origine seront perdues. (Une fuite de ressources signifie que votre application les maintient en attente et qu'elles ne peuvent pas être récupérées, ce qui permet de perdre beaucoup de mémoire.)
http://developer.Android.com/guide/topics/resources/runtime-changes.html#RetainingAnObject
setRetainInstance(true)
est utilisé pour conserver des occurrences de fragments dynamiques lors d'une reconstitution d'activité, telle qu'une rotation d'écran ou d'autres modifications de configuration. Cela ne signifie toutefois pas que le fragment sera conservé pour toujours par le système.
Lorsqu'une activité est arrêtée pour d'autres raisons, telles que le fait que l'utilisateur termine l'activité (c'est-à-dire qu'il appuie de nouveau), le fragment devrait être éligible pour la récupération de place.
"SetRetainInstance" est utilisé pour maintenir l'état du fragment lorsque l'activité est recréée. Selon la documentation officielle: si nous utilisons "setRetainInstance", 2 méthodes du cycle de vie du fragment ne seront pas exécutées (onCreate, onDestroy) . Cependant, les vues contenues dans le fragment seront recréées, c'est-à-dire parce que le cycle de vie sera exécuté à partir de "onCreateView" . Dans ces cas, si nous avons enregistré des données dans "onSaveInstanceState", nous devrions le demander dans "onActivityCreated" au lieu de "onCreate".
Informations officielles: https://developer.Android.com/reference/Android/app/Fragment.html#setRetainInstance(boolean)
Plus d'infos: https://inthecheesefactory.com/blog/fragment-state-saving-best-practices/fr