jenkins-bot has submitted this change and it was merged.
Change subject: Keep only a limited number of WebViews in memory.
......................................................................
Keep only a limited number of WebViews in memory.
(scroll position to be implemented in next patch)
Bug: 64450
Change-Id: I768e2dcae18924d78253fad66bfaa83b8447d94a
---
M wikipedia/res/layout/activity_main.xml
A
wikipedia/src/main/java/android/support/v4/app/FixedFragmentStatePagerAdapter.java
A wikipedia/src/main/java/org/wikipedia/page/BackStack.java
A wikipedia/src/main/java/org/wikipedia/page/BackStackItem.java
M wikipedia/src/main/java/org/wikipedia/page/PageActivity.java
A wikipedia/src/main/java/org/wikipedia/page/PageFragmentAdapter.java
A wikipedia/src/main/java/org/wikipedia/page/PageFragmentPager.java
M wikipedia/src/main/java/org/wikipedia/page/PageViewFragment.java
8 files changed, 525 insertions(+), 50 deletions(-)
Approvals:
Yuvipanda: Looks good to me, approved
jenkins-bot: Verified
diff --git a/wikipedia/res/layout/activity_main.xml
b/wikipedia/res/layout/activity_main.xml
index 7a767b2..4a70937 100644
--- a/wikipedia/res/layout/activity_main.xml
+++ b/wikipedia/res/layout/activity_main.xml
@@ -7,11 +7,10 @@
android:saveEnabled="false"
android:layout_height="match_parent">
<!-- The main content view -->
- <FrameLayout
- android:id="@+id/content_frame"
+ <org.wikipedia.page.PageFragmentPager
+ android:id="@+id/content_pager"
android:layout_width="match_parent"
- android:layout_height="match_parent">
- </FrameLayout>
+ android:layout_height="match_parent" />
<!-- The navigation drawer -->
<!-- Don't set marginTop here, it somehow also affects marginBottom.
wtf?! -->
<fragment android:layout_width="288dp"
android:layout_height="match_parent"
diff --git
a/wikipedia/src/main/java/android/support/v4/app/FixedFragmentStatePagerAdapter.java
b/wikipedia/src/main/java/android/support/v4/app/FixedFragmentStatePagerAdapter.java
new file mode 100644
index 0000000..eebd065
--- /dev/null
+++
b/wikipedia/src/main/java/android/support/v4/app/FixedFragmentStatePagerAdapter.java
@@ -0,0 +1,28 @@
+package android.support.v4.app;
+
+import android.os.Bundle;
+import android.view.ViewGroup;
+
+/**
+ * TODO: Remove this class when Google updates the Support library.
+ * This solves an intermittent crash when using FragmentStatePagerAdapter.
+ *
+ * Android bug: https://code.google.com/p/android/issues/detail?id=37484
+ */
+public abstract class FixedFragmentStatePagerAdapter extends
FragmentStatePagerAdapter {
+
+ public FixedFragmentStatePagerAdapter(FragmentManager fm) {
+ super(fm);
+ }
+
+ @Override
+ public Object instantiateItem(ViewGroup container, int position) {
+ Fragment f = (Fragment) super.instantiateItem(container, position);
+ Bundle savedFragmentState = f.mSavedFragmentState;
+ if (savedFragmentState != null) {
+ savedFragmentState.setClassLoader(f.getClass().getClassLoader());
+ }
+ return f;
+ }
+
+}
diff --git a/wikipedia/src/main/java/org/wikipedia/page/BackStack.java
b/wikipedia/src/main/java/org/wikipedia/page/BackStack.java
new file mode 100644
index 0000000..fb36074
--- /dev/null
+++ b/wikipedia/src/main/java/org/wikipedia/page/BackStack.java
@@ -0,0 +1,47 @@
+package org.wikipedia.page;
+
+import android.os.*;
+import java.util.*;
+
+public class BackStack implements Parcelable {
+
+ private ArrayList<BackStackItem> backStack;
+
+ public ArrayList<BackStackItem> getStack() {
+ return backStack;
+ }
+
+ public int size() {
+ return backStack.size();
+ }
+
+ public BackStack() {
+ backStack = new ArrayList<BackStackItem>();
+ }
+
+ public BackStack(Parcel in) {
+ backStack = in.readArrayList(BackStackItem.class.getClassLoader());
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeList(backStack);
+ }
+
+ public static final Parcelable.Creator<BackStack> CREATOR
+ = new Parcelable.Creator<BackStack>() {
+ public BackStack createFromParcel(Parcel in) {
+ return new BackStack(in);
+ }
+
+ public BackStack[] newArray(int size) {
+ return new BackStack[size];
+ }
+ };
+
+}
\ No newline at end of file
diff --git a/wikipedia/src/main/java/org/wikipedia/page/BackStackItem.java
b/wikipedia/src/main/java/org/wikipedia/page/BackStackItem.java
new file mode 100644
index 0000000..12c99f1
--- /dev/null
+++ b/wikipedia/src/main/java/org/wikipedia/page/BackStackItem.java
@@ -0,0 +1,47 @@
+package org.wikipedia.page;
+
+import android.os.*;
+import org.wikipedia.*;
+import org.wikipedia.history.*;
+
+public class BackStackItem implements Parcelable {
+ public final PageTitle title;
+ public final HistoryEntry historyEntry;
+ public final int scrollPosition;
+
+ public BackStackItem(PageTitle title, HistoryEntry historyEntry, int
scrollPosition) {
+ this.title = title;
+ this.historyEntry = historyEntry;
+ this.scrollPosition = scrollPosition;
+ }
+
+ public BackStackItem(Parcel in) {
+ title = in.readParcelable(PageTitle.class.getClassLoader());
+ historyEntry = in.readParcelable(HistoryEntry.class.getClassLoader());
+ scrollPosition = in.readInt();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeParcelable(title, flags);
+ parcel.writeParcelable(historyEntry, flags);
+ parcel.writeInt(scrollPosition);
+ }
+
+ public static final Parcelable.Creator<BackStackItem> CREATOR
+ = new Parcelable.Creator<BackStackItem>() {
+ public BackStackItem createFromParcel(Parcel in) {
+ return new BackStackItem(in);
+ }
+
+ public BackStackItem[] newArray(int size) {
+ return new BackStackItem[size];
+ }
+ };
+
+}
diff --git a/wikipedia/src/main/java/org/wikipedia/page/PageActivity.java
b/wikipedia/src/main/java/org/wikipedia/page/PageActivity.java
index a7636d6..f2a6cbc 100644
--- a/wikipedia/src/main/java/org/wikipedia/page/PageActivity.java
+++ b/wikipedia/src/main/java/org/wikipedia/page/PageActivity.java
@@ -1,11 +1,12 @@
package org.wikipedia.page;
-import android.app.*;
+import android.app.ActivityManager;
+import android.app.AlertDialog;
import android.content.*;
import android.net.*;
import android.os.*;
import android.preference.*;
-import android.support.v4.widget.*;
+import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.*;
import android.util.*;
import android.view.*;
@@ -13,9 +14,11 @@
import de.keyboardsurfer.android.widget.crouton.*;
import org.wikipedia.*;
import org.wikipedia.analytics.*;
+import org.wikipedia.concurrency.SaneAsyncTask;
import org.wikipedia.events.*;
import org.wikipedia.history.*;
import org.wikipedia.interlanguage.*;
+import org.wikipedia.pageimages.PageImageSaveTask;
import org.wikipedia.recurring.*;
import org.wikipedia.search.*;
import org.wikipedia.settings.*;
@@ -31,10 +34,22 @@
private Bus bus;
private WikipediaApp app;
- private SearchArticlesFragment searchAriclesFragment;
+ private SearchArticlesFragment searchArticlesFragment;
private DrawerLayout drawerLayout;
+ /**
+ * Container that will hold our WebViews, and animate between them.
+ */
+ private PageFragmentPager fragmentPager;
+
private PageViewFragment curPageFragment;
+
+ private PageFragmentAdapter fragmentAdapter;
+
+ /**
+ * Lightweight back-stack of history items
+ */
+ private BackStack backStack;
private boolean pausedStateOfZero;
private String pausedXcsOfZero;
@@ -54,9 +69,11 @@
if (savedInstanceState != null) {
pausedStateOfZero =
savedInstanceState.getBoolean("pausedStateOfZero");
pausedXcsOfZero = savedInstanceState.getString("pausedXcsOfZero");
- if (savedInstanceState.containsKey("curPageFragment")) {
- curPageFragment = (PageViewFragment)
getSupportFragmentManager().getFragment(savedInstanceState, "curPageFragment");
+ if (savedInstanceState.containsKey("backStack")) {
+ backStack = savedInstanceState.getParcelable("backStack");
}
+ } else {
+ backStack = new BackStack();
}
bus = app.getBus();
@@ -64,10 +81,22 @@
readingActionFunnel = new ReadingActionFunnel(app);
- searchAriclesFragment = (SearchArticlesFragment)
getSupportFragmentManager().findFragmentById(R.id.search_fragment);
+ searchArticlesFragment = (SearchArticlesFragment)
getSupportFragmentManager().findFragmentById(R.id.search_fragment);
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
- searchAriclesFragment.setDrawerLayout(drawerLayout);
+ searchArticlesFragment.setDrawerLayout(drawerLayout);
+
+ fragmentPager = (PageFragmentPager) findViewById(R.id.content_pager);
+ // disable the default swipe motion to flip pages (we'll be doing it
programmatically)
+ fragmentPager.setPagingEnabled(false);
+
+ fragmentAdapter = new PageFragmentAdapter(getSupportFragmentManager(),
backStack);
+ fragmentPager.setAdapter(fragmentAdapter);
+
+ // Set the maximum number of fragments that will be kept in memory.
+ // Old Fragments will be automatically destroyed, but their state will
be saved,
+ // so when the user goes back, they will be recreated.
+ fragmentPager.setOffscreenPageLimit(calculateMaxFragments());
if (savedInstanceState == null) {
// Don't do this if we are just rotating the phone
@@ -92,7 +121,25 @@
new RecurringTasksExecutor(this).run();
}
- private void displayNewPage(PageTitle title, HistoryEntry entry) {
+ private int calculateMaxFragments() {
+ // calculate the maximum number of WebViews to keep in memory, based
on VM size
+ ActivityManager activityManager =
(ActivityManager)getApplicationContext().getSystemService(ACTIVITY_SERVICE);
+ int memMegs = activityManager.getMemoryClass();
+ // allow up to 7MB for the app itself, 3 MB for spikes by WebView
allocations,
+ // and 2 MB for each WebView stored in memory.
+ int maxFragments = (memMegs - 7 - 3) / 2;
+ if (maxFragments <= 0) {
+ // make sure there's at least one, for really low-memory devices.
+ maxFragments = 1;
+ } else if (maxFragments > 6) {
+ // more than this will probably break rendering.
+ maxFragments = 6;
+ }
+ Log.d("PageActivity", "Maximum Fragments in memory: " + maxFragments);
+ return maxFragments;
+ }
+
+ private void displayNewPage(final PageTitle title, final HistoryEntry
entry) {
readingActionFunnel.logSomethingHappened(title.getSite());
if (drawerLayout.isDrawerOpen(Gravity.START)) {
drawerLayout.closeDrawer(Gravity.START);
@@ -101,17 +148,56 @@
Utils.visitInExternalBrowser(this,
Uri.parse(title.getMobileUri()));
return;
}
- PageViewFragment pageFragment = new PageViewFragment(title, entry,
R.id.search_fragment);
- getSupportFragmentManager().beginTransaction()
- .setCustomAnimations(R.anim.slide_in_right,
R.anim.slide_out_left, R.anim.slide_in_left, R.anim.slide_out_right)
- .add(R.id.content_frame, pageFragment, title.getCanonicalUri())
- .addToBackStack(title.getCanonicalUri())
- .commit();
- if (curPageFragment != null) {
- curPageFragment.hide();
+ // Add history entry now
+ new HistorySaveTask(entry).execute();
+ // Save image for this page title
+ new PageImageSaveTask(app, app.getAPIForSite(title.getSite()),
title).execute();
+
+ // animate the new fragment into place
+ // then hide the previous fragment.
+ final PageViewFragment prevFragment = curPageFragment;
+ fragmentPager.setOnAnimationListener(new
PageFragmentPager.OnAnimationListener() {
+ @Override
+ public void OnAnimationFinished() {
+ if (prevFragment != null) {
+ prevFragment.hide();
+ }
+ fragmentPager.setOnAnimationListener(null);
+ }
+ });
+
+ backStack.getStack().add(new BackStackItem(title, entry, 0));
+
+ fragmentAdapter.notifyDataSetChanged();
+ fragmentPager.setCurrentItem(backStack.size() - 1);
+
+ curPageFragment =
(PageViewFragment)fragmentAdapter.getItem(fragmentPager.getCurrentItem());
+
+ Log.d("PageActivity", "pageBackStack has " + backStack.size() + "
items");
+ }
+
+ /**
+ * Saving a history item needs to be in its own task, since the operation
may
+ * actually block for several seconds, and should not be on the main
thread.
+ */
+ private class HistorySaveTask extends SaneAsyncTask<Void> {
+ private final HistoryEntry entry;
+ public HistorySaveTask(HistoryEntry entry) {
+ super(SINGLE_THREAD);
+ this.entry = entry;
}
- curPageFragment = pageFragment;
+
+ @Override
+ public Void performTask() throws Throwable {
+ app.getPersister(HistoryEntry.class).persist(entry);
+ return null;
+ }
+
+ @Override
+ public void onCatch(Throwable caught) {
+ Log.d("HistorySaveTask", caught.getMessage());
+ }
}
@Subscribe
@@ -162,18 +248,35 @@
drawerLayout.closeDrawer(Gravity.START);
return;
}
- if (!searchAriclesFragment.handleBackPressed()
+ if (!searchArticlesFragment.handleBackPressed()
&& !(curPageFragment != null &&
curPageFragment.handleBackPressed())) {
- if (getSupportFragmentManager().getBackStackEntryCount() <= 1) {
+ if (backStack.size() <= 1) {
// Everything we could pop has been popped....
finish();
} else {
- getSupportFragmentManager().popBackStackImmediate();
- String tag =
getSupportFragmentManager().getBackStackEntryAt(getSupportFragmentManager().getBackStackEntryCount()
- 1).getName();
- curPageFragment = (PageViewFragment)
getSupportFragmentManager().findFragmentByTag(tag);
+
+ // don't do anything if we're in the middle of an animation
(looks better)
+ if (fragmentPager.isAnimating()) {
+ return;
+ }
+
+ // let the Pager finish its animation, then remove the
fragment that was moved off.
+ fragmentPager.setOnAnimationListener(new
PageFragmentPager.OnAnimationListener() {
+ @Override
+ public void OnAnimationFinished() {
+ fragmentAdapter.removeFragment(backStack.size() - 1);
+
+ fragmentAdapter.notifyDataSetChanged();
+ fragmentPager.setOnAnimationListener(null);
+ }
+ });
+
+ fragmentPager.setCurrentItem(fragmentPager.getCurrentItem() -
1);
+ curPageFragment =
fragmentAdapter.getFragmentAt(fragmentPager.getCurrentItem());
curPageFragment.show();
- searchAriclesFragment.clearErrors();
- searchAriclesFragment.ensureVisible();
+
+ searchArticlesFragment.clearErrors();
+ searchArticlesFragment.ensureVisible();
}
}
}
@@ -274,13 +377,19 @@
@Override
protected void onResume() {
super.onResume();
- boolean latestWikipediaZeroDispostion =
WikipediaApp.getWikipediaZeroDisposition();
- if (WikipediaApp.isWikipediaZeroDevmodeOn() && pausedStateOfZero &&
!latestWikipediaZeroDispostion) {
+ boolean latestWikipediaZeroDisposition =
WikipediaApp.getWikipediaZeroDisposition();
+ if (WikipediaApp.isWikipediaZeroDevmodeOn() && pausedStateOfZero &&
!latestWikipediaZeroDisposition) {
bus.post(new WikipediaZeroStateChangeEvent());
}
+ fragmentAdapter.onResume(this);
if (curPageFragment != null) {
//refresh the current fragment's state (ensures correct state of
overflow menu)
curPageFragment.show();
+ }
+ // if we're just being resumed from a saved state, then sync
curPageFragment
+ // with the correct item in the pager.
+ if (curPageFragment == null && fragmentAdapter.getCount() > 0) {
+ curPageFragment =
(PageViewFragment)fragmentAdapter.getItem(fragmentPager.getCurrentItem());
}
}
@@ -296,9 +405,7 @@
super.onSaveInstanceState(outState);
outState.putBoolean("pausedStateOfZero", pausedStateOfZero);
outState.putString("pausedXcsOfZero", pausedXcsOfZero);
- if (curPageFragment != null) {
- getSupportFragmentManager().putFragment(outState,
"curPageFragment", curPageFragment);
- }
+ outState.putParcelable("backStack", backStack);
}
@Override
diff --git
a/wikipedia/src/main/java/org/wikipedia/page/PageFragmentAdapter.java
b/wikipedia/src/main/java/org/wikipedia/page/PageFragmentAdapter.java
new file mode 100644
index 0000000..f8e7acf
--- /dev/null
+++ b/wikipedia/src/main/java/org/wikipedia/page/PageFragmentAdapter.java
@@ -0,0 +1,93 @@
+package org.wikipedia.page;
+
+import android.support.v4.app.*;
+import android.util.*;
+import android.view.*;
+import org.wikipedia.R;
+import java.util.List;
+
+public class PageFragmentAdapter extends FixedFragmentStatePagerAdapter {
+ private SparseArray<PageViewFragment> fragmentArray;
+ private BackStack backStack;
+
+ public PageFragmentAdapter(FragmentManager fm, BackStack backStack) {
+ super(fm);
+ this.backStack = backStack;
+ fragmentArray = new SparseArray<PageViewFragment>();
+ }
+
+ @Override
+ public Fragment getItem(int position) {
+ PageViewFragment f = fragmentArray.get(position);
+ if (f == null) {
+ f = new PageViewFragment(position,
+ backStack.getStack().get(position).title,
+ backStack.getStack().get(position).historyEntry,
+ R.id.search_fragment);
+
+ fragmentArray.put(position, f);
+ }
+ return f;
+ }
+
+ public PageViewFragment getFragmentAt(int position) {
+ return fragmentArray.get(position);
+ }
+
+ @Override
+ public int getCount() {
+ return backStack.size();
+ }
+
+ @Override
+ public void notifyDataSetChanged() {
+ super.notifyDataSetChanged();
+ }
+
+ @Override
+ public CharSequence getPageTitle(int position) {
+ return fragmentArray.get(position).getTitle().getDisplayText();
+ }
+
+ /**
+ * Remove the specified fragment without saving its state.
+ * @param position Position at which to remove the fragment.
+ */
+ public void removeFragment(int position) {
+ PageViewFragment fragment = fragmentArray.get(position);
+ fragment.setSaveState(PageViewFragment.SAVE_STATE_NONE);
+ fragmentArray.delete(position);
+ backStack.getStack().remove(position);
+ }
+
+ @Override
+ public void destroyItem(ViewGroup container, int position, Object object) {
+ PageViewFragment fragment = fragmentArray.get(position);
+ if (fragment != null) {
+ fragment.setSaveState(PageViewFragment.SAVE_STATE_TITLE);
+ }
+ super.destroyItem(container, position, object);
+ }
+
+ @Override
+ public int getItemPosition(Object item) {
+ if (fragmentArray.indexOfValue((PageViewFragment) item) == -1) {
+ return FragmentStatePagerAdapter.POSITION_NONE;
+ }
+ return FragmentStatePagerAdapter.POSITION_UNCHANGED;
+ }
+
+ /**
+ * Rebuilds this adapter's inner catalog of Fragments, useful for when
+ * the activity is restored from a saved state.
+ * @param activity Calling activity.
+ */
+ public void onResume(PageActivity activity) {
+ List<Fragment> fragments =
activity.getSupportFragmentManager().getFragments();
+ for (Fragment f : fragments) {
+ if (f instanceof PageViewFragment) {
+ fragmentArray.put(((PageViewFragment) f).getPagerIndex(),
(PageViewFragment)f);
+ }
+ }
+ }
+}
diff --git a/wikipedia/src/main/java/org/wikipedia/page/PageFragmentPager.java
b/wikipedia/src/main/java/org/wikipedia/page/PageFragmentPager.java
new file mode 100644
index 0000000..403f7e7
--- /dev/null
+++ b/wikipedia/src/main/java/org/wikipedia/page/PageFragmentPager.java
@@ -0,0 +1,79 @@
+package org.wikipedia.page;
+
+import android.content.*;
+import android.support.v4.view.ViewPager;
+import android.util.*;
+import android.view.MotionEvent;
+
+public class PageFragmentPager extends ViewPager {
+
+ private boolean isPagingEnabled = true;
+ private OnAnimationListener onAnimationListener;
+ private boolean isAnimating = false;
+
+ public PageFragmentPager(Context context) {
+ super(context);
+ this.setOnPageChangeListener(new FragmentPagerListener());
+ }
+
+ public PageFragmentPager(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ this.setOnPageChangeListener(new FragmentPagerListener());
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (this.isPagingEnabled) {
+ return super.onTouchEvent(event);
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent event) {
+ if (this.isPagingEnabled) {
+ return super.onInterceptTouchEvent(event);
+ }
+ return false;
+ }
+
+ public void setPagingEnabled(boolean b) {
+ this.isPagingEnabled = b;
+ }
+
+ private class FragmentPagerListener implements
ViewPager.OnPageChangeListener {
+ @Override
+ public void onPageScrolled(int position, float positionOffset, int
positionPixels) {
+ }
+ private boolean pageChanged = false;
+ @Override
+ public void onPageSelected(int position) {
+ pageChanged = true;
+ }
+ @Override
+ public void onPageScrollStateChanged(int state) {
+ if (state == ViewPager.SCROLL_STATE_IDLE) {
+ isAnimating = false;
+ if (pageChanged) {
+ if (onAnimationListener != null) {
+ onAnimationListener.OnAnimationFinished();
+ }
+ }
+ } else {
+ isAnimating = true;
+ }
+ }
+ }
+
+ public boolean isAnimating() {
+ return isAnimating;
+ }
+
+ public interface OnAnimationListener {
+ public void OnAnimationFinished();
+ }
+
+ public void setOnAnimationListener(OnAnimationListener listener) {
+ onAnimationListener = listener;
+ }
+}
\ No newline at end of file
diff --git a/wikipedia/src/main/java/org/wikipedia/page/PageViewFragment.java
b/wikipedia/src/main/java/org/wikipedia/page/PageViewFragment.java
index 55196ee..65f2a80 100644
--- a/wikipedia/src/main/java/org/wikipedia/page/PageViewFragment.java
+++ b/wikipedia/src/main/java/org/wikipedia/page/PageViewFragment.java
@@ -27,12 +27,46 @@
private static final String KEY_SCROLL_Y = "scrollY";
private static final String KEY_CURRENT_HISTORY_ENTRY =
"currentHistoryEntry";
private static final String KEY_QUICK_RETURN_BAR_ID = "quickReturnBarId";
+ private static final String KEY_PAGER_INDEX = "pagerIndex";
public static final int STATE_NO_FETCH = 1;
public static final int STATE_INITIAL_FETCH = 2;
public static final int STATE_COMPLETE_FETCH = 3;
private int state = STATE_NO_FETCH;
+
+ /**
+ * Indicates that the full state of this fragment will be saved when
onSaveInstanceState
+ * is called, including the heavy Page object that contains the full page
text. This is good
+ * when the fragment is destroyed due to the activity being closed.
+ */
+ public static final int SAVE_STATE_FULL = 0;
+
+ /**
+ * Indicates that only a partial state of this fragment will be saved when
onSaveInstanceState
+ * is called, including the Title, HistoryItem, and scroll position. This
is used when the
+ * fragment is destroyed by the ViewPager when the user slides it out of
sight. The next time
+ * the fragment is recreated, we'll fetch the page contents from the
network again.
+ */
+ public static final int SAVE_STATE_TITLE = 1;
+
+ /**
+ * Indicates that none of this fragment's state will be saved when
onSaveInstanceState
+ * is called. This is used when the fragment is destroyed due to the user
going "back"
+ * in the ViewPager.
+ */
+ public static final int SAVE_STATE_NONE = 2;
+
+ /**
+ * Determines how much of this fragment's state will be saved when it's
destroyed.
+ * (when onSaveInstanceState is called)
+ */
+ private int saveState = SAVE_STATE_FULL;
+
+ /**
+ * Stores this fragment's position in the ViewPager in the parent activity.
+ */
+ private int pagerIndex;
private PageTitle title;
private ObservableWebView webView;
@@ -41,7 +75,7 @@
private View retryButton;
private View pageDoesNotExistError;
private DisableableDrawerLayout tocDrawer;
- private FrameLayout pageFragmentContainer;
+ private View pageFragmentContainer;
private Page page;
private HistoryEntry curEntry;
@@ -61,7 +95,8 @@
private ReadingActionFunnel readingActionFunnel;
// Pass in the id rather than the View object itself for the quickReturn
bar, to help it survive rotates
- public PageViewFragment(PageTitle title, HistoryEntry historyEntry, int
quickReturnBarId) {
+ public PageViewFragment(int pagerIndex, PageTitle title, HistoryEntry
historyEntry, int quickReturnBarId) {
+ this.pagerIndex = pagerIndex;
this.title = title;
this.curEntry = historyEntry;
this.quickReturnBarId = quickReturnBarId;
@@ -78,12 +113,41 @@
return page;
}
+ public HistoryEntry getHistoryEntry() {
+ return curEntry;
+ }
+
+ public int getScrollY() {
+ if (webView != null) {
+ scrollY = webView.getScrollY();
+ }
+ return scrollY;
+ }
+
+ public void setScrollY(int scrollY) {
+ this.scrollY = scrollY;
+ if (webView != null) {
+ webView.scrollTo(0, scrollY);
+ }
+ }
+
+ public void setSaveState(int saveState) {
+ this.saveState = saveState;
+ }
+
+ public int getPagerIndex() {
+ return pagerIndex;
+ }
+
/*
Hide the entire fragment. This is necessary when displaying a new page
fragment on top
of a previous one -- some devices have issues with rendering "heavy"
components
(like WebView) when overlaid on top of many other Views.
*/
public void hide() {
+ if (pageFragmentContainer == null) {
+ return;
+ }
pageFragmentContainer.setVisibility(View.GONE);
}
@@ -92,6 +156,9 @@
stack of fragments
*/
public void show() {
+ if (pageFragmentContainer == null) {
+ return;
+ }
pageFragmentContainer.setVisibility(View.VISIBLE);
//refresh the fragment's state (ensures correct state of overflow menu)
setState(state);
@@ -126,12 +193,17 @@
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
- outState.putParcelable(KEY_TITLE, title);
- outState.putParcelable(KEY_PAGE, page);
- outState.putInt(KEY_STATE, state);
- outState.putInt(KEY_SCROLL_Y, webView.getScrollY());
- outState.putParcelable(KEY_CURRENT_HISTORY_ENTRY, curEntry);
- outState.putInt(KEY_QUICK_RETURN_BAR_ID, quickReturnBarId);
+ if (saveState != SAVE_STATE_NONE) {
+ outState.putInt(KEY_PAGER_INDEX, pagerIndex);
+ outState.putParcelable(KEY_TITLE, title);
+ outState.putInt(KEY_SCROLL_Y, webView.getScrollY());
+ outState.putParcelable(KEY_CURRENT_HISTORY_ENTRY, curEntry);
+ outState.putInt(KEY_QUICK_RETURN_BAR_ID, quickReturnBarId);
+ if (saveState == SAVE_STATE_FULL) {
+ outState.putParcelable(KEY_PAGE, page);
+ outState.putInt(KEY_STATE, state);
+ }
+ }
}
@Override
@@ -144,13 +216,14 @@
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null &&
savedInstanceState.containsKey(KEY_TITLE)) {
title = savedInstanceState.getParcelable(KEY_TITLE);
+ curEntry =
savedInstanceState.getParcelable(KEY_CURRENT_HISTORY_ENTRY);
+ scrollY = savedInstanceState.getInt(KEY_SCROLL_Y);
+ quickReturnBarId =
savedInstanceState.getInt(KEY_QUICK_RETURN_BAR_ID);
+ pagerIndex = savedInstanceState.getInt(KEY_PAGER_INDEX);
if (savedInstanceState.containsKey(KEY_PAGE)) {
page = savedInstanceState.getParcelable(KEY_PAGE);
+ state = savedInstanceState.getInt(KEY_STATE);
}
- state = savedInstanceState.getInt(KEY_STATE);
- scrollY = savedInstanceState.getInt(KEY_SCROLL_Y);
- curEntry =
savedInstanceState.getParcelable(KEY_CURRENT_HISTORY_ENTRY);
- quickReturnBarId =
savedInstanceState.getInt(KEY_QUICK_RETURN_BAR_ID);
}
if (title == null) {
throw new RuntimeException("No PageTitle passed in to constructor
or in instanceState");
@@ -158,7 +231,7 @@
app = (WikipediaApp)getActivity().getApplicationContext();
- pageFragmentContainer = (FrameLayout)
getView().findViewById(R.id.page_fragment_container);
+ pageFragmentContainer =
getView().findViewById(R.id.page_fragment_container);
webView = (ObservableWebView)
getView().findViewById(R.id.page_web_view);
loadProgress = (ProgressBar)
getView().findViewById(R.id.page_load_progress);
networkError = getView().findViewById(R.id.page_error);
@@ -319,10 +392,6 @@
displayLeadSection();
setState(STATE_INITIAL_FETCH);
new RestSectionsFetchTask().execute();
-
- // Add history entry now
- app.getPersister(HistoryEntry.class).persist(curEntry);
- new PageImageSaveTask(app, api, title).execute();
}
@Override
@@ -390,4 +459,10 @@
}
return false;
}
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ Log.d("PageViewFragment", "Fragment destroyed.");
+ }
}
--
To view, visit https://gerrit.wikimedia.org/r/134083
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I768e2dcae18924d78253fad66bfaa83b8447d94a
Gerrit-PatchSet: 15
Gerrit-Project: apps/android/wikipedia
Gerrit-Branch: master
Gerrit-Owner: Dbrant <[email protected]>
Gerrit-Reviewer: BearND <[email protected]>
Gerrit-Reviewer: Brion VIBBER <[email protected]>
Gerrit-Reviewer: Yuvipanda <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits