Repository: incubator-weex
Updated Branches:
  refs/heads/master a2f1f13a9 -> b582c193b


[android][WEEX-185] Embed Support Auto Memory Manage


Project: http://git-wip-us.apache.org/repos/asf/incubator-weex/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-weex/commit/b582c193
Tree: http://git-wip-us.apache.org/repos/asf/incubator-weex/tree/b582c193
Diff: http://git-wip-us.apache.org/repos/asf/incubator-weex/diff/b582c193

Branch: refs/heads/master
Commit: b582c193b62654568b58eb688fae337d0c6d0f9f
Parents: a2f1f13
Author: jianbai.gbj <jianbai....@alibaba-inc.com>
Authored: Wed Jan 3 17:22:53 2018 +0800
Committer: acton393 <zhangxing610...@gmail.com>
Committed: Thu Jan 18 17:30:26 2018 +0800

----------------------------------------------------------------------
 .../java/com/taobao/weex/WXSDKInstance.java     |  14 ++
 .../java/com/taobao/weex/common/Constants.java  |   4 +
 .../com/taobao/weex/ui/component/WXEmbed.java   | 152 +++++++++++++++++--
 .../taobao/weex/ui/component/WXVContainer.java  |  75 +++++++++
 .../com/taobao/weex/ui/view/WXImageView.java    |   6 +-
 .../weex/ui/component/PriorityQueueTest.java    |  56 +++++++
 6 files changed, 289 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b582c193/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java 
b/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java
index 2c1b47b..9e452b5 100644
--- a/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java
+++ b/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java
@@ -71,6 +71,7 @@ import com.taobao.weex.ui.component.NestedContainer;
 import com.taobao.weex.ui.component.WXBasicComponentType;
 import com.taobao.weex.ui.component.WXComponent;
 import com.taobao.weex.ui.component.WXComponentFactory;
+import com.taobao.weex.ui.component.WXEmbed;
 import com.taobao.weex.ui.flat.FlatGUIContext;
 import com.taobao.weex.ui.view.WXScrollView;
 import com.taobao.weex.ui.view.WXScrollView.WXScrollViewListener;
@@ -89,6 +90,7 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.PriorityQueue;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
@@ -173,6 +175,11 @@ public class WXSDKInstance implements 
IWXActivityStateListener,DomContext, View.
   private ComponentObserver mComponentObserver;
   private boolean mIsCommitedDomAtionExp = false;
 
+  public PriorityQueue<WXEmbed> hiddenEmbeds;
+
+  private int maxHiddenEmbedsNum = -1; //max hidden embed num, -1 standard for 
ulimit
+
+
   public boolean getismIsCommitedDomAtionExp() {
        return mIsCommitedDomAtionExp;
   }
@@ -181,6 +188,13 @@ public class WXSDKInstance implements 
IWXActivityStateListener,DomContext, View.
        this.mIsCommitedDomAtionExp = mIsCommitedDomAtionExp;
   }
 
