Dbrant has uploaded a new change for review.
https://gerrit.wikimedia.org/r/134083
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
M wikipedia/src/main/java/org/wikipedia/page/PageActivity.java
M wikipedia/src/main/java/org/wikipedia/page/PageViewFragment.java
3 files changed, 175 insertions(+), 17 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/apps/android/wikipedia
refs/changes/83/134083/1
diff --git a/wikipedia/res/layout/activity_main.xml
b/wikipedia/res/layout/activity_main.xml
index 7a767b2..53faa33 100644
--- a/wikipedia/res/layout/activity_main.xml
+++ b/wikipedia/res/layout/activity_main.xml
@@ -7,11 +7,11 @@
android:saveEnabled="false"
android:layout_height="match_parent">
<!-- The main content view -->
- <FrameLayout
- android:id="@+id/content_frame"
+ <ViewAnimator
+ android:id="@+id/content_animator"
android:layout_width="match_parent"
android:layout_height="match_parent">
- </FrameLayout>
+ </ViewAnimator>
<!-- 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/org/wikipedia/page/PageActivity.java
b/wikipedia/src/main/java/org/wikipedia/page/PageActivity.java
index b8e7bda..418da5a 100644
--- a/wikipedia/src/main/java/org/wikipedia/page/PageActivity.java
+++ b/wikipedia/src/main/java/org/wikipedia/page/PageActivity.java
@@ -1,14 +1,18 @@
package org.wikipedia.page;
-import android.app.*;
+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.app.FragmentTransaction;
+import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.*;
import android.util.*;
import android.view.*;
+import android.view.animation.Animation;
+import android.widget.FrameLayout;
+import android.widget.ViewAnimator;
import com.squareup.otto.*;
import de.keyboardsurfer.android.widget.crouton.*;
import org.wikipedia.*;
@@ -21,6 +25,8 @@
import org.wikipedia.settings.*;
import org.wikipedia.staticdata.*;
+import java.util.*;
+
public class PageActivity extends ActionBarActivity {
public static final String ACTION_PAGE_FOR_TITLE =
"org.wikipedia.page_for_title";
public static final String EXTRA_PAGETITLE = "org.wikipedia.pagetitle";
@@ -28,13 +34,46 @@
private static final String ZERO_ON_NOTICE_PRESENTED =
"org.wikipedia.zero.zeroOnNoticePresented";
private static final String ZERO_OFF_NOTICE_PRESENTED =
"org.wikipedia.zero.zeroOffNoticePresented";
+ /**
+ * Maximum number of WebViews that may be on top of each other at any
given time.
+ */
+ private static final int MAX_WEBVIEW_COUNT = 4;
+
private Bus bus;
private WikipediaApp app;
private SearchArticlesFragment searchAriclesFragment;
private DrawerLayout drawerLayout;
+ /**
+ * Container that will hold our WebViews, and animate between them.
+ */
+ private ViewAnimator pageAnimator;
+
private PageViewFragment curPageFragment;
+
+ /**
+ * Resource ID, to be incremented and assigned to each new dynamically
generated
+ * fragment container, since it seems that a fragment can only be "add"ed
to an id,
+ * and not a dynamic View.
+ */
+ private int fragmentViewId = 0;
+
+ /**
+ * Back-stack of lightweight history items that will be used for
recreating PageViewFragments.
+ */
+ private Stack<BackStackItem> pageBackStack;
+
+ private class BackStackItem {
+ 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;
+ }
+ }
private boolean pausedStateOfZero;
private String pausedXcsOfZero;
@@ -69,6 +108,9 @@
searchAriclesFragment.setDrawerLayout(drawerLayout);
+ pageAnimator = (ViewAnimator) findViewById(R.id.content_animator);
+ pageBackStack = new Stack<BackStackItem>();
+
if (savedInstanceState == null) {
// Don't do this if we are just rotating the phone
Intent intent = getIntent();
@@ -101,17 +143,61 @@
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();
+ pageBackStack.push(new BackStackItem(curPageFragment.getTitle(),
+ curPageFragment.getHistoryEntry(),
+ curPageFragment.getScrollY()));
}
- curPageFragment = pageFragment;
+
+ // create an empty View to which the new Fragment will be bound
+ FrameLayout fragmentContainer = new FrameLayout(this);
+ fragmentContainer.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ fragmentContainer.setId(++fragmentViewId);
+
+ final PageViewFragment pageFragment = new PageViewFragment(title,
entry, R.id.search_fragment);
+ fragmentContainer.setTag(pageFragment);
+
+ FragmentTransaction trans =
getSupportFragmentManager().beginTransaction();
+ trans.add(fragmentViewId, pageFragment, title.getCanonicalUri());
+
+ // if there are already MAX_WEBVIEW_COUNT children in the Animator,
then get rid of the oldest one,
+ // and destroy its associated fragment.
+ if (pageAnimator.getChildCount() >= MAX_WEBVIEW_COUNT) {
+ PageViewFragment oldFragment = (PageViewFragment)
pageAnimator.getChildAt(0).getTag();
+ pageAnimator.removeViewAt(0);
+ trans.remove(oldFragment);
+ }
+
+ trans.commit();
+
+ // add the new fragment to the "end" of the Animator
+ pageAnimator.addView(fragmentContainer);
+
+ // animate the new fragment into place
+ // then hide the previous fragment, but only when the animation
finishes.
+ pageAnimator.setInAnimation(this, R.anim.slide_in_right);
+ pageAnimator.getInAnimation().setAnimationListener(new
Animation.AnimationListener() {
+ @Override
+ public void onAnimationStart(Animation animation) {
+ }
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ if (curPageFragment != null) {
+ curPageFragment.hide();
+ }
+ curPageFragment = pageFragment;
+ }
+ @Override
+ public void onAnimationRepeat(Animation animation) {
+ }
+ });
+ pageAnimator.setOutAnimation(this, R.anim.slide_out_left);
+ pageAnimator.showNext();
+
+ Log.d("PageActivity", "pageAnimator has " +
pageAnimator.getChildCount() + " items");
}
@Subscribe
@@ -164,13 +250,67 @@
}
if (!searchAriclesFragment.handleBackPressed()
&& !(curPageFragment != null &&
curPageFragment.handleBackPressed())) {
- if (getSupportFragmentManager().getBackStackEntryCount() <= 1) {
+ if (pageBackStack.size() == 0) {
// 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 (pageAnimator.getOutAnimation() != null &&
!pageAnimator.getOutAnimation().hasEnded()) {
+ return;
+ }
+
+ final PageViewFragment oldFragment = (PageViewFragment)
pageAnimator.getCurrentView().getTag();
+
+ // if there are items in the pageBackStack that are older than
the oldest fragment in the Animator,
+ // then create a new fragment for that page and jam it into
the bottom of the Animator stack.
+ if (pageBackStack.size() >= pageAnimator.getChildCount()) {
+ // create an empty View to which the new Fragment will be
bound
+ FrameLayout fragmentContainer = new
FrameLayout(PageActivity.this);
+ fragmentContainer.setLayoutParams(new
ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ fragmentContainer.setId(++fragmentViewId);
+
+ BackStackItem item =
pageBackStack.get(pageBackStack.size() - pageAnimator.getChildCount());
+
+ PageViewFragment pageFragment = new
PageViewFragment(item.title, item.historyEntry, R.id.search_fragment);
+ pageFragment.setScrollY(item.scrollPosition);
+ getSupportFragmentManager().beginTransaction()
+ .add(fragmentViewId, pageFragment,
item.title.getCanonicalUri())
+ .commit();
+
+ fragmentContainer.setTag(pageFragment);
+ pageAnimator.addView(fragmentContainer, 0);
+ }
+
+ pageBackStack.pop();
+
+ // animate the fragment that's currently on top away from
sight.
+ // at the end of the animation, destroy the fragment!
+ pageAnimator.setInAnimation(this, R.anim.slide_in_left);
+ pageAnimator.setOutAnimation(this, R.anim.slide_out_right);
+ pageAnimator.getOutAnimation().setAnimationListener(new
Animation.AnimationListener() {
+ @Override
+ public void onAnimationStart(Animation animation) {
+ }
+ @Override
+ public void onAnimationEnd(Animation animation) {
+
+ getSupportFragmentManager().beginTransaction()
+ .remove(oldFragment)
+ .commit();
+
+ pageAnimator.removeViewAt(pageAnimator.getChildCount()
- 1);
+ }
+ @Override
+ public void onAnimationRepeat(Animation animation) {
+ }
+ });
+
+ pageAnimator.showPrevious();
+ curPageFragment = (PageViewFragment)
pageAnimator.getCurrentView().getTag();
+
curPageFragment.show();
searchAriclesFragment.ensureVisible();
}
diff --git a/wikipedia/src/main/java/org/wikipedia/page/PageViewFragment.java
b/wikipedia/src/main/java/org/wikipedia/page/PageViewFragment.java
index 3bb2ce7..af0b985 100644
--- a/wikipedia/src/main/java/org/wikipedia/page/PageViewFragment.java
+++ b/wikipedia/src/main/java/org/wikipedia/page/PageViewFragment.java
@@ -78,6 +78,24 @@
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);
+ }
+ }
+
/*
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
--
To view, visit https://gerrit.wikimedia.org/r/134083
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I768e2dcae18924d78253fad66bfaa83b8447d94a
Gerrit-PatchSet: 1
Gerrit-Project: apps/android/wikipedia
Gerrit-Branch: master
Gerrit-Owner: Dbrant <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits