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()); + } +}