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

Reply via email to