+  public int getMaxHiddenEmbedsNum() {
+    return maxHiddenEmbedsNum;
+  }
+
+  public void setMaxHiddenEmbedsNum(int maxHiddenEmbedsNum) {
+    this.maxHiddenEmbedsNum = maxHiddenEmbedsNum;
+  }
 
   /**
    * If anchor is created manually(etc. define a layout xml resource ),

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b582c193/android/sdk/src/main/java/com/taobao/weex/common/Constants.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/Constants.java 
b/android/sdk/src/main/java/com/taobao/weex/common/Constants.java
index 3bb91f6..66c4df0 100644
--- a/android/sdk/src/main/java/com/taobao/weex/common/Constants.java
+++ b/android/sdk/src/main/java/com/taobao/weex/common/Constants.java
@@ -195,6 +195,10 @@ public class Constants {
     String OVERFLOW_HIDDEN_HEIGHT = "overflowHiddenHeight";
     String OVERFLOW_HIDDEN_WIDTH = "overflowHiddenWidth";
 
+    String PRIORITY  = "priority";
+
+    String STRATEGY  = "strategy";
+
 
 
 

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b582c193/android/sdk/src/main/java/com/taobao/weex/ui/component/WXEmbed.java
----------------------------------------------------------------------
diff --git 
a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXEmbed.java 
b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXEmbed.java
index 9b95be3..6002a5d 100644
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXEmbed.java
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXEmbed.java
@@ -29,6 +29,7 @@ import android.widget.ImageView;
 
 import com.taobao.weappplus_sdk.R;
 import com.taobao.weex.IWXRenderListener;
+import com.taobao.weex.WXEnvironment;
 import com.taobao.weex.WXRenderErrorCode;
 import com.taobao.weex.WXSDKInstance;
 import com.taobao.weex.annotation.Component;
@@ -39,8 +40,22 @@ import com.taobao.weex.dom.WXDomObject;
 import com.taobao.weex.utils.WXLogUtils;
 import com.taobao.weex.utils.WXUtils;
 import com.taobao.weex.utils.WXViewUtils;
+
+import java.util.Comparator;
+import java.util.PriorityQueue;
+
 @Component(lazyload = false)
-public class WXEmbed extends WXDiv implements 
WXSDKInstance.OnInstanceVisibleListener,NestedContainer {
+public class WXEmbed extends WXDiv implements 
WXSDKInstance.OnInstanceVisibleListener,NestedContainer{
+
+
+  public static final  String STRATEGY_NONE =  "none";
+  public static final  String STRATEGY_NORMAL =  "normal";
+  public static final  String STRATEGY_HIGH =  "high";
+
+
+  public static final  String PRIORITY_LOW =  "low";
+  public static final  String PRIORITY_NORMAL =  "normal";
+  public static final  String PRIORITY_HIGH =  "high";
 
   public static final String ITEM_ID = "itemId";
 
@@ -52,6 +67,13 @@ public class WXEmbed extends WXDiv implements 
WXSDKInstance.OnInstanceVisibleLis
   private boolean mIsVisible = true;
   private EmbedRenderListener mListener;
 
+
+  private String priority = PRIORITY_NORMAL;
+
+  private String strategy = "normal";  //none, normal, high(ignore priority)
+
+  private long hiddenTime;
+
   public interface EmbedManager {
     WXEmbed getEmbed(String itemId);
     void putEmbed(String itemId,WXEmbed comp);
@@ -182,6 +204,8 @@ public class WXEmbed extends WXDiv implements 
WXSDKInstance.OnInstanceVisibleLis
         ((EmbedManager) instance).putEmbed(itemId.toString(), this);
       }
     }
+    this.priority = 
WXUtils.getString(node.getAttrs().get(Constants.Name.PRIORITY), 
PRIORITY_NORMAL);
+    this.strategy = 
WXUtils.getString(node.getAttrs().get(Constants.Name.STRATEGY), STRATEGY_NONE);
   }
 
   @Override
@@ -202,6 +226,12 @@ public class WXEmbed extends WXDiv implements 
WXSDKInstance.OnInstanceVisibleLis
         if (src != null)
           setSrc(src);
         return true;
+      case Constants.Name.PRIORITY:
+        String priority = WXUtils.getString(param,null);
+        if (priority != null){
+           setPriority(priority);
+        }
+        return true;
     }
     return super.setProperty(key, param);
   }
@@ -245,6 +275,15 @@ public class WXEmbed extends WXDiv implements 
WXSDKInstance.OnInstanceVisibleLis
     return src;
   }
 
+
+  @WXComponentProp(name = Constants.Name.PRIORITY)
+  public void setPriority(String priority) {
+       if(TextUtils.isEmpty(priority)){
+         return;
+       }
+       this.priority = priority;
+  }
+
   /**
    * Load embed content, default behavior is create a nested instance.
    */
@@ -258,6 +297,20 @@ public class WXEmbed extends WXDiv implements 
WXSDKInstance.OnInstanceVisibleLis
     }
   }
 
