Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Flow mortar ViewPager Adapter with save state. Logic of saving state took from FragmentStatePagerAdapter.
package com.ghm.ui.adapter;
import android.content.Context;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.v4.view.PagerAdapter;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.ghm.ui.util.ScreenHelper;
import java.util.ArrayList;
import java.util.List;
import flow.path.Path;
import io.techery.presenta.mortarscreen.ScreenScoper;
import mortar.MortarScope;
public class ScreenPagerStateAdapter<S extends Path> extends PagerAdapter {
protected final Context context;
private final List<S> screens;
private final ScreenScoper screenScoper;
private ArrayList<View> views = new ArrayList<>();
private ArrayList<SparseArray<Parcelable>> states = new ArrayList<>();
public ScreenPagerStateAdapter(Context context) {
this.context = context;
this.screens = new ArrayList<>();
screenScoper = new ScreenScoper();
}
public void addScreen(S... newScreens) {
for (S newScreen : newScreens) {
screens.add(newScreen);
}
notifyDataSetChanged();
}
@Override
public int getCount() {
return screens.size();
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
Path screen = screens.get(position);
String scopeName = getName(position);
MortarScope screenScope = screenScoper.getScreenScope(context, scopeName, screen);
Context screenContext = screenScope.createContext(context);
int layout = ScreenHelper.getLayout(screen);
View newChild = LayoutInflater.from(screenContext).inflate(layout, container, false);
container.addView(newChild);
fillIfNeed(position);
SparseArray<Parcelable> state = states.get(position);
if (state != null) {
newChild.restoreHierarchyState(state);
}
views.set(position, newChild);
return newChild;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
View view = ((View) object);
MortarScope screenScope = MortarScope.getScope(view.getContext());
container.removeView(view);
screenScope.destroy();
fillIfNeed(position);
SparseArray<Parcelable> array = new SparseArray<>();
view.saveHierarchyState(array);
states.set(position, array);
views.set(position, null);
}
public final S getItem(int position) {
return screens.get(position);
}
@Override public Parcelable saveState() {
Bundle bundle = new Bundle();
for (int i = 0; i < states.size(); i++) {
fillIfNeed(i);
SparseArray<Parcelable> state = states.get(i);
if (state == null) continue;
bundle.putSparseParcelableArray(getName(i), state);
}
for (int i = 0; i < views.size(); i++) {
fillIfNeed(i);
View view = views.get(i);
if (view == null) continue;
SparseArray<Parcelable> state = new SparseArray<>();
view.saveHierarchyState(state);
bundle.putSparseParcelableArray(getName(i), state);
}
return bundle;
}
@Override public void restoreState(Parcelable state, ClassLoader loader) {
Bundle bundle = (Bundle) state;
states.clear();
views.clear();
for (int i = 0; i < getCount(); i++) {
SparseArray<Parcelable> array = null;
try {
array = bundle.getSparseParcelableArray(getName(i));
} catch (Exception e) {
e.printStackTrace();
}
if (array == null) array = new SparseArray<>();
states.add(i, array);
}
}
private void fillIfNeed(int position) {
while (views.size() <= position) {
views.add(null);
}
while (states.size() <= position) {
states.add(null);
}
}
private String getName(int position) {
Path screen = getItem(position);
return String.format("%s_%d", screen.getClass().getName(), position);
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view.equals(object);
}
}
@Zhuinden
Copy link

Zhuinden commented May 13, 2017

You should set the class loader on the bundle, otherwise you risk getting BadParcelException

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