improve textdom and refactor template cache and render function
Project: http://git-wip-us.apache.org/repos/asf/incubator-weex/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-weex/commit/9e6bee8e Tree: http://git-wip-us.apache.org/repos/asf/incubator-weex/tree/9e6bee8e Diff: http://git-wip-us.apache.org/repos/asf/incubator-weex/diff/9e6bee8e Branch: refs/heads/release-0.16 Commit: 9e6bee8ee2b2340a79874dcd3314195b324024a1 Parents: 772ac33 Author: jianbai.gbj <jianbai....@alibaba-inc.com> Authored: Wed Sep 27 11:06:45 2017 +0800 Committer: gurisxie <279483...@qq.com> Committed: Tue Oct 10 12:11:25 2017 +0800 ---------------------------------------------------------------------- .../taobao/weex/bridge/NativeInvokeHelper.java | 2 +- .../main/java/com/taobao/weex/dom/WXAttr.java | 6 + .../com/taobao/weex/dom/WXCellDomObject.java | 11 + .../java/com/taobao/weex/dom/WXDomManager.java | 4 + .../java/com/taobao/weex/dom/WXDomObject.java | 7 +- .../taobao/weex/dom/WXRecyclerDomObject.java | 47 +- .../com/taobao/weex/dom/WXTextDomObject.java | 31 +- .../com/taobao/weex/dom/binding/ELUtils.java | 2 + .../java/com/taobao/weex/dom/flex/CSSNode.java | 14 +- .../taobao/weex/ui/component/WXComponent.java | 10 +- .../weex/ui/component/binding/Layouts.java | 53 ++- .../weex/ui/component/binding/Statements.java | 103 +++-- .../ui/component/list/BasicListComponent.java | 1 - .../taobao/weex/ui/component/list/WXCell.java | 30 ++ .../list/template/CellLifecycleManager.java | 211 --------- .../component/list/template/DomTreeBuilder.java | 83 ++++ .../component/list/template/TemplateCache.java | 30 ++ .../list/template/TemplateViewHolder.java | 2 + .../list/template/WXRecyclerTemplateList.java | 443 ++++++++++++------- .../ui/component/binding/StatementTest.java | 8 +- 20 files changed, 654 insertions(+), 444 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e6bee8e/android/sdk/src/main/java/com/taobao/weex/bridge/NativeInvokeHelper.java ---------------------------------------------------------------------- diff --git a/android/sdk/src/main/java/com/taobao/weex/bridge/NativeInvokeHelper.java b/android/sdk/src/main/java/com/taobao/weex/bridge/NativeInvokeHelper.java index 98381b5..73255db 100644 --- a/android/sdk/src/main/java/com/taobao/weex/bridge/NativeInvokeHelper.java +++ b/android/sdk/src/main/java/com/taobao/weex/bridge/NativeInvokeHelper.java @@ -47,7 +47,7 @@ public final class NativeInvokeHelper { try { invoker.invoke(target, params); } catch (Exception e) { - throw new RuntimeException(e); + throw new RuntimeException(target + "Invoker " + invoker.toString() ,e); } } }, 0); http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e6bee8e/android/sdk/src/main/java/com/taobao/weex/dom/WXAttr.java ---------------------------------------------------------------------- diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/WXAttr.java b/android/sdk/src/main/java/com/taobao/weex/dom/WXAttr.java index c3b0399..b05d46d 100644 --- a/android/sdk/src/main/java/com/taobao/weex/dom/WXAttr.java +++ b/android/sdk/src/main/java/com/taobao/weex/dom/WXAttr.java @@ -19,6 +19,7 @@ package com.taobao.weex.dom; import static com.taobao.weex.dom.binding.ELUtils.COMPONENT_PROPS; +import static com.taobao.weex.dom.binding.ELUtils.EXCLUDES_BINDING; import static java.lang.Boolean.parseBoolean; import android.support.annotation.NonNull; @@ -477,6 +478,11 @@ public class WXAttr implements Map<String, Object>,Cloneable { ELUtils.bindingBlock(value); return false; } + for(String exclude : EXCLUDES_BINDING){ + if(key.equals(exclude)){ + return false; + } + } if(ELUtils.isBinding(value)){ if(mBindingAttrs == null){ mBindingAttrs = new ArrayMap<String, Object>(); http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e6bee8e/android/sdk/src/main/java/com/taobao/weex/dom/WXCellDomObject.java ---------------------------------------------------------------------- diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/WXCellDomObject.java b/android/sdk/src/main/java/com/taobao/weex/dom/WXCellDomObject.java index 6d50ab6..649a09d 100644 --- a/android/sdk/src/main/java/com/taobao/weex/dom/WXCellDomObject.java +++ b/android/sdk/src/main/java/com/taobao/weex/dom/WXCellDomObject.java @@ -41,11 +41,22 @@ public class WXCellDomObject extends WXDomObject { if (WXBasicComponentType.CELL.equals(domObject.getType()) || WXBasicComponentType.CELL_SLOT.equals(domObject.getType())) { float w = ((WXRecyclerDomObject) parent).getColumnWidth(); + if(w <= 0 && parentDom.getColumnCount() <= 1){ + w = parentDom.getAvailableWidth(); + if(w <= 0){ + w = parentDom.getLayoutWidth(); + if(w <= 0){ + w = parentDom.getViewPortWidth(); + } + } + } node.setLayoutWidth(w); + measureOutput.width = w; } else if (WXBasicComponentType.HEADER.equals(domObject.getType())){ float w = parentDom.getAvailableWidth(); WXLogUtils.d("getAvailableWidth:"+w); node.setLayoutWidth(w); + measureOutput.width = w; } }else if (node instanceof WXCellDomObject){ WXCellDomObject slotDomObject = (WXCellDomObject) node; http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e6bee8e/android/sdk/src/main/java/com/taobao/weex/dom/WXDomManager.java ---------------------------------------------------------------------- diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/WXDomManager.java b/android/sdk/src/main/java/com/taobao/weex/dom/WXDomManager.java index 66fd56e..e1ed82f 100644 --- a/android/sdk/src/main/java/com/taobao/weex/dom/WXDomManager.java +++ b/android/sdk/src/main/java/com/taobao/weex/dom/WXDomManager.java @@ -178,6 +178,10 @@ public final class WXDomManager { } } + public DOMActionContext getDomContext(String instanceId){ + return mDomRegistries.get(instanceId); + } + /** * @param action * @param createContext only true when create body http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e6bee8e/android/sdk/src/main/java/com/taobao/weex/dom/WXDomObject.java ---------------------------------------------------------------------- diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/WXDomObject.java b/android/sdk/src/main/java/com/taobao/weex/dom/WXDomObject.java index 001545d..8398a2d 100644 --- a/android/sdk/src/main/java/com/taobao/weex/dom/WXDomObject.java +++ b/android/sdk/src/main/java/com/taobao/weex/dom/WXDomObject.java @@ -136,6 +136,10 @@ public class WXDomObject extends CSSNode implements Cloneable,ImmutableDomObject return mRef; } + public void setRef(String ref) { + this.mRef = ref; + } + public String getType(){ return mType; } @@ -301,6 +305,7 @@ public class WXDomObject extends CSSNode implements Cloneable,ImmutableDomObject } } + public boolean isFixed() { return mStyles == null ? false : mStyles.isFixed(); } @@ -459,7 +464,7 @@ public class WXDomObject extends CSSNode implements Cloneable,ImmutableDomObject super.dirty(); } - /** package **/ void applyStyleToNode() { + /** package **/public void applyStyleToNode() { WXStyle stylesMap = getStyles(); int vp = getViewPortWidth(); if (!stylesMap.isEmpty()) { http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e6bee8e/android/sdk/src/main/java/com/taobao/weex/dom/WXRecyclerDomObject.java ---------------------------------------------------------------------- diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/WXRecyclerDomObject.java b/android/sdk/src/main/java/com/taobao/weex/dom/WXRecyclerDomObject.java index 1ae3af2..11918e8 100644 --- a/android/sdk/src/main/java/com/taobao/weex/dom/WXRecyclerDomObject.java +++ b/android/sdk/src/main/java/com/taobao/weex/dom/WXRecyclerDomObject.java @@ -27,9 +27,11 @@ import com.taobao.weex.ui.component.WXBasicComponentType; import com.taobao.weex.utils.WXLogUtils; import com.taobao.weex.utils.WXViewUtils; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.Map; -import static com.taobao.weex.dom.flex.CSSLayout.DIMENSION_WIDTH; /** * Created by zhengshihan on 2017/2/21. @@ -43,6 +45,10 @@ public class WXRecyclerDomObject extends WXDomObject{ private float mAvailableWidth = 0; private boolean mIsPreCalculateCellWidth =false; + /**cell-slot not on the tree */ + private List<WXCellDomObject> cellList; + + public float getAvailableWidth() { return WXViewUtils.getRealPxByWidth(mAvailableWidth,getViewPortWidth()); } @@ -64,9 +70,18 @@ public class WXRecyclerDomObject extends WXDomObject{ } @Override public void add(WXDomObject child, int index) { - super.add(child, index); + if(WXBasicComponentType.CELL_SLOT.equals(child.getType()) + && child instanceof WXCellDomObject){ + if(cellList == null){ + cellList = Collections.synchronizedList(new ArrayList<WXCellDomObject>()); + } + cellList.add((WXCellDomObject)child); + }else{ + super.add(child, index); + } - if (WXBasicComponentType.CELL.equals(child.getType())) { + if (WXBasicComponentType.CELL.equals(child.getType()) + || WXBasicComponentType.CELL_SLOT.equals(child.getType())) { if (!mIsPreCalculateCellWidth) { preCalculateCellWidth(); } @@ -77,6 +92,22 @@ public class WXRecyclerDomObject extends WXDomObject{ } @Override + public void remove(WXDomObject child) { + if(cellList != null){ + cellList.remove(child); + } + super.remove(child); + } + + @Override + public void removeFromDom(WXDomObject child) { + if(cellList != null){ + cellList.remove(child); + } + super.removeFromDom(child); + } + + @Override public float getStyleWidth() { float width = getLayoutWidth(); if (Float.isNaN(width) || width <= 0){ @@ -192,4 +223,14 @@ public class WXRecyclerDomObject extends WXDomObject{ return Constants.Orientation.VERTICAL; } + @Override + public WXDomObject clone() { + WXRecyclerDomObject domObject = (WXRecyclerDomObject) super.clone(); + domObject.cellList = cellList; + return domObject; + } + + public List<WXCellDomObject> getCellList() { + return cellList; + } } http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e6bee8e/android/sdk/src/main/java/com/taobao/weex/dom/WXTextDomObject.java ---------------------------------------------------------------------- diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/WXTextDomObject.java b/android/sdk/src/main/java/com/taobao/weex/dom/WXTextDomObject.java index 3456bde..bdcfd39 100644 --- a/android/sdk/src/main/java/com/taobao/weex/dom/WXTextDomObject.java +++ b/android/sdk/src/main/java/com/taobao/weex/dom/WXTextDomObject.java @@ -39,6 +39,8 @@ import android.text.TextUtils; import android.text.style.AbsoluteSizeSpan; import android.text.style.AlignmentSpan; import android.text.style.ForegroundColorSpan; +import android.util.Log; + import com.taobao.weex.WXEnvironment; import com.taobao.weex.common.Constants; import com.taobao.weex.common.WXThread; @@ -98,9 +100,16 @@ public class WXTextDomObject extends WXDomObject { if (CSSConstants.isUndefined(width)) { width = node.cssstyle.maxWidth; } - if(textDomObject.getTextWidth(textDomObject.mTextPaint,width,false)>0) { - textDomObject.layout = textDomObject.createLayout(width, false, null); - textDomObject.hasBeenMeasured = true; + boolean forceWidth = false; + if(width > 0){ + if(node.getParent() != null && textDomObject.mAlignment == Layout.Alignment.ALIGN_CENTER){ + forceWidth = FloatUtil.floatsEqual(width, node.getParent().getLayoutWidth()); + } + } + textDomObject.hasBeenMeasured = true; + width = textDomObject.getTextWidth(textDomObject.mTextPaint,width, forceWidth); + if(width > 0 && textDomObject.mText != null) { + textDomObject.layout = textDomObject.createLayout(width, true, null); textDomObject.previousWidth = textDomObject.layout.getWidth(); measureOutput.height = textDomObject.layout.getHeight(); measureOutput.width = textDomObject.previousWidth; @@ -186,7 +195,7 @@ public class WXTextDomObject extends WXDomObject { hasBeenMeasured = false; if (layout != null && !layout.equals(atomicReference.get()) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - if(Thread.currentThread() instanceof WXThread){ + if(Thread.currentThread() != Looper.getMainLooper().getThread()){ warmUpTextLayoutCache(layout); } } @@ -241,8 +250,12 @@ public class WXTextDomObject extends WXDomObject { float contentWidth = WXDomUtils.getContentWidth(this); if (contentWidth > 0) { spanned = createSpanned(mText); - layout = createLayout(contentWidth, true, layout); - previousWidth = layout.getWidth(); + if(mText != null){ + layout = createLayout(contentWidth, true, layout); + previousWidth = layout.getWidth(); + }else{ + previousWidth = 0; + } } } @@ -394,6 +407,12 @@ public class WXTextDomObject extends WXDomObject { * outerWidth in case of outerWidth is defined, in other case, it will be outer width. */ float getTextWidth(TextPaint textPaint,float outerWidth, boolean forceToDesired) { + if(mText == null){ + if(forceToDesired){ + return outerWidth; + } + return 0; + } float textWidth; if (forceToDesired) { textWidth = outerWidth; http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e6bee8e/android/sdk/src/main/java/com/taobao/weex/dom/binding/ELUtils.java ---------------------------------------------------------------------- diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/binding/ELUtils.java b/android/sdk/src/main/java/com/taobao/weex/dom/binding/ELUtils.java index c0924f0..8202a46 100644 --- a/android/sdk/src/main/java/com/taobao/weex/dom/binding/ELUtils.java +++ b/android/sdk/src/main/java/com/taobao/weex/dom/binding/ELUtils.java @@ -41,6 +41,8 @@ public class ELUtils { public static final String COMPONENT_PROPS = "@componentProps"; + public static final String[] EXCLUDES_BINDING = {"clickEventParams"}; + /** * @param value check object is binding expression * */ http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e6bee8e/android/sdk/src/main/java/com/taobao/weex/dom/flex/CSSNode.java ---------------------------------------------------------------------- diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/flex/CSSNode.java b/android/sdk/src/main/java/com/taobao/weex/dom/flex/CSSNode.java index 3f55245..79ba6e5 100755 --- a/android/sdk/src/main/java/com/taobao/weex/dom/flex/CSSNode.java +++ b/android/sdk/src/main/java/com/taobao/weex/dom/flex/CSSNode.java @@ -9,6 +9,9 @@ package com.taobao.weex.dom.flex; import android.support.annotation.NonNull; +import com.taobao.weex.WXEnvironment; +import com.taobao.weex.utils.WXLogUtils; + import java.util.ArrayList; import static com.taobao.weex.dom.flex.CSSLayout.DIMENSION_HEIGHT; @@ -54,6 +57,10 @@ public class CSSNode { dirty(); } + public void markLayoutStateUpdated(){ + this.mLayoutState = LayoutState.UP_TO_DATE; + } + /** * whether layout changed when {@link #updateLastLayout(CSSLayout)} invoked last time. * @return @@ -165,12 +172,15 @@ public class CSSNode { if (mLayoutState == LayoutState.DIRTY) { return; } else if (mLayoutState == LayoutState.HAS_NEW_LAYOUT) { - throw new IllegalStateException("Previous csslayout was ignored! markLayoutSeen() never called"); + if(WXEnvironment.isApkDebugable()){ + WXLogUtils.w("weex", new IllegalStateException("Previous csslayout was ignored! markLayoutSeen() never called")); + } + markLayoutSeen(); } mLayoutState = LayoutState.DIRTY; - if (mParent != null) { + if (mParent != null && !mParent.isDirty()) { mParent.dirty(); } } http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e6bee8e/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java ---------------------------------------------------------------------- diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java index e9d7296..f735e4e 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java @@ -337,7 +337,7 @@ public abstract class WXComponent<T extends View> implements IWXObject, IWXActi long startNanos = System.nanoTime(); if(!isLazy()) { if (component == null) { - component = this; + component = this; } setLayout(component.getDomObject()); setPadding(component.getDomObject().getPadding(), component.getDomObject().getBorder()); @@ -1408,6 +1408,14 @@ public abstract class WXComponent<T extends View> implements IWXObject, IWXActi view.setVisibility(View.GONE); } } + if(mDomObj != null){ + WXDomObject domObject = (WXDomObject) mDomObj; + if (TextUtils.equals(visibility, Constants.Value.VISIBLE)) { + domObject.setVisible(true); + } else if (TextUtils.equals(visibility, Constants.Value.HIDDEN)) { + domObject.setVisible(false); + } + } } /** http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e6bee8e/android/sdk/src/main/java/com/taobao/weex/ui/component/binding/Layouts.java ---------------------------------------------------------------------- diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/binding/Layouts.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/binding/Layouts.java index 5b8d32c..1e48ea7 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/component/binding/Layouts.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/binding/Layouts.java @@ -28,9 +28,11 @@ import com.taobao.weex.WXSDKInstance; import com.taobao.weex.common.Constants; import com.taobao.weex.dom.WXDomObject; import com.taobao.weex.dom.flex.CSSLayoutContext; +import com.taobao.weex.dom.flex.CSSNode; import com.taobao.weex.ui.component.WXComponent; import com.taobao.weex.ui.component.WXVContainer; import com.taobao.weex.ui.component.list.template.TemplateViewHolder; +import com.taobao.weex.ui.component.list.template.WXRecyclerTemplateList; import com.taobao.weex.utils.WXLogUtils; /** @@ -41,35 +43,41 @@ public class Layouts { * do dom layout async or sync , and set layout to component on main. * on first use do sync layout, when compontnet reuse do async layout * */ - public static void doLayoutAsync(final TemplateViewHolder templateViewHolder){ + public static void doLayoutAsync(final TemplateViewHolder templateViewHolder, boolean async){ final WXComponent component = templateViewHolder.getComponent(); final int position = templateViewHolder.getHolderPosition(); if(templateViewHolder.asyncTask != null){ - templateViewHolder.asyncTask.cancel(true); + templateViewHolder.asyncTask.cancel(false); templateViewHolder.asyncTask = null; } - AsyncTask<Void, Void, Void> asyncTask = new AsyncTask<Void, Void, Void>() { - @Override - protected Void doInBackground(Void... params) { - if(templateViewHolder.getHolderPosition() == position){ - if(component.getInstance() != null && !component.getInstance().isDestroy()) { - doSafeLayout(component, templateViewHolder.getLayoutContext()); + if(async){ + AsyncTask<Void, Void, Void> asyncTask = new AsyncTask<Void, Void, Void>() { + @Override + protected Void doInBackground(Void... params) { + if(templateViewHolder.getHolderPosition() == position){ + if(component.getInstance() != null && !component.getInstance().isDestroy()) { + doSafeLayout(component, templateViewHolder.getLayoutContext()); + } } + return null; } - return null; - } - @Override - protected void onPostExecute(Void aVoid) { - if(position == templateViewHolder.getHolderPosition()) { - if(component.getInstance() != null && !component.getInstance().isDestroy()) { - setLayout(component, false); + @Override + protected void onPostExecute(Void aVoid) { + if(position == templateViewHolder.getHolderPosition()) { + if(component.getInstance() != null && !component.getInstance().isDestroy()) { + setLayout(component, false); + } } } - } - }; - templateViewHolder.asyncTask = asyncTask; - asyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); //serial executor is better + }; + templateViewHolder.asyncTask = asyncTask; + asyncTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); //serial executor is better + }else{ + doSafeLayout(component, templateViewHolder.getLayoutContext()); + Log.e("weex", "weex" + component.getLayoutHeight() + " " + component.getLayoutWidth()); + setLayout(component, false); + } } @@ -81,13 +89,13 @@ public class Layouts { long start = System.currentTimeMillis(); doLayout(component, layoutContext); if(WXEnvironment.isApkDebugable()){ - WXLogUtils.d("WXTemplateList", + WXLogUtils.d(WXRecyclerTemplateList.TAG, "WXTemplateList doSafeLayout" + component.getDomObject().getAttrs().get(Constants.Name.Recycler.SLOT_TEMPLATE_TYPE) + Thread.currentThread().getName() + " doSafeLayout used " + (System.currentTimeMillis() - start)); } }catch (Exception e){ if(WXEnvironment.isApkDebugable()){ - WXLogUtils.e("WXTemplateListdoSafeLayout", e); + WXLogUtils.e(WXRecyclerTemplateList.TAG, e); } } } @@ -135,6 +143,9 @@ public class Layouts { WXDomObject domObject = (WXDomObject) component.getDomObject(); if(domObject.hasUpdate() || force){ domObject.markUpdateSeen(); + if(domObject.hasUpdate()){ + domObject.markLayoutStateUpdated(); + } component.setLayout(component.getDomObject()); if(component.getDomObject().getExtra() != null){ component.updateExtra(component.getDomObject().getExtra()); http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e6bee8e/android/sdk/src/main/java/com/taobao/weex/ui/component/binding/Statements.java ---------------------------------------------------------------------- diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/binding/Statements.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/binding/Statements.java index 6912335..1af8934 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/component/binding/Statements.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/binding/Statements.java @@ -25,6 +25,8 @@ import android.util.Log; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; +import com.taobao.weex.WXEnvironment; +import com.taobao.weex.annotation.Component; import com.taobao.weex.common.Constants; import com.taobao.weex.dom.WXAttr; import com.taobao.weex.dom.WXDomObject; @@ -39,6 +41,8 @@ import com.taobao.weex.ui.component.WXComponent; import com.taobao.weex.ui.component.WXComponentFactory; import com.taobao.weex.ui.component.WXImage; import com.taobao.weex.ui.component.WXVContainer; +import com.taobao.weex.ui.component.list.WXCell; +import com.taobao.weex.ui.component.list.template.WXRecyclerTemplateList; import com.taobao.weex.utils.WXLogUtils; import com.taobao.weex.utils.WXUtils; @@ -59,7 +63,11 @@ public class Statements { * recursive copy component, none parent connect * */ public static WXComponent copyComponentTree(WXComponent component){ + long start = System.currentTimeMillis(); WXComponent copy = copyComponentTree(component, component.getParent()); + if(WXEnvironment.isApkDebugable()){ + WXLogUtils.d(WXRecyclerTemplateList.TAG, Thread.currentThread() + component.getRef() + "copyComponentTree " + "used " + (System.currentTimeMillis() - start)); + } return copy; } @@ -96,26 +104,47 @@ public class Statements { * may be next render it can be used. * after statement has executed, render component's binding attrs in context and bind it to component. * */ - public static final void doRender(WXComponent component, ArrayStack stack){ + public static final List<WXComponent> doRender(WXComponent component, ArrayStack stack){ + List<WXComponent> updates = new ArrayList<>(4); try{ - doRenderComponent(component, stack); + doRenderComponent(component, stack, updates); }catch (Exception e){ WXLogUtils.e("WeexStatementRender", e); } + return updates; } + public static final void doInitCompontent(List<WXComponent> updates) { + if(updates == null || updates.size() == 0){ + return; + } + for(WXComponent renderNode : updates){ + if(renderNode.getParent() == null){ + throw new IllegalArgumentException("render node parent cann't find"); + } + WXVContainer parent = renderNode.getParent(); + int renderIndex = parent.indexOf(renderNode); + if(renderIndex < 0){ + throw new IllegalArgumentException("render node cann't find"); + } + parent.createChildViewAt(renderIndex); + renderNode.applyLayoutAndEvent(renderNode); + renderNode.bindData(renderNode); + } + } - /** - * @param component component with v-for statement, v-if statement and bind attrs - * @param context execute context - * render component in context, the function do the following work. - * execute component's v-for statement, v-if statement in context, - * and rebuild component's tree with the statement, v-for reuse component execute by pre render. - * if executed, component will be removed, don't remove, just mark it waste; - * may be next render it can be used. - * after statement has executed, render component's binding attrs in context and bind it to component. - * */ - static final int doRenderComponent(WXComponent component, ArrayStack context){ + /** + * @param component component with v-for statement, v-if statement and bind attrs + * @param context execute context + * render component in context, the function do the following work. + * execute component's v-for statement, v-if statement in context, + * and rebuild component's tree with the statement, v-for reuse component execute by pre render. + * if executed, component will be removed, don't remove, just mark it waste; + * may be next render it can be used. + * after statement has executed, render component's binding attrs in context and bind it to component. + * */ + private static final int doRenderComponent(WXComponent component, ArrayStack context, + List<WXComponent> updates){ WXVContainer parent = component.getParent(); WXDomObject domObject = (WXDomObject) component.getDomObject(); WXAttr attrs = domObject.getAttrs(); @@ -198,18 +227,18 @@ public class Statements { } //none resuable render node, create node, add to parent, but clear node's statement if(renderNode == null){ + long start = System.currentTimeMillis(); renderNode = copyComponentTree(component, parent); WXDomObject renderNodeDomObject = (WXDomObject) renderNode.getDomObject(); renderNodeDomObject.getAttrs().setStatement(null); // clear node's statement parentDomObject.add(renderNodeDomObject, renderIndex); parent.addChild(renderNode, renderIndex); - if(Thread.currentThread() == Looper.getMainLooper().getThread()) { - parent.createChildViewAt(renderIndex); - renderNode.applyLayoutAndEvent(renderNode); - renderNode.bindData(renderNode); + updates.add(renderNode); + if(WXEnvironment.isApkDebugable()){ + WXLogUtils.d(WXRecyclerTemplateList.TAG, Thread.currentThread().getName() + renderNode.getRef() + renderNode.getDomObject().getType() + "statements copy component tree used " + (System.currentTimeMillis() - start)); } } - doBindingAttrsEventAndRenderChildNode(renderNode, domObject, context); + doBindingAttrsEventAndRenderChildNode(renderNode, domObject, context, updates); renderIndex++; if(loop.size() > 0){ context.push(loop); @@ -220,7 +249,7 @@ public class Statements { } } }else{ - WXLogUtils.e("StatementsVFor", vfor.toJSONString() + " not call vfor block, for pre compile"); + WXLogUtils.e(WXRecyclerTemplateList.TAG, vfor.toJSONString() + " not call vfor block, for pre compile"); } //after v-for execute, remove component created pre v-for. for(;renderIndex<parent.getChildCount(); renderIndex++){ @@ -237,20 +266,23 @@ public class Statements { if(vif != null){ if(!Operators.isTrue(vif.execute(context))){ component.setWaste(true); - return 1; + if(Thread.currentThread() == Looper.getMainLooper().getThread()) { + return 1; + } }else{ component.setWaste(false); } } } - doBindingAttrsEventAndRenderChildNode(component, domObject, context); + doBindingAttrsEventAndRenderChildNode(component, domObject, context, updates); return 1; } /** * bind attrs and doRender component child * */ - private static void doBindingAttrsEventAndRenderChildNode(WXComponent component, WXDomObject domObject, ArrayStack context){ + private static void doBindingAttrsEventAndRenderChildNode(WXComponent component, WXDomObject domObject, ArrayStack context, + List<WXComponent> updates){ WXAttr attr = component.getDomObject().getAttrs(); /** * sub component supported, sub component new stack @@ -266,10 +298,17 @@ public class Statements { } doRenderBindingAttrsAndEvent(component, domObject, context); if(component instanceof WXVContainer){ + if(!domObject.isShow()){ + if(!(component instanceof WXCell)){ + if(Thread.currentThread() == Looper.getMainLooper().getThread()){ + return; + } + } + } WXVContainer container = (WXVContainer) component; for(int k=0; k<container.getChildCount();){ WXComponent next = container.getChild(k); - k += doRenderComponent(next, context); + k += doRenderComponent(next, context, updates); } } } @@ -325,6 +364,7 @@ public class Statements { if(Thread.currentThread() == Looper.getMainLooper().getThread()) { component.updateProperties(dynamic); } + dynamic.clear(); } } WXEvent event = domObject.getEvents(); @@ -346,9 +386,16 @@ public class Statements { * @param context context * return binding attrs rended value in context * */ + private static final ThreadLocal<Map<String, Object>> dynamicLocal = new ThreadLocal<>(); public static Map<String, Object> renderBindingAttrs(ArrayMap bindAttrs, ArrayStack context){ Set<Map.Entry<String, Object>> entrySet = bindAttrs.entrySet(); - Map<String, Object> dynamic = new HashMap<>(); + Map<String, Object> dynamic = dynamicLocal.get(); + if(dynamic == null) { + dynamic = new HashMap<>(); + } + if(dynamic.size() > 0){ + dynamic.clear(); + } for(Map.Entry<String, Object> entry : entrySet){ Object value = entry.getValue(); String key = entry.getKey(); @@ -378,7 +425,13 @@ public class Statements { builder.append(blockValue); } } - dynamic.put(key, builder.toString()); + String builderString = builder.toString(); + if(builderString.length() > 256){ + if(WXEnvironment.isApkDebugable()){ + WXLogUtils.w(WXRecyclerTemplateList.TAG, " warn too big string " + builderString); + } + } + dynamic.put(key, builderString); } } return dynamic; http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e6bee8e/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java ---------------------------------------------------------------------- diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java index 9b8fe04..640a17e 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java @@ -459,7 +459,6 @@ public abstract class BasicListComponent<T extends ViewGroup & ListComponentView //Invalid position return; } - final WXRecyclerView view = bounceRecyclerView.getInnerView(); view.scrollTo(smooth, pos, offset, getOrientation()); } http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e6bee8e/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXCell.java ---------------------------------------------------------------------- diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXCell.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXCell.java index 401b654..4fe4bc2 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXCell.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/WXCell.java @@ -55,6 +55,12 @@ public class WXCell extends WidgetContainer<WXFrameLayout> { private int mScrollPositon = -1; private boolean mFlatUIEnabled = false; + private Object renderData; + + private boolean isSourceUsed = false; + + private boolean hasLayout = false; + @Deprecated public WXCell(WXSDKInstance instance, WXDomObject dom, WXVContainer parent, String instanceId, boolean isLazy) { super(instance, dom, parent); @@ -178,4 +184,28 @@ public class WXCell extends WidgetContainer<WXFrameLayout> { public boolean intendToBeFlatContainer() { return getInstance().getFlatUIContext().isFlatUIEnabled(this) && WXCell.class.equals(getClass()) && !isSticky(); } + + public Object getRenderData() { + return renderData; + } + + public void setRenderData(Object renderData) { + this.renderData = renderData; + } + + public boolean isSourceUsed() { + return isSourceUsed; + } + + public void setSourceUsed(boolean sourceUsed) { + isSourceUsed = sourceUsed; + } + + public boolean isHasLayout() { + return hasLayout; + } + + public void setHasLayout(boolean hasLayout) { + this.hasLayout = hasLayout; + } } http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e6bee8e/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/CellLifecycleManager.java ---------------------------------------------------------------------- diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/CellLifecycleManager.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/CellLifecycleManager.java deleted file mode 100644 index d30963d..0000000 --- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/CellLifecycleManager.java +++ /dev/null @@ -1,211 +0,0 @@ -/** - * 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.list.template; - -import com.taobao.weex.common.Constants; -import com.taobao.weex.dom.WXEvent; -import com.taobao.weex.ui.component.WXComponent; -import com.taobao.weex.ui.component.WXVContainer; -import com.taobao.weex.ui.component.list.WXCell; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * cell-slot lifecycle manager, onCreate onAttach onDetach destroy - * Created by furture on 2017/9/19. - */ -public class CellLifecycleManager { - - private static final String[] lifecycleEventNames = { - Constants.Event.SLOT_LIFECYCLE.CREATE, - Constants.Event.SLOT_LIFECYCLE.ATTACH, - Constants.Event.SLOT_LIFECYCLE.DETACH, - Constants.Event.SLOT_LIFECYCLE.DESTORY - }; - - private WXRecyclerTemplateList recyclerTemplateList; - private Map<String,Map<String,List<String>>> eventSlotWatchRefs; - - - private Map<Integer,Boolean> firedCreateEvent; // only call once - - - public CellLifecycleManager(WXRecyclerTemplateList recyclerTemplateList) { - this.recyclerTemplateList = recyclerTemplateList; - this.eventSlotWatchRefs = new HashMap<>(); - this.firedCreateEvent = new HashMap<>(); - } - - - - public void filterLifecycleWatchEvent(WXCell cell, WXComponent component){ - WXEvent wxEvent = component.getDomObject().getEvents(); - for(String event : lifecycleEventNames){ - if(wxEvent.contains(event)){ - Map<String,List<String>> slotWatchRefs = eventSlotWatchRefs.get(event); - if(slotWatchRefs == null){ - slotWatchRefs = new HashMap<>(); - eventSlotWatchRefs.put(event, slotWatchRefs); - } - List<String> refs = slotWatchRefs.get(cell.getRef()); - if(refs == null){ - refs = new ArrayList<>(8); - slotWatchRefs.put(cell.getRef(), refs); - } - if(!refs.contains(component.getRef())){ - refs.add(component.getRef()); - } - } - } - if(component instanceof WXVContainer){ - WXVContainer container = (WXVContainer) component; - for(int i=0; i<container.getChildCount(); i++){ - WXComponent child = container.getChild(i); - filterLifecycleWatchEvent(cell, child); - } - } - } - - /** - * onCreate event - * */ - public void onCreate(int position){ - WXCell cell = recyclerTemplateList.getSourceTemplate(position); - if(cell == null){ - return; - } - if(firedCreateEvent.get(position) != null){ - return; - } - firedCreateEvent.put(position, true); - Map<String,List<String>> slotWatchCreateRefs = eventSlotWatchRefs.get(Constants.Event.SLOT_LIFECYCLE.CREATE); - if(slotWatchCreateRefs == null - || slotWatchCreateRefs.get(cell.getRef()) == null - || slotWatchCreateRefs.get(cell.getRef()).size() == 0){ - return; - } - List<String> refs = slotWatchCreateRefs.get(cell.getRef()); - if(refs == null || refs.size() == 0){ - return; - } - fireChildEvent(Constants.Event.SLOT_LIFECYCLE.CREATE, cell, refs, position); - } - - public void onInsert(int position){ - WXCell cell = recyclerTemplateList.getSourceTemplate(position); - if(cell == null){ - return; - } - firedCreateEvent.put(position, true); - firedCreateEvent.put(firedCreateEvent.size(), true); - Map<String,List<String>> slotWatchCreateRefs = eventSlotWatchRefs.get(Constants.Event.SLOT_LIFECYCLE.CREATE); - if(slotWatchCreateRefs == null - || slotWatchCreateRefs.get(cell.getRef()) == null - || slotWatchCreateRefs.get(cell.getRef()).size() == 0){ - return; - } - List<String> refs = slotWatchCreateRefs.get(cell.getRef()); - if(refs == null || refs.size() == 0){ - return; - } - fireChildEvent(Constants.Event.SLOT_LIFECYCLE.CREATE, cell, refs, position); - } - - /** - * onAttach event - * */ - public void onAttach(int position, WXCell cell){ - if(cell == null || position < 0){ - return; - } - Map<String,List<String>> slotWatchAttachRefs = eventSlotWatchRefs.get(Constants.Event.SLOT_LIFECYCLE.ATTACH); - if(slotWatchAttachRefs == null - || slotWatchAttachRefs.get(cell.getRef()) == null - || slotWatchAttachRefs.get(cell.getRef()).size() == 0){ - return; - } - List<String> refs = slotWatchAttachRefs.get(cell.getRef()); - fireChildEvent(Constants.Event.SLOT_LIFECYCLE.ATTACH, cell, refs, position); - } - - /** - * onDetach event - * */ - public void onDetach(int position, WXCell cell){ - if(cell == null || position < 0){ - return; - } - Map<String,List<String>> slotWatchDetachRefs = eventSlotWatchRefs.get(Constants.Event.SLOT_LIFECYCLE.ATTACH); - if(slotWatchDetachRefs == null - || slotWatchDetachRefs.get(cell.getRef()) == null - || slotWatchDetachRefs.get(cell.getRef()).size() == 0){ - return; - } - List<String> refs = slotWatchDetachRefs.get(cell.getRef()); - fireChildEvent(Constants.Event.SLOT_LIFECYCLE.DETACH, cell, refs, position); - } - - /** - * onDestory event - * */ - public void onDestory(int position){ - Boolean hasCreated = firedCreateEvent.remove(position); - if(hasCreated == null){ - return; - } - Map<String,List<String>> slotWatchDestroyRefs = eventSlotWatchRefs.get(Constants.Event.SLOT_LIFECYCLE.DESTORY); - if(slotWatchDestroyRefs == null - || slotWatchDestroyRefs.size() == 0){ - return; - } - WXCell cell = recyclerTemplateList.getSourceTemplate(position); - if(cell == null){ - return; - } - List<String> refs = slotWatchDestroyRefs.get(cell.getRef()); - if(refs == null || refs.size() == 0){ - return; - } - fireChildEvent(Constants.Event.SLOT_LIFECYCLE.DESTORY, cell, refs, position); - } - - public Map<Integer, Boolean> getFiredCreateEvent() { - return firedCreateEvent; - } - - private final void fireChildEvent(String event, WXCell cell, List<String> refs, int position){ - if(refs == null || refs.size() == 0){ - return; - } - for(String ref : refs){ - List<WXComponent> components = recyclerTemplateList.findChildListByRef(cell, ref); - if(components == null || components.size() == 0){ - continue; - } - for(WXComponent component : components) { - Map<String, Object> params = new HashMap<>(8); - params.put("index", position); - component.fireEvent(event, params); - } - } - } -} http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e6bee8e/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/DomTreeBuilder.java ---------------------------------------------------------------------- diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/DomTreeBuilder.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/DomTreeBuilder.java new file mode 100644 index 0000000..c475195 --- /dev/null +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/DomTreeBuilder.java @@ -0,0 +1,83 @@ +/** + * 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.list.template; + +import com.taobao.weex.WXSDKManager; +import com.taobao.weex.dom.DOMActionContext; +import com.taobao.weex.dom.WXDomObject; +import com.taobao.weex.dom.action.TraceableAction; +import com.taobao.weex.ui.component.WXComponent; +import com.taobao.weex.ui.component.WXComponentFactory; +import com.taobao.weex.ui.component.WXVContainer; + +/** + * Created by furture on 2017/10/2. + */ + +class DomTreeBuilder extends TraceableAction { + + + + + public WXComponent generateComponentTree(DOMActionContext context, WXDomObject dom, WXVContainer parent) { + if (dom == null) { + return null; + } + long startNanos = System.nanoTime(); + WXComponent component = WXComponentFactory.newInstance(context.getInstance(), dom, parent); + if (component != null) { + component.mTraceInfo.domThreadStart = dom.mDomThreadTimestamp; + component.mTraceInfo.rootEventId = mTracingEventId; + component.mTraceInfo.domQueueTime = mDomQueueTime; + } + ((WXDomObject)component.getDomObject()).applyStyleToNode(); + context.registerDOMObject(dom.getRef(), dom); + context.registerComponent(dom.getRef(), component); + if (component instanceof WXVContainer) { + WXVContainer container = (WXVContainer) component; + WXDomObject parentDom = (WXDomObject) container.getDomObject(); + int count = dom.childCount(); + WXDomObject child = null; + for (int i = 0; i < count; ++i) { + child = dom.getChild(i); + if (child != null) { + WXComponent childComponent = generateComponentTree(context, child, container); + container.addChild(childComponent); + parentDom.add((WXDomObject) childComponent.getDomObject(), -1); + } + } + } + if (component != null) { + component.mTraceInfo.domThreadNanos = System.nanoTime() - startNanos; + } + return component; + } + + public static final WXComponent buildTree(WXDomObject domObject, WXVContainer parent){ + DOMActionContext domActionContext = WXSDKManager.getInstance().getWXDomManager().getDomContext(parent.getInstanceId()); + if(domActionContext == null){ + return null; + } + domObject.getStyles().put("display", "flex"); + DomTreeBuilder builder = new DomTreeBuilder(); + return builder.generateComponentTree(domActionContext, domObject, parent); + + } + +} http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e6bee8e/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/TemplateCache.java ---------------------------------------------------------------------- diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/TemplateCache.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/TemplateCache.java new file mode 100644 index 0000000..eab80bc --- /dev/null +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/TemplateCache.java @@ -0,0 +1,30 @@ +/** + * 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.list.template; +import com.taobao.weex.ui.component.list.WXCell; +import java.util.concurrent.ConcurrentLinkedQueue; + +/** + * preload cell cache + * Created by furture on 2017/9/29. + */ +class TemplateCache { + ConcurrentLinkedQueue<WXCell> cells = new ConcurrentLinkedQueue<>(); + boolean isLoadIng = false; +} http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e6bee8e/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/TemplateViewHolder.java ---------------------------------------------------------------------- diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/TemplateViewHolder.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/TemplateViewHolder.java index a418e3e..d0b5dbf 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/TemplateViewHolder.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/TemplateViewHolder.java @@ -47,6 +47,8 @@ public class TemplateViewHolder extends ListBaseViewHolder { public AsyncTask<Void, Void, Void> asyncTask; + public Object data; + /** * header position * */ http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e6bee8e/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/WXRecyclerTemplateList.java ---------------------------------------------------------------------- diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/WXRecyclerTemplateList.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/WXRecyclerTemplateList.java index 5d23bf6..d371ab2 100644 --- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/WXRecyclerTemplateList.java +++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/WXRecyclerTemplateList.java @@ -25,6 +25,7 @@ import android.graphics.PointF; import android.os.AsyncTask; import android.os.Build; import android.os.Looper; +import android.os.MessageQueue; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.util.ArrayMap; @@ -43,14 +44,16 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.taobao.weex.WXEnvironment; import com.taobao.weex.WXSDKInstance; +import com.taobao.weex.WXSDKManager; import com.taobao.weex.annotation.Component; import com.taobao.weex.annotation.JSMethod; +import com.taobao.weex.bridge.WXBridgeManager; import com.taobao.weex.common.Constants; import com.taobao.weex.common.ICheckBindingScroller; import com.taobao.weex.common.OnWXScrollListener; -import com.taobao.weex.dom.ImmutableDomObject; import com.taobao.weex.dom.WXAttr; import com.taobao.weex.dom.WXCellDomObject; +import com.taobao.weex.dom.WXDomHandler; import com.taobao.weex.dom.WXDomObject; import com.taobao.weex.dom.WXEvent; import com.taobao.weex.dom.WXRecyclerDomObject; @@ -81,10 +84,12 @@ import com.taobao.weex.utils.WXViewUtils; import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; import static com.taobao.weex.common.Constants.Name.LOADMOREOFFSET; @@ -96,10 +101,11 @@ import static com.taobao.weex.common.Constants.Name.LOADMOREOFFSET; @Component(lazyload = false) public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> implements IRecyclerAdapterListener<TemplateViewHolder>, IOnLoadMoreListener, Scrollable { - private static final String TAG = "WXRecyclerTemplateList"; + public static final String TAG = "WXRecyclerTemplateList"; private static final String NAME_HAS_FIXED_SIZE = "hasFixedSize"; private static final String NAME_ITEM_VIEW_CACHE_SIZE = "itemViewCacheSize"; + private static final String NAME_TEMPLATE_CACHE_SIZE = "templateCacheSize"; private WXRecyclerDomObject mDomObject; @@ -135,11 +141,12 @@ public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> imp - private Map<String, WXCell> mTemplates; + private Map<String, WXCell> mTemplateSources; private String listDataTemplateKey = Constants.Name.Recycler.SLOT_TEMPLATE_TYPE; private Runnable listUpdateRunnable; - private ConcurrentHashMap<String, WXCell> mTemplatesCache; - private ConcurrentHashMap<String, Boolean> mTemplateRendered; + private ConcurrentHashMap<String, TemplateCache> mTemplatesCache; + private int templateCacheSize = 2; + /** * sticky helper @@ -148,12 +155,6 @@ public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> imp /** - * cell item lifecycle manager - * */ - private CellLifecycleManager cellLifecycleManager; - - - /** * appear and disappear event managaer * */ private ArrayMap<Integer, List<AppearanceHelper>> mAppearHelpers = new ArrayMap<>(); @@ -166,6 +167,9 @@ public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> imp * */ private ArrayMap<Integer, Map<String,Map<Integer, List<Object>>>> mDisAppearWatchList = new ArrayMap<>(); + private ArrayStack bindIngStackContext = new ArrayStack(); + private Map bindIngMapContext = new HashMap(); + public WXRecyclerTemplateList(WXSDKInstance instance, WXDomObject node, WXVContainer parent) { super(instance, node, parent); initRecyclerTemplateList(instance, node, parent); @@ -180,10 +184,9 @@ public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> imp } mTemplateViewTypes = new ArrayMap<>(); mTemplateViewTypes.put("", 0); //empty view, when template was not sended - mTemplates = new HashMap<>(); + mTemplateSources = new HashMap<>(); mTemplatesCache = new ConcurrentHashMap<>(); mStickyHelper = new TemplateStickyHelper(this); - cellLifecycleManager = new CellLifecycleManager(this); orientation = mDomObject.getOrientation(); listDataTemplateKey = WXUtils.getString(getDomObject().getAttrs().get(Constants.Name.Recycler.LIST_DATA_TEMPLATE_KEY), Constants.Name.Recycler.SLOT_TEMPLATE_TYPE); listDataItemKey = WXUtils.getString(getDomObject().getAttrs().get(Constants.Name.Recycler.LIST_DATA_ITEM), listDataItemKey); @@ -194,7 +197,12 @@ public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> imp listData = array; } } - mTemplateRendered = new ConcurrentHashMap<>(); + + if(mDomObject != null && mDomObject.getCellList() != null){ + for(int i=0; i<mDomObject.getCellList().size(); i++){ + addChild(DomTreeBuilder.buildTree(mDomObject.getCellList().get(i), this)); + } + } } @Override @@ -206,8 +214,13 @@ public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> imp bounceRecyclerView.getInnerView().addItemDecoration(RecyclerTransform.parseTransforms(getOrientation(), transforms)); } mItemAnimator = bounceRecyclerView.getInnerView().getItemAnimator(); + + if(attrs.get(NAME_TEMPLATE_CACHE_SIZE) != null){ + templateCacheSize = WXUtils.getInteger(attrs.get(NAME_TEMPLATE_CACHE_SIZE), templateCacheSize); + } + boolean hasFixedSize = false; - int itemViewCacheSize = 4; + int itemViewCacheSize = 2; if(attrs.get(NAME_ITEM_VIEW_CACHE_SIZE) != null){ itemViewCacheSize = WXUtils.getNumberInt(getDomObject().getAttrs().get(NAME_ITEM_VIEW_CACHE_SIZE), itemViewCacheSize); } @@ -217,7 +230,9 @@ public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> imp RecyclerViewBaseAdapter recyclerViewBaseAdapter = new RecyclerViewBaseAdapter<>(this); recyclerViewBaseAdapter.setHasStableIds(true); bounceRecyclerView.getInnerView().setItemAnimator(null); - bounceRecyclerView.getInnerView().setItemViewCacheSize(itemViewCacheSize); + if(itemViewCacheSize != 2) { + bounceRecyclerView.getInnerView().setItemViewCacheSize(itemViewCacheSize); + } bounceRecyclerView.getInnerView().setHasFixedSize(hasFixedSize); bounceRecyclerView.setRecyclerViewBaseAdapter(recyclerViewBaseAdapter); bounceRecyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER); @@ -302,6 +317,9 @@ public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> imp if(getHostView() != null && getHostView().getRecyclerViewBaseAdapter() != null){ getHostView().getRecyclerViewBaseAdapter().notifyDataSetChanged(); } + if(WXEnvironment.isApkDebugable()){ + WXLogUtils.d(TAG, "WXTemplateList notifyDataSetChanged"); + } } }; return bounceRecyclerView; @@ -537,7 +555,9 @@ public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> imp @Override public void addChild(WXComponent child, int index) { - super.addChild(child, index); + if(!(child instanceof WXCell)) { + super.addChild(child, index); + } if(child instanceof WXBaseRefresh){ return; } @@ -546,19 +566,18 @@ public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> imp Object templateId = child.getDomObject().getAttrs().get(Constants.Name.Recycler.SLOT_TEMPLATE_TYPE); String key = WXUtils.getString(templateId, null); if(key != null){ - //set visible false, skip layout in dom thread, set visible true in onCreateViewHolder - if(child.getDomObject() != null) { - WXDomObject domObject = (WXDomObject) child.getDomObject(); - domObject.setVisible(false); + if(child.getDomObject() instanceof WXCellDomObject + && getDomObject() instanceof WXRecyclerDomObject){ + WXCellDomObject domObject = (WXCellDomObject) child.getDomObject(); + domObject.setRecyclerDomObject((WXRecyclerDomObject) getDomObject()); } - mTemplates.put(key, (WXCell) child); - asyncPreloadCellCopyCache(key); + mTemplateSources.put(key, (WXCell) child); + ensureSourceCellRenderWithData((WXCell)child); if(mTemplateViewTypes.get(key) == null){ mTemplateViewTypes.put(key, mTemplateViewTypes.size()); } } } - cellLifecycleManager.filterLifecycleWatchEvent((WXCell)child, child); notifyUpdateList(); } } @@ -602,21 +621,6 @@ public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> imp } - /** - * To determine whether an animation is needed - * @param child - * @return - */ - private boolean isRemoveAnimation(WXComponent child) { - ImmutableDomObject domObject = child.getDomObject(); - if (domObject != null) { - Object attr = domObject.getAttrs().get(Constants.Name.DELETE_CELL_ANIMATION); - if (Constants.Value.DEFAULT.equals(attr)) { - return true; - } - } - return false; - } @Override public void computeVisiblePointInViewCoordinate(PointF pointF) { @@ -727,23 +731,13 @@ public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> imp @JSMethod public void setListData(Object param){ - if(listData != null){ - for(int i=0;i<listData.size(); i++){ - cellLifecycleManager.onDestory(i); - } - } - boolean update = listData != null; + boolean update = listData != null && listData != param; if(param instanceof JSONArray){ listData = (JSONArray) param; } if(update){ notifyUpdateList(); } - if(listData != null){ - for(int i=0; i<listData.size(); i++){ - cellLifecycleManager.onCreate(i); - } - } } @JSMethod @@ -751,14 +745,9 @@ public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> imp if(listData == null){ listData = new JSONArray(); } - int position = listData.size(); if(arrayObject instanceof JSONArray){ listData.addAll(arrayObject); } - int end = listData.size(); - for(int i=position; i<end; i++){ - cellLifecycleManager.onCreate(position); - } notifyUpdateList(); } @@ -771,7 +760,6 @@ public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> imp return; } listData.add(index, data); - cellLifecycleManager.onInsert(index); notifyUpdateList(); } @@ -783,13 +771,7 @@ public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> imp if(listData == null || index >= listData.size()){ return; } - int before = getItemViewType(index); listData.set(index, data); - int after = getItemViewType(index); - if(before != after){ - cellLifecycleManager.onDestory(index); - cellLifecycleManager.onCreate(index); - } notifyUpdateList(); } @@ -806,15 +788,7 @@ public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> imp } index -= offset; if(index < listData.size()){ - int markPostion = listData.size() - 1; - cellLifecycleManager.onDestory(index); listData.remove((int)index); - if(index < listData.size()){ - cellLifecycleManager.getFiredCreateEvent().put(index, true); - } - if(markPostion >= 0){ - cellLifecycleManager.getFiredCreateEvent().remove(markPostion); - } offset++; } } @@ -1002,8 +976,8 @@ public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> imp if(mTemplateViewTypes != null){ mTemplateViewTypes.clear(); } - if(mTemplates != null){ - mTemplates.clear(); + if(mTemplateSources != null){ + mTemplateSources.clear(); } if(mAppearHelpers != null){ mAppearHelpers.clear(); @@ -1017,8 +991,7 @@ public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> imp @Override - public void onViewRecycled(TemplateViewHolder holder) { - } + public void onViewRecycled(TemplateViewHolder holder) {} @Override public void onBindViewHolder(final TemplateViewHolder templateViewHolder, int position) { @@ -1029,110 +1002,96 @@ public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> imp if(component == null){ return; } - cellLifecycleManager.onDetach(templateViewHolder.getHolderPosition(), component); long start = System.currentTimeMillis(); + boolean async = templateViewHolder.getHolderPosition() >= 0; templateViewHolder.setHolderPosition(position); - Statements.doRender(component, getStackContextForPosition(position)); - if(WXEnvironment.isApkDebugable()){ - WXLogUtils.d(TAG, position + getTemplateKey(position) + " onBindViewHolder render used " + (System.currentTimeMillis() - start)); - } - Layouts.doLayoutAsync(templateViewHolder); - cellLifecycleManager.onAttach(position, component); - if(WXEnvironment.isApkDebugable()){ - WXLogUtils.d(TAG, position + getTemplateKey(position) + " onBindViewHolder layout used " + (System.currentTimeMillis() - start)); + Object data = listData.get(position); + if(component.getRenderData() == data){ + if(!async){ + if(!component.isHasLayout()) { + Layouts.doLayoutAsync(templateViewHolder, async); + } + if(WXEnvironment.isApkDebugable()){ + WXLogUtils.d(TAG, position + getTemplateKey(position) + " onBindViewHolder source layout used " + (System.currentTimeMillis() - start) + async); + } + } + component.setHasLayout(true); + }else{ + List<WXComponent> updates = Statements.doRender(component, getStackContextForPosition(position, data)); + Statements.doInitCompontent(updates); + component.setRenderData(data); + if(WXEnvironment.isApkDebugable()){ + WXLogUtils.d(TAG, position + getTemplateKey(position) + " onBindViewHolder render used " + (System.currentTimeMillis() - start)); + } + if(component.isHasLayout()){ + async = true; + } + Layouts.doLayoutAsync(templateViewHolder, async); + component.setHasLayout(true); + if(WXEnvironment.isApkDebugable()){ + WXLogUtils.d(TAG, position + getTemplateKey(position) + " onBindViewHolder layout used " + (System.currentTimeMillis() - start) + async); + } } } @Override public TemplateViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { String template = mTemplateViewTypes.keyAt(viewType); - WXCell source = mTemplates.get(template); + WXCell source = mTemplateSources.get(template); if(source == null){ FrameLayout view = new FrameLayout(getContext()); view.setLayoutParams(new FrameLayout.LayoutParams(0, 0)); return new TemplateViewHolder(view, viewType); } - long start = System.currentTimeMillis(); - WXCell component = mTemplatesCache.remove(template); - boolean needLayout = false; - if(component == null) { - component = (WXCell) copyCell(source); - needLayout = true; + TemplateCache cache = mTemplatesCache.get(template); + WXCell component = null; + boolean cacheHit = true; + if(cache != null && cache.cells != null && cache.cells.size() > 0){ + component = cache.cells.poll(); } - asyncPreloadCellCopyCache(template); - CSSLayoutContext layoutContext = null; - if(needLayout){ - layoutContext = new CSSLayoutContext(); - Layouts.doSafeLayout(component, layoutContext); - if(WXEnvironment.isApkDebugable()){ - WXLogUtils.d(TAG, template + " onCreateViewHolder sync layout used " + (System.currentTimeMillis() - start)); - } + if(cache == null || !cache.isLoadIng){ + asyncLoadTemplateCache(template); } - Layouts.setLayout(component, false); - component.lazy(false); - component.createView(); - if(WXEnvironment.isApkDebugable()){ - WXLogUtils.d(TAG, template + " onCreateViewHolder view used " + (System.currentTimeMillis() - start)); + if(component == null){ + cacheHit = false; + if(!source.isSourceUsed()){ + source.setSourceUsed(true); + ensureSourceCellRenderWithData(source); + component = source; + if(WXEnvironment.isApkDebugable()) { + WXLogUtils.d(TAG, template + " onCreateViewHolder source"); + } + } } - component.applyLayoutAndEvent(component); - if(WXEnvironment.isApkDebugable()) { - WXLogUtils.d(TAG, template + " onCreateViewHolder apply layout used " + (System.currentTimeMillis() - start)); + if(component == null) { + long start = System.currentTimeMillis(); + component = (WXCell) copyCell(source); + if(WXEnvironment.isApkDebugable()) { + WXLogUtils.d(TAG, template + " onCreateViewHolder copy used " + (System.currentTimeMillis() - start)); + } } - component.bindData(component); - if(WXEnvironment.isApkDebugable()) { - WXLogUtils.d(TAG, template + " onCreateViewHolder bindData used " + (System.currentTimeMillis() - start)); + if(component.isLazy()) { + doInitLazyCell(component, template, false); + if(WXEnvironment.isApkDebugable()) { + WXLogUtils.d(TAG, template + " onCreateViewHolder cache hit " + cacheHit + " idle init false "); + } + }else{ + if(WXEnvironment.isApkDebugable()) { + WXLogUtils.d(TAG, template + " onCreateViewHolder cache hit " + cacheHit + " idle init true"); + } } TemplateViewHolder templateViewHolder = new TemplateViewHolder(component, viewType); - templateViewHolder.setLayoutContext(layoutContext); return templateViewHolder; } - private void asyncPreloadCellCopyCache(final String template) { - final WXCell cell = mTemplates.get(template); - if(cell == null){ - return; - } - if(mTemplatesCache.get(template) != null){ - return; - } - AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() { - @Override - public void run() { - if(cell.getInstance() == null || cell.getInstance().isDestroy()){ - return; - } - WXCell component = (WXCell) copyCell(cell); - if(cell.getInstance() == null || cell.getInstance().isDestroy()){ - return; - } - Layouts.doSafeLayout(component, new CSSLayoutContext()); - mTemplatesCache.put(template, component); - } - }); - } /** - * copy cell component from source, and return source + * copy cell component from source, init render data, and return source + * if none data, return null * */ - private WXComponent copyCell(WXComponent cell){ - /** pre render for cell */ - Boolean rendered = mTemplateRendered.get(cell.getRef()); - if(rendered == null || !rendered) { - if(listData != null){ - for(int i=0; i<listData.size(); i++){ - WXCell source = getSourceTemplate(i); - if(source == cell){ - Statements.doRender(cell, getStackContextForPosition(i)); - mTemplateRendered.put(source.getRef(), true); - break; - } - } - } - } + private WXComponent copyCell(WXCell cell){ + ensureSourceCellRenderWithData(cell); WXCell component = (WXCell) Statements.copyComponentTree(cell); - if(component.getDomObject() != null){ - ((WXDomObject)component.getDomObject()).setVisible(true); - } if(component.getDomObject() instanceof WXCellDomObject && getDomObject() instanceof WXRecyclerDomObject){ WXCellDomObject domObject = (WXCellDomObject) component.getDomObject(); @@ -1141,6 +1100,26 @@ public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> imp return component; } + private void ensureSourceCellRenderWithData(WXCell cell){ + if(cell.getRenderData() == null){ + if(listData != null && listData.size() > 0){ + synchronized (this){ + if(cell.getRenderData() == null){ + for(int i=0; i<listData.size(); i++){ + if(cell == getSourceTemplate(i)){ + Object data = listData.get(i); + Statements.doRender(cell, getStackContextForPosition(i, data)); + cell.setRenderData(data); + //WXSDKManager.getInstance().getWXDomManager().postAction(getInstanceId(), new RenderSourceCellAction(cell, null, data), false); + break; + } + } + } + } + } + } + } + /** * @param position * when template not send, return an invalid id, use empty view holder. @@ -1164,14 +1143,19 @@ public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> imp /** * return code context for render component * */ - private ArrayStack getStackContextForPosition(int position){ - ArrayStack stack = new ArrayStack(); - Map map = new HashMap(); + private ArrayStack getStackContextForPosition(int position, Object item){ + if(!bindIngStackContext.isEmpty()){ + bindIngStackContext.getList().clear(); + } + if(!bindIngMapContext.isEmpty()){ + bindIngMapContext.clear(); + } + ArrayStack stack = bindIngStackContext; + Map map = bindIngMapContext; if(listData != null){ stack.push(listData); stack.push(map); map.put(listDataKey, listData); - Object item = listData.get(position); if(!TextUtils.isEmpty(listDataIndexKey)) { map.put(listDataIndexKey, position); } @@ -1201,7 +1185,7 @@ public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> imp * */ public WXCell getSourceTemplate(int position){ String template = getTemplateKey(position); - return mTemplates.get(template); + return mTemplateSources.get(template); } @@ -1236,7 +1220,7 @@ public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> imp if(mTemplateViewTypes == null || mTemplateViewTypes.size() <= 1){ return 0; } - if(mTemplates == null || mTemplates.size() == 0){ + if(mTemplateSources == null || mTemplateSources.size() == 0){ return 0; } return listData.size(); @@ -1385,7 +1369,7 @@ public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> imp if(map == null){ continue; } - WXCell template = mTemplates.get(getTemplateKey(position)); + WXCell template = mTemplateSources.get(getTemplateKey(position)); if(template == null){ return; } @@ -1420,15 +1404,16 @@ public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> imp } private void notifyUpdateList(){ - if(getHostView() != null - && listUpdateRunnable != null - && getHostView().getInnerView() != null){ - if(Looper.getMainLooper().getThread().getId() != Thread.currentThread().getId()){ - getHostView().removeCallbacks(listUpdateRunnable); - getHostView().post(listUpdateRunnable); - }else{ - listUpdateRunnable.run(); - } + if(getHostView() == null + || getHostView().getInnerView() == null + || listUpdateRunnable == null){ + return; + } + if(Looper.getMainLooper().getThread().getId() != Thread.currentThread().getId()){ + getHostView().removeCallbacks(listUpdateRunnable); + getHostView().post(listUpdateRunnable); + }else{ + listUpdateRunnable.run(); } } @@ -1545,4 +1530,126 @@ public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> imp } return componentList; } + + + /** + * copy cell async and save to cache + * */ + private void asyncLoadTemplateCache(final String template) { + if(Thread.currentThread() != Looper.getMainLooper().getThread()){ + if(listData == null || listData.size() == 0){ + return; + } + boolean firstScreenContains = false; + for(int i=0; i<listData.size(); i++){ + if(template.equals(getTemplateKey(i))){ + firstScreenContains = true; + break; + } + } + if(!firstScreenContains){ + return; + } + } + final WXCell source = mTemplateSources.get(template); + if(source == null){ + return; + } + TemplateCache cellCache = mTemplatesCache.get(template); + if(cellCache == null){ + cellCache = new TemplateCache(); + mTemplatesCache.put(template, cellCache); + } + if(cellCache.cells.size() >= templateCacheSize){ + cellCache.isLoadIng = false; + return; + } + if(cellCache.isLoadIng){ + return; + } + cellCache.isLoadIng = true; + AsyncTask<Void,Void, Void> preloadTask = new AsyncTask<Void, Void, Void>() { + @Override + protected Void doInBackground(Void... params) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + TemplateCache cellCache = mTemplatesCache.get(template); + if(cellCache == null || cellCache.cells == null){ + return null; + } + while (cellCache.cells.size() < templateCacheSize){ + WXCell component = (WXCell) copyCell(source); + if(component == null){ + return null; + } + if(source.getInstance() == null || source.getInstance().isDestroy()){ + return null; + } + cellCache.cells.add(component); + } + return null; + } + @Override + protected void onPostExecute(Void aVoid) { + if(source.getInstance() == null || source.getInstance().isDestroy()){ + return; + } + final TemplateCache cellCache = mTemplatesCache.get(template); + if(cellCache == null){ + return; + } + if(cellCache.cells == null + || cellCache.cells.size() == 0){ + cellCache.isLoadIng = false; + return; + } + Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() { + @Override + public boolean queueIdle() { + if(source.getInstance() == null || source.getInstance().isDestroy()){ + return false; + } + ConcurrentLinkedQueue<WXCell> queue = cellCache.cells; + Iterator<WXCell> iterator = queue.iterator(); + while (iterator.hasNext()){ + WXCell component = iterator.next(); + if(component.isLazy()){ + doInitLazyCell(component, template, true); + return iterator.hasNext(); + } + if(!component.isHasLayout()){ + Layouts.doSafeLayout(component, new CSSLayoutContext()); + component.setHasLayout(true); + } + } + return false; + } + }); + cellCache.isLoadIng = false; + } + }; + preloadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + + private static void doInitLazyCell(WXCell component, String template, boolean inPreload){ + if(component.isLazy()){ + long start = System.currentTimeMillis(); + component.lazy(false); + component.createView(); + if(WXEnvironment.isApkDebugable()) { + WXLogUtils.d(TAG, "doInitLazyCell " + inPreload + template + " createView used " + (System.currentTimeMillis() - start)); + } + component.applyLayoutAndEvent(component); + if(WXEnvironment.isApkDebugable()) { + WXLogUtils.d(TAG, "doInitLazyCell " + inPreload + template + " apply layout used " + (System.currentTimeMillis() - start)); + } + component.bindData(component); + if(WXEnvironment.isApkDebugable()) { + WXLogUtils.d(TAG, "doInitLazyCell " + inPreload + template + " bindData used " + (System.currentTimeMillis() - start)); + } + } + } } http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/9e6bee8e/android/sdk/src/test/java/com/taobao/weex/ui/component/binding/StatementTest.java ---------------------------------------------------------------------- diff --git a/android/sdk/src/test/java/com/taobao/weex/ui/component/binding/StatementTest.java b/android/sdk/src/test/java/com/taobao/weex/ui/component/binding/StatementTest.java index 3566816..3924a3a 100644 --- a/android/sdk/src/test/java/com/taobao/weex/ui/component/binding/StatementTest.java +++ b/android/sdk/src/test/java/com/taobao/weex/ui/component/binding/StatementTest.java @@ -76,7 +76,7 @@ public class StatementTest { public void testVFor() throws Exception { WXCell cell = createVForNode(); int count = 3; - Statements.doRenderComponent(cell, createContext(count)); + Statements.doRender(cell, createContext(count)); Assert.assertTrue(cell.getChildCount() == 1); WXDiv div = (WXDiv) cell.getChild(0); Assert.assertEquals(div.getChildCount(), count); @@ -88,7 +88,7 @@ public class StatementTest { WXComponent childThree = div.getChild(2); count = 4; - Statements.doRenderComponent(cell, createContext(count)); + Statements.doRender(cell, createContext(count)); Assert.assertTrue(cell.getChildCount() == 1); div = (WXDiv) cell.getChild(0); Assert.assertTrue(div.getChildCount() == count); @@ -98,7 +98,7 @@ public class StatementTest { WXComponent childFour = div.getChild(3); count = 5; - Statements.doRenderComponent(cell, createContext(count)); + Statements.doRender(cell, createContext(count)); Assert.assertTrue(cell.getChildCount() == 1); div = (WXDiv) cell.getChild(0); Assert.assertTrue(div.getChildCount() == count); @@ -109,7 +109,7 @@ public class StatementTest { count = 3; - Statements.doRenderComponent(cell, createContext(count)); + Statements.doRender(cell, createContext(count)); Assert.assertTrue(cell.getChildCount() == 1); div = (WXDiv) cell.getChild(0); Assert.assertTrue(div.getChildCount() == 5);