+  private static final int getLevel(WXEmbed embed){
+    String priority = embed.priority;
+    String strategy = embed.strategy;
+    int level  = 5;
+    if(!STRATEGY_HIGH.equals(strategy)) {
+      if (TextUtils.equals(priority, PRIORITY_LOW)) {
+        level = 0;
+      } else if (TextUtils.equals(priority, PRIORITY_HIGH)) {
+        level = 10;
+      }
+    }
+    return  level;
+  }
+
   private WXSDKInstance createInstance() {
     WXSDKInstance sdkInstance = getInstance().createNestedInstance(this);
     getInstance().addOnInstanceVisibleListener(this);
@@ -293,35 +346,85 @@ public class WXEmbed extends WXDiv implements 
WXSDKInstance.OnInstanceVisibleLis
   public void setVisibility(String visibility) {
     super.setVisibility(visibility);
     boolean visible = TextUtils.equals(visibility, Constants.Value.VISIBLE);
-    if (!TextUtils.isEmpty(src) && visible) {
-      if (mNestedInstance == null) {
-        loadContent();
-      } else {
-        mNestedInstance.onViewAppear();
+    if(mIsVisible != visible){
+      
+      if (!TextUtils.isEmpty(src) && visible) {
+        if (mNestedInstance == null) {
+          loadContent();
+        } else {
+          mNestedInstance.onViewAppear();
+        }
       }
-    }
 
-    if (!visible) {
-      if (mNestedInstance != null) {
-        mNestedInstance.onViewDisappear();
+      if (!visible) {
+        if (mNestedInstance != null) {
+          mNestedInstance.onViewDisappear();
+        }
       }
+      mIsVisible = visible;
+      doAutoEmbedMemoryStrategy();
     }
-    mIsVisible = visible;
   }
 
   @Override
   public void destroy() {
     super.destroy();
-    if (mNestedInstance != null) {
-      mNestedInstance.destroy();
-      mNestedInstance = null;
-    }
+    destoryNestInstance();
     src = null;
     if (getInstance() != null) {
       getInstance().removeOnInstanceVisibleListener(this);
     }
   }
 
+
+  private void  doAutoEmbedMemoryStrategy(){
+    /**
+     * auto manage embed amount in current instance, save memory
+     * */
+    if(!STRATEGY_NONE.equals(this.strategy)){
+      if(!mIsVisible && mNestedInstance != null){
+        if(PRIORITY_LOW.equals(this.priority)){
+          destoryNestInstance();
+        }else{
+          if(getInstance().hiddenEmbeds == null){ // low is in front, when 
priority is same, hidden time pre in first
+            getInstance().hiddenEmbeds = new PriorityQueue<>(8, new 
Comparator<WXEmbed>() {
+              @Override
+              public int compare(WXEmbed o1, WXEmbed o2) {
+                int level =  getLevel(o1) - getLevel(o2);
+                if(level != 0){
+                  return  level;
+                }
+                return (int) (o1.hiddenTime - o2.hiddenTime);
+              }
+            });
+          }
+          //getInstance().hiddenEmbeds.remove(this);
+          if(!getInstance().hiddenEmbeds.contains(this)) {
+            this.hiddenTime = System.currentTimeMillis();
+            getInstance().hiddenEmbeds.add(this);
+          }
+          if(getInstance().hiddenEmbeds != null && 
getInstance().getMaxHiddenEmbedsNum() >= 0){
+            while (getInstance().hiddenEmbeds.size() > 
getInstance().getMaxHiddenEmbedsNum()){
+              WXEmbed embed = getInstance().hiddenEmbeds.poll();
+              if(embed.mIsVisible){
+                continue;
+              }
+              if(embed != null) {
+                embed.destoryNestInstance();
+              }
+            }
+          }
+        }
+      }
+      if(mIsVisible && mNestedInstance != null){
+        if(getInstance().hiddenEmbeds != null && 
getInstance().hiddenEmbeds.contains(this)){
+          getInstance().hiddenEmbeds.remove(this);
+        }
+      }
+    }
+
+  }
+
   @Override
   public void onAppear() {
     //appear event from root instance will not trigger visibility change
@@ -381,4 +484,23 @@ public class WXEmbed extends WXDiv implements 
WXSDKInstance.OnInstanceVisibleLis
       mNestedInstance.onActivityDestroy();
     }
   }
+
+  public void setStrategy(String strategy) {
+    this.strategy = strategy;
+  }
+
+  private void destoryNestInstance(){
+    if(getInstance().hiddenEmbeds != null && 
getInstance().hiddenEmbeds.contains(this)){
+        getInstance().hiddenEmbeds.remove(this);
+    }
+    if (mNestedInstance != null) {
+       mNestedInstance.destroy();
+       mNestedInstance = null;
+    }
+    if(WXEnvironment.isApkDebugable()){
+       WXLogUtils.w("WXEmbed destoryNestInstance priority " + priority + " 
index " + getDomObject().getAttrs().get("index")
+        + "  " + hiddenTime  + " embeds size " + (getInstance().hiddenEmbeds 
== null ?  0 : getInstance().hiddenEmbeds.size())
+       + " strategy " + this.strategy);
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b582c193/android/sdk/src/main/java/com/taobao/weex/ui/component/WXVContainer.java
----------------------------------------------------------------------
diff --git 
a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXVContainer.java 
b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXVContainer.java
index 0d3e477..635b8e4 100644
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXVContainer.java
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXVContainer.java
@@ -22,6 +22,7 @@ import android.content.Context;
 import android.content.Intent;
 import android.support.annotation.RestrictTo;
 import android.support.annotation.RestrictTo.Scope;
+import android.support.v4.view.ViewCompat;
 import android.util.Pair;
 import android.support.annotation.Nullable;
 import android.util.Pair;
@@ -30,9 +31,12 @@ import android.view.View;
 import android.view.ViewGroup;
 
 import com.taobao.weex.WXSDKInstance;
+import com.taobao.weex.annotation.JSMethod;
 import com.taobao.weex.common.Constants;
 import com.taobao.weex.dom.WXDomObject;
+import com.taobao.weex.ui.view.WXImageView;
 import com.taobao.weex.utils.WXLogUtils;
+import com.taobao.weex.utils.WXUtils;
 import com.taobao.weex.utils.WXViewUtils;
 
 import java.util.ArrayList;
@@ -486,6 +490,77 @@ public abstract class WXVContainer<T extends ViewGroup> 
extends WXComponent<T> {
     super.onRenderFinish(state);
   }
 
+  @JSMethod
+  public void releaseImageList(String viewTreeRecycle){
+    if(getHostView() == null
+            || !ViewCompat.isAttachedToWindow(getHostView())
+            || !(getHostView() instanceof  ViewGroup)){
+       return;
+    }
+    boolean isViewTree = WXUtils.getBoolean(viewTreeRecycle, false);
+    if(isViewTree){
+      doViewTreeRecycleImageView(getHostView(), true);
+    }else{
+      int count = getChildCount();
+      for(int i=0; i<count; i++){
+        WXComponent component =  getChild(i);
+        if(component instanceof  WXImage && ((WXImage) 
component).getHostView() instanceof WXImageView){
+          WXImageView imageView = (WXImageView) component.getHostView();
+          if(imageView != null && ViewCompat.isAttachedToWindow(imageView)){
+            imageView.autoReleaseImage();
+          }
+        }else if(component instanceof  WXVContainer){
+          ((WXVContainer) component).releaseImageList(viewTreeRecycle);
+        }
+      }
+    }
+  }
+
+  @JSMethod
+  public void recoverImageList(String viewTreeRecycle){
+    if(getHostView() == null
+            || !ViewCompat.isAttachedToWindow(getHostView())
+            || !(getHostView() instanceof  ViewGroup)){
+         return;
+    }
+    boolean isViewTree = WXUtils.getBoolean(viewTreeRecycle, false);
+    if(isViewTree){
+      doViewTreeRecycleImageView(getHostView(), false);
+    }else{
+      int count = getChildCount();
+      for(int i=0; i<count; i++){
+        WXComponent component =  getChild(i);
+        if(component instanceof  WXImage && ((WXImage) 
component).getHostView() instanceof WXImageView){
+          WXImageView imageView = (WXImageView) component.getHostView();
+          if(imageView != null && ViewCompat.isAttachedToWindow(imageView)){
+            imageView.autoRecoverImage();
+          }
+        }else if(component instanceof  WXVContainer){
+          ((WXVContainer) component).recoverImageList(viewTreeRecycle);
+        }
+      }
+    }
+  }
+
+  /**
+   * transverse view tree, and recycle wximageview in container
+   * */
+  private void doViewTreeRecycleImageView(ViewGroup viewGroup, boolean 
isRelease){
+        int count = viewGroup.getChildCount();
+        for(int i=0; i<count; i++){
+            View view = viewGroup.getChildAt(i);
+            if(view instanceof  WXImageView){
+                if(isRelease){
+                   ((WXImageView) view).autoReleaseImage();
+                }else{
+                   ((WXImageView) view).autoRecoverImage();
+                }
+            }else if(view instanceof  ViewGroup){
+               doViewTreeRecycleImageView((ViewGroup) view, isRelease);
+            }
+        }
+  }
+
 
   public void requestDisallowInterceptTouchEvent(boolean 
requestDisallowInterceptTouchEvent) {
     if(this.requestDisallowInterceptTouchEvent != 
requestDisallowInterceptTouchEvent){

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b582c193/android/sdk/src/main/java/com/taobao/weex/ui/view/WXImageView.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXImageView.java 
b/android/sdk/src/main/java/com/taobao/weex/ui/view/WXImageView.java
index befa2cf..d8670c1 100644
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXImageView.java
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/view/WXImageView.java
@@ -48,7 +48,7 @@ public class WXImageView extends ImageView implements 
WXGestureObservable,
   private float[] borderRadius;
   private boolean gif;
   private boolean isBitmapReleased = false;
-  private boolean enableBitmapAutoManage = false;
+  private boolean enableBitmapAutoManage = true;
 
 
   public WXImageView(Context context) {
@@ -227,7 +227,7 @@ public class WXImageView extends ImageView implements 
WXGestureObservable,
      this.enableBitmapAutoManage = enableBitmapAutoManage;
   }
 
-  protected void autoReleaseImage(){
+  public void autoReleaseImage(){
       if(enableBitmapAutoManage) {
         if (!isBitmapReleased) {
           isBitmapReleased = true;
@@ -239,7 +239,7 @@ public class WXImageView extends ImageView implements 
WXGestureObservable,
       }
   }
 
-  protected void autoRecoverImage(){
+  public void autoRecoverImage(){
     if(enableBitmapAutoManage){
       if(isBitmapReleased){
         WXImage image = getComponent();

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b582c193/android/sdk/src/test/java/com/taobao/weex/ui/component/PriorityQueueTest.java
----------------------------------------------------------------------
diff --git 
a/android/sdk/src/test/java/com/taobao/weex/ui/component/PriorityQueueTest.java 
b/android/sdk/src/test/java/com/taobao/weex/ui/component/PriorityQueueTest.java
new file mode 100644
index 0000000..805d13c
--- /dev/null
+++ 
b/android/sdk/src/test/java/com/taobao/weex/ui/component/PriorityQueueTest.java
@@ -0,0 +1,56 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package com.taobao.weex.ui.component;
+
+import junit.framework.TestCase;
+
+import org.junit.Test;
+
+import java.util.Comparator;
+import java.util.PriorityQueue;
+
+/**
+ * Created by furture on 2018/1/3.
+ */
+
+public class PriorityQueueTest extends TestCase {
+
+
+    @Test
+    public void testPriority(){
+        PriorityQueue<Integer> embeds = new PriorityQueue<>(8, new 
Comparator<Integer>() {
+            @Override
+            public int compare(Integer o1, Integer o2) {
+                return o1 - o2;
+            }
+        });
+
+
+        embeds.add(10);
+        embeds.add(9);
+        embeds.offer(1);
+
+        embeds.offer(2);
+        embeds.add(11);
+
+        System.out.println(embeds.peek()  + "  " + embeds.size());
+
+        System.out.println(embeds.poll() + "  " + embeds.size());
+    }
+}

Reply via email to