Ma structure de projet ressemble à ceci:ViewPager se bloque sur le changement d'orientation - fragments pile et provoquent OutOfMemoryException
MainActivity-> PagerFragment-> PagerViewAdapter qui détient plusieurs PagerImageFragments
Je reçois un OutOfMemoryException après quelques de l'orientation change mais le pager affiche des bitmaps "efficacement" (j'ai utilisé AsyncTask/LruCache). Ensuite, j'ai remarqué que la mémoire utilisée par l'application se multiplie après chaque changement d'orientation et à partir des journaux, je peux voir que onCreate() dans PagerFragment est appelée deux fois à chaque fois. Je pense qu'à cause de cela, mes fragments sont recréés et empilés, ce qui cause le problème. Comment puis-je empêcher cela de se produire?
J'ai essayé la mise
@Override
protected void onSaveInstanceState(final Bundle outState) {
// super.onSaveInstanceState(outState);
}
Ce qui n'a rien fait pour moi. Alors j'ai essayé:
setRetainInstance(true);
qui a rendu mon PagerFragment recréent une seule fois, mais c'est toujours pas ce que je voulais.
EDIT: J'ai légèrement modifié MainActivity de sorte qu'il ne fait que l'initialisation s'il n'y a pas d'instance enregistrée et supprime tous les fragments au démarrage d'un nouveau. J'ai supprimé setRetainInstance (true). Je peux maintenant changer d'orientation plusieurs fois (cela se terminera toujours par une exception de MOO, mais cela prend beaucoup plus de temps pour le déclencher). Mais maintenant il y a un autre problème - si je laisse PagerFragment pour un autre fragment et reviens, il se bloque.
MainActivity:
public class MainActivity extends AppCompatActivity {
private final String TAG = "LOG";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState==null) {
...
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
PagerFragment fragment = new PagerFragment();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();
...
switchContent(new PagerFragment());
}
}
public void switchContent(Fragment fragment) {
FragmentManager fm = getSupportFragmentManager();
List<Fragment> fragmentList = fm.getFragments();
if (fragmentList != null) {
for (Fragment frag : fragmentList) {
Log.d(TAG, "switchContent: destroying "+frag);
fm.beginTransaction()
.remove(frag).commit();
}
}
fm.beginTransaction()
.replace(R.id.fragment_container, fragment)
.commit();
}
intérieur PagerFragment:
PagerAdapter adapter = new PagerViewAdapter(getFragmentManager(), pdfFactory.getPageCount());
ViewPager pager = (ViewPager) getActivity().findViewById(R.id.pager);
pager.setAdapter(adapter);
pager.setPageMargin((int) getResources().getDimension(R.dimen.activity_horizontal_margin));
pager.setCurrentItem(position);
pager.setOffscreenPageLimit(2);
PagerViewAdapter:
public class PagerViewAdapter extends FragmentStatePagerAdapter {
private final int size;
public PagerViewAdapter(FragmentManager fm, int size) {
super(fm);
this.size = size;
}
@Override
public int getCount() {
return size;
}
@Override
public Fragment getItem(int position) {
return PagerImageFragment.newInstance(position);
}
}
PagerImageFragment:
public class PagerImageFragment extends Fragment {
private PhotoView photoView;
int position;
private MyCache<Integer, Bitmap> myCache;
public static PagerImageFragment newInstance(Integer pos) {
final PagerImageFragment f = new PagerImageFragment();
final Bundle args = new Bundle();
args.putInt("position", pos);
f.setArguments(args);
Log.d("DISPLAY", "Bundling...");
return f;
}
public PagerImageFragment() {}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Initialize the cache
myCache = new MyCache<>(5 * 1024 * 1024);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate and locate the main ImageView
final View v = inflater.inflate(R.layout.pager_element, container, false);
photoView = (PhotoView) v.findViewById(R.id.pager_image);
Bitmap image = myCache.get(position);
if (image != null) {
photoView.setImageBitmap(image);
}
else {
new SetImageTask(photoView, myCache).execute(position);
}
return v;
}
Exception (après modification):
java.lang.NullPointerException: Attempt to write to field 'int android.support.v4.app.Fragment.mNextAnim' on a null object reference
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:770)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1677)
at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:536)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:155)
at android.app.ActivityThread.main(ActivityThread.java:5696)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
J'ai posté seulement une partie de mon application. Cette activité modifie les fragments, et seul celui-ci a ce problème. Si j'ajoute configChanges, ne casserai-je pas le reste de l'application? J'ai entendu dire que ce n'est pas recommandé et je suis à la recherche d'une solution propre. – Haruspik