[WEEX-174][android] TemplateList Support Lifecycle and statefull component

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

Branch: refs/heads/master
Commit: 886d859ab75ef892aad50506dace5818c06b66d2
Parents: 20c293f
Author: jianbai.gbj <jianbai....@alibaba-inc.com>
Authored: Wed Dec 20 15:07:01 2017 +0800
Committer: jianbai.gbj <jianbai....@alibaba-inc.com>
Committed: Thu Feb 8 11:55:09 2018 +0800

----------------------------------------------------------------------
 .../java/com/alibaba/weex/WXApplication.java    |   6 +-
 .../weex/extend/module/WXWsonTestModule.java    |  58 ++
 .../java/com/taobao/weex/WXEnvironment.java     |  17 +-
 .../com/taobao/weex/bridge/WXBridgeManager.java | 112 +++-
 .../java/com/taobao/weex/common/Constants.java  |   7 +-
 .../main/java/com/taobao/weex/dom/WXAttr.java   |  19 +-
 .../java/com/taobao/weex/dom/WXDomModule.java   |   7 +-
 .../java/com/taobao/weex/dom/WXDomObject.java   |  29 +-
 .../main/java/com/taobao/weex/dom/WXEvent.java  |  91 +--
 .../main/java/com/taobao/weex/dom/WXStyle.java  |  54 ++
 .../dom/action/AbstractAddElementAction.java    |  15 +-
 .../com/taobao/weex/dom/action/Actions.java     |   6 +
 .../weex/dom/action/AddElementAction.java       |   8 +-
 .../weex/dom/action/UpdateAttributeAction.java  |   6 +-
 .../dom/action/UpdateComponentDataAction.java   |  69 +++
 .../com/taobao/weex/dom/binding/ELUtils.java    |   1 +
 .../taobao/weex/dom/binding/WXStatement.java    |   6 +
 .../java/com/taobao/weex/el/parse/Block.java    |   3 +-
 .../java/com/taobao/weex/el/parse/Operator.java |   3 +-
 .../com/taobao/weex/el/parse/Operators.java     |  11 +-
 .../java/com/taobao/weex/el/parse/Token.java    |   3 +-
 .../weex/ui/component/ComponentUtils.java       | 122 ++++
 .../taobao/weex/ui/component/WXComponent.java   | 110 +++-
 .../weex/ui/component/binding/Layouts.java      |  23 +-
 .../weex/ui/component/binding/Statements.java   | 224 +++++--
 .../taobao/weex/ui/component/list/WXCell.java   |  18 +-
 .../list/template/AsyncCellLoadTask.java        | 128 ++++
 .../list/template/CellDataManager.java          | 272 +++++++++
 .../list/template/CellRenderContext.java        |  79 +++
 .../list/template/CellRenderState.java          | 122 ++++
 .../component/list/template/DomTreeBuilder.java | 100 ---
 .../ui/component/list/template/PositionRef.java |  64 ++
 .../template/VirtualComponentLifecycle.java     |  45 ++
 .../list/template/WXRecyclerTemplateList.java   | 610 ++++++++++---------
 .../java/com/taobao/weex/el/FailedCaseTest.java |  50 ++
 .../ui/component/binding/StatementTest.java     |   8 +-
 36 files changed, 1940 insertions(+), 566 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/886d859a/android/playground/app/src/main/java/com/alibaba/weex/WXApplication.java
----------------------------------------------------------------------
diff --git 
a/android/playground/app/src/main/java/com/alibaba/weex/WXApplication.java 
b/android/playground/app/src/main/java/com/alibaba/weex/WXApplication.java
index 41ca4cb..0561043 100644
--- a/android/playground/app/src/main/java/com/alibaba/weex/WXApplication.java
+++ b/android/playground/app/src/main/java/com/alibaba/weex/WXApplication.java
@@ -38,6 +38,7 @@ import com.alibaba.weex.extend.module.RenderModule;
 import com.alibaba.weex.extend.module.SyncTestModule;
 import com.alibaba.weex.extend.module.WXEventModule;
 import com.alibaba.weex.extend.module.WXTitleBar;
+import com.alibaba.weex.extend.module.WXWsonTestModule;
 import com.facebook.drawee.backends.pipeline.Fresco;
 import com.taobao.weex.InitConfig;
 import com.taobao.weex.WXEnvironment;
@@ -62,7 +63,8 @@ public class WXApplication extends Application {
      * Fresco.initialize(this,config);
      **/
 //    initDebugEnvironment(true, false, "DEBUG_SERVER_HOST");
-    WXBridgeManager.updateGlobalConfig("wson_off");
+    WXBridgeManager.updateGlobalConfig("wson_on");
+    WXEnvironment.setOpenDebugLog(true);
     WXEnvironment.setApkDebugable(true);
     WXSDKEngine.addCustomOptions("appName", "WXSample");
     WXSDKEngine.addCustomOptions("appGroup", "WXApp");
@@ -95,6 +97,8 @@ public class WXApplication extends Application {
       WXSDKEngine.registerModule("geolocation", GeolocationModule.class);
 
       WXSDKEngine.registerModule("titleBar", WXTitleBar.class);
+
+      WXSDKEngine.registerModule("wsonTest", WXWsonTestModule.class);
       /**
        * override default image tag
        * WXSDKEngine.registerComponent("image", FrescoImageComponent.class);

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/886d859a/android/playground/app/src/main/java/com/alibaba/weex/extend/module/WXWsonTestModule.java
----------------------------------------------------------------------
diff --git 
a/android/playground/app/src/main/java/com/alibaba/weex/extend/module/WXWsonTestModule.java
 
b/android/playground/app/src/main/java/com/alibaba/weex/extend/module/WXWsonTestModule.java
new file mode 100644
index 0000000..b018678
--- /dev/null
+++ 
b/android/playground/app/src/main/java/com/alibaba/weex/extend/module/WXWsonTestModule.java
@@ -0,0 +1,58 @@
+package com.alibaba.weex.extend.module;
+
+import android.util.Log;
+
+import com.alibaba.fastjson.JSONObject;
+import com.taobao.weex.annotation.JSMethod;
+import com.taobao.weex.bridge.JSCallback;
+import com.taobao.weex.common.WXModule;
+import com.taobao.weex.wson.Wson;
+
+/**
+ * Created by furture on 2018/1/18.
+ */
+
+public class WXWsonTestModule extends WXModule {
+
+    @JSMethod(uiThread = false)
+    public boolean callPass(JSONObject params) {
+        if(params.get("refundId") != null){
+            if(params.get("refundId").getClass() != Long.class){
+                Log.e("Weex", "weex wson refundId failed case");
+                return false;
+            }
+            return  ((Long)params.get("refundId")) == 6419458776149741l;
+        }
+
+        if(params.get("refundId2") != null){
+            if(params.get("refundId2").getClass() != Long.class){
+                Log.e("Weex", "weex wson refundId failed case");
+                return false;
+            }
+            return ((Long)params.get("refundId2")) == 64194587761497416l;
+        }
+
+
+
+
+        return true;
+    }
+
+    @JSMethod(uiThread = false)
+    public Object back(JSONObject params) {
+        JSONObject back = new JSONObject(params);
+        back.put("longMax", Long.MAX_VALUE);
+        back.put("longMin", Long.MIN_VALUE);
+        back.put("javaJSON", back.toJSONString());
+        return back;
+    }
+
+    @JSMethod(uiThread = false)
+    public void  backAsync(JSONObject params, JSCallback callback) {
+        JSONObject back = new JSONObject(params);
+        back.put("longMax", Long.MAX_VALUE);
+        back.put("longMin", Long.MIN_VALUE);
+        back.put("javaJSON", back.toJSONString());
+        callback.invoke(back);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/886d859a/android/sdk/src/main/java/com/taobao/weex/WXEnvironment.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/WXEnvironment.java 
b/android/sdk/src/main/java/com/taobao/weex/WXEnvironment.java
index e19570f..e6084d9 100644
--- a/android/sdk/src/main/java/com/taobao/weex/WXEnvironment.java
+++ b/android/sdk/src/main/java/com/taobao/weex/WXEnvironment.java
@@ -88,6 +88,8 @@ public class WXEnvironment {
   private static boolean isApkDebug = true;
   public static boolean isPerf = false;
 
+  private static boolean openDebugLog = false;
+
   private static String sGlobalFontFamily;
 
   private static Map<String, String> options = new HashMap<>();
@@ -305,9 +307,20 @@ public class WXEnvironment {
       }
     }
   }
-    
+
+  public static boolean isOpenDebugLog() {
+    return openDebugLog;
+  }
+
+  public static void setOpenDebugLog(boolean openDebugLog) {
+    WXEnvironment.openDebugLog = openDebugLog;
+  }
+
   public static void  setApkDebugable(boolean debugable){
-      isApkDebug  = debugable;
+    isApkDebug  = debugable;
+    if(!isApkDebug){
+       openDebugLog = false;
+    }
   }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/886d859a/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridgeManager.java
----------------------------------------------------------------------
diff --git 
a/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridgeManager.java 
b/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridgeManager.java
index 349b5f8..79e3127 100644
--- a/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridgeManager.java
+++ b/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridgeManager.java
@@ -78,6 +78,8 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Stack;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 import static com.taobao.weex.bridge.WXModuleManager.getDomModule;
 import static com.taobao.weex.bridge.WXModuleManager.createDomModule;
@@ -115,6 +117,7 @@ public class WXBridgeManager implements Callback, 
BactchExecutor {
   public static final String METHOD_REGISTER_COMPONENTS = "registerComponents";
   public static final String METHOD_FIRE_EVENT = "fireEvent";
   public static final String METHD_FIRE_EVENT_SYNC = "fireEventSync";
+  public static final String METHD_COMPONENT_HOOK_SYNC = "componentHook";
   public static final String METHOD_CALLBACK = "callback";
   public static final String METHOD_REFRESH_INSTANCE = "refreshInstance";
   public static final String METHOD_NOTIFY_TRIM_MEMORY = "notifyTrimMemory";
@@ -361,7 +364,7 @@ public class WXBridgeManager implements Callback, 
BactchExecutor {
 
   public Object callNativeModule(String instanceId, String module, String 
method, JSONArray arguments, Object options) {
 
-    if (WXEnvironment.isApkDebugable()) {
+    if (WXEnvironment.isOpenDebugLog()) {
       mLodBuilder.append("[WXBridgeManager] callNativeModule >>>> 
instanceId:").append(instanceId)
           .append(", module:").append(module).append(", 
method:").append(method).append(", arguments:").append(arguments);
       WXLogUtils.d(mLodBuilder.substring(0));
@@ -389,7 +392,7 @@ public class WXBridgeManager implements Callback, 
BactchExecutor {
 
   public Object callNativeModule(String instanceId, String module, String 
method, JSONArray arguments, JSONObject options) {
 
-    if (WXEnvironment.isApkDebugable()) {
+    if (WXEnvironment.isOpenDebugLog()) {
       mLodBuilder.append("[WXBridgeManager] callNativeModule >>>> 
instanceId:").append(instanceId)
           .append(", module:").append(module).append(", 
method:").append(method).append(", arguments:").append(arguments);
       WXLogUtils.d(mLodBuilder.substring(0));
@@ -420,7 +423,7 @@ public class WXBridgeManager implements Callback, 
BactchExecutor {
   }
 
   public Object callNativeComponent(String instanceId, String componentRef, 
String method, JSONArray arguments, Object options) {
-    if (WXEnvironment.isApkDebugable()) {
+    if (WXEnvironment.isOpenDebugLog()) {
       mLodBuilder.append("[WXBridgeManager] callNativeComponent >>>> 
instanceId:").append(instanceId)
           .append(", componentRef:").append(componentRef).append(", 
method:").append(method).append(", arguments:").append(arguments);
       WXLogUtils.d(mLodBuilder.substring(0));
@@ -458,7 +461,7 @@ public class WXBridgeManager implements Callback, 
BactchExecutor {
       return IWXBridge.INSTANCE_RENDERING_ERROR;
     }
 
-    if (WXEnvironment.isApkDebugable()) {
+    if (WXEnvironment.isOpenDebugLog()) {
     mLodBuilder.append("[WXBridgeManager] callNative >>>> 
instanceId:").append(instanceId)
         .append(", tasks:").append(tasks).append(", 
callback:").append(callback);
     WXLogUtils.d(mLodBuilder.substring(0));
@@ -534,12 +537,12 @@ public class WXBridgeManager implements Callback, 
BactchExecutor {
          return IWXBridge.INSTANCE_RENDERING_ERROR;
     }
 
-    // if (WXEnvironment.isApkDebugable()) {
+    if (WXEnvironment.isOpenDebugLog()) {
     mLodBuilder.append("[WXBridgeManager] callCreateBody >>>> 
instanceId:").append(instanceId)
         .append(", tasks:").append(tasks).append(", 
callback:").append(callback);
     WXLogUtils.d(mLodBuilder.substring(0));
     mLodBuilder.setLength(0);
-    // }
+    }
 
 
     if (mDestroyedInstanceId != null && 
mDestroyedInstanceId.contains(instanceId)) {
@@ -581,7 +584,7 @@ public class WXBridgeManager implements Callback, 
BactchExecutor {
 
   // callUpdateFinish
   public int callUpdateFinish(String instanceId, String callback) {
-    if (WXEnvironment.isApkDebugable()) {
+    if (WXEnvironment.isOpenDebugLog()) {
       mLodBuilder.append("[WXBridgeManager] callUpdateFinish >>>> 
instanceId:").append(instanceId)
           .append(", callback:").append(callback);
       WXLogUtils.d(mLodBuilder.substring(0));
@@ -615,12 +618,12 @@ public class WXBridgeManager implements Callback, 
BactchExecutor {
 
   // callCreateFinish
   public int callCreateFinish(String instanceId, String callback) {
-    // if (WXEnvironment.isApkDebugable()) {
+    if (WXEnvironment.isOpenDebugLog()) {
     mLodBuilder.append("[WXBridgeManager] callCreateFinish >>>> 
instanceId:").append(instanceId)
         .append(", callback:").append(callback);
     WXLogUtils.d(mLodBuilder.substring(0));
     mLodBuilder.setLength(0);
-    // }
+     }
 
     if (mDestroyedInstanceId != null && 
mDestroyedInstanceId.contains(instanceId)) {
       return IWXBridge.DESTROY_INSTANCE;
@@ -650,7 +653,7 @@ public class WXBridgeManager implements Callback, 
BactchExecutor {
 
   // callRefreshFinish
   public int callRefreshFinish(String instanceId, String callback) {
-    if (WXEnvironment.isApkDebugable()) {
+    if (WXEnvironment.isOpenDebugLog()) {
       mLodBuilder.append("[WXBridgeManager] callRefreshFinish >>>> 
instanceId:").append(instanceId)
           .append(", callback:").append(callback);
       WXLogUtils.d(mLodBuilder.substring(0));
@@ -693,7 +696,7 @@ public class WXBridgeManager implements Callback, 
BactchExecutor {
 
       return IWXBridge.INSTANCE_RENDERING_ERROR;
     }
-    if (WXEnvironment.isApkDebugable()) {
+    if (WXEnvironment.isOpenDebugLog()) {
       mLodBuilder.append("[WXBridgeManager] callUpdateAttrs >>>> 
instanceId:").append(instanceId)
           .append(", ref:").append(ref)
           .append(", task:").append(task)
@@ -748,7 +751,7 @@ public class WXBridgeManager implements Callback, 
BactchExecutor {
                          "task is empty", null);
          return IWXBridge.INSTANCE_RENDERING_ERROR;
     }
-   if (WXEnvironment.isApkDebugable()) {
+   if (WXEnvironment.isOpenDebugLog()) {
     mLodBuilder.append("[WXBridgeManager] callUpdateStyle >>>> 
instanceId:").append(instanceId)
         .append(", ref:").append(ref)
         .append(", task:").append(task)
@@ -796,7 +799,7 @@ public class WXBridgeManager implements Callback, 
BactchExecutor {
   // callUpdateStyle
   public int callRemoveElement(String instanceId, String ref, String callback) 
{
 
-    if (WXEnvironment.isApkDebugable()) {
+    if (WXEnvironment.isOpenDebugLog()) {
       mLodBuilder.append("[WXBridgeManager] callRemoveElement >>>> 
instanceId:").append(instanceId)
           .append(", ref:").append(ref);
       WXLogUtils.d(mLodBuilder.substring(0));
@@ -835,7 +838,7 @@ public class WXBridgeManager implements Callback, 
BactchExecutor {
   // callMoveElement
   public int callMoveElement(String instanceId, String ref, String parentref, 
String index, String callback) {
 
-    if (WXEnvironment.isApkDebugable()) {
+    if (WXEnvironment.isOpenDebugLog()) {
       mLodBuilder.append("[WXBridgeManager] callMoveElement >>>> 
instanceId:").append(instanceId)
           .append(", parentref:").append(parentref)
           .append(", index:").append(index)
@@ -872,13 +875,13 @@ public class WXBridgeManager implements Callback, 
BactchExecutor {
 
   public int callAddEvent(String instanceId, String ref, String event, String 
callback) {
 
-//    if (WXEnvironment.isApkDebugable()) {
+   if (WXEnvironment.isOpenDebugLog()) {
     mLodBuilder.append("[WXBridgeManager] callAddEvent >>>> 
instanceId:").append(instanceId)
         .append(", ref:").append(ref)
         .append(", event:").append(event);
     WXLogUtils.d(mLodBuilder.substring(0));
     mLodBuilder.setLength(0);
-//    }
+   }
 
     if (mDestroyedInstanceId != null && 
mDestroyedInstanceId.contains(instanceId)) {
       return IWXBridge.DESTROY_INSTANCE;
@@ -911,7 +914,7 @@ public class WXBridgeManager implements Callback, 
BactchExecutor {
 
   public int callRemoveEvent(String instanceId, String ref, String event, 
String callback) {
 
-    if (WXEnvironment.isApkDebugable()) {
+    if (WXEnvironment.isOpenDebugLog()) {
       mLodBuilder.append("[WXBridgeManager] callRemoveEvent >>>> 
instanceId:").append(instanceId)
           .append(", ref:").append(ref)
           .append(", event:").append(event);
@@ -950,7 +953,7 @@ public class WXBridgeManager implements Callback, 
BactchExecutor {
 
   public int callAddElement(String instanceId, String ref, JSONObject dom, 
String index, String callback) {
 
-    if (WXEnvironment.isApkDebugable()) {
+    if (WXEnvironment.isOpenDebugLog()) {
       mLodBuilder.append("[WXBridgeManager] callNative::callAddElement >>>> 
instanceId:").append(instanceId)
           .append(", ref:").append(ref).append(", dom:").append(dom).append(", 
callback:").append(callback);
       WXLogUtils.d(mLodBuilder.substring(0));
@@ -1108,9 +1111,68 @@ public class WXBridgeManager implements Callback, 
BactchExecutor {
   }
 
 
+
   /**
-   * aync call js event and return result in eventResult callback
+   * ref, type, data, domChanges
    * */
+  public EventResult syncCallJSEventWithResult(final String method, final 
String instanceId, final List<Object> params, final Object... args) {
+    final CountDownLatch waitLatch = new CountDownLatch(1);
+    EventResult callback = new EventResult(){
+      @Override
+      public void onCallback(Object result) {
+        super.onCallback(result);
+        waitLatch.countDown();
+      }
+    };
+    try{
+      asyncCallJSEventWithResult(callback, method, instanceId, params, args);
+      waitLatch.await(100, TimeUnit.MILLISECONDS);
+      return  callback;
+    }catch (Exception e){
+      WXLogUtils.e("syncCallJSEventWithResult", e);
+      return  callback;
+    }
+  }
+
+  public void asyncCallJSEventVoidResult(final String method, final String 
instanceId, final List<Object> params, final Object... args) {
+    post(new Runnable() {
+      @Override
+      public void run() {
+        try{
+          if (args == null || args.length == 0) {
+            return;
+          }
+
+          ArrayList<Object> argsList = new ArrayList<>();
+          for (Object arg : args) {
+            argsList.add(arg);
+          }
+          if (params != null) {
+            ArrayMap map = new ArrayMap(4);
+            map.put(KEY_PARAMS, params);
+            argsList.add(map);
+          }
+
+          WXHashMap<String, Object> task = new WXHashMap<>();
+          task.put(KEY_METHOD, method);
+          task.put(KEY_ARGS, argsList);
+          Object[] tasks = {task};
+          WXJSObject[] jsArgs = {
+                  new WXJSObject(WXJSObject.String, instanceId),
+                  WXJsonUtils.wsonWXJSObject(tasks)};
+          invokeExecJS(String.valueOf(instanceId), null, METHOD_CALL_JS, 
jsArgs, true);
+          jsArgs[0] = null;
+          jsArgs = null;
+        }catch (Exception e){
+          WXLogUtils.e("asyncCallJSEventVoidResult" , e);
+        }
+      }
+    });
+  }
+
+    /**
+     * aync call js event and return result in eventResult callback
+     * */
   private void asyncCallJSEventWithResult(final EventResult eventCallback, 
final String method, final String instanceId, final List<Object> params, final 
Object... args) {
     post(new Runnable() {
       @Override
@@ -1153,7 +1215,7 @@ public class WXBridgeManager implements Callback, 
BactchExecutor {
           taskResult = null;
           jsArgs = null;
         }catch (Exception e){
-          WXLogUtils.e("asyncCallJSEventWithResult ");
+          WXLogUtils.e("asyncCallJSEventWithResult" , e);
         }
       }
     });
@@ -1363,7 +1425,7 @@ public class WXBridgeManager implements Callback, 
BactchExecutor {
         return;
       }
       long start = System.currentTimeMillis();
-      if (WXEnvironment.isApkDebugable()) {
+      if (WXEnvironment.isOpenDebugLog()) {
         WXLogUtils.d("refreshInstance >>>> instanceId:" + instanceId
             + ", data:" + refreshData.data + ", isDirty:" + 
refreshData.isDirty);
       }
@@ -1524,7 +1586,7 @@ public class WXBridgeManager implements Callback, 
BactchExecutor {
         return;
       }
       try {
-        if (WXEnvironment.isApkDebugable()) {
+        if (WXEnvironment.isOpenDebugLog()) {
           WXLogUtils.d("createInstance >>>> instanceId:" + 
instance.getInstanceId()
               + ", options:"
               + WXJsonUtils.fromObjectToJSONString(options)
@@ -1584,7 +1646,7 @@ public class WXBridgeManager implements Callback, 
BactchExecutor {
 
   private void invokeDestroyInstance(String instanceId) {
     try {
-      if (WXEnvironment.isApkDebugable()) {
+      if (WXEnvironment.isOpenDebugLog()) {
         WXLogUtils.d("destroyInstance >>>> instanceId:" + instanceId);
       }
       WXJSObject instanceIdObj = new WXJSObject(WXJSObject.String,
@@ -1642,7 +1704,7 @@ public class WXBridgeManager implements Callback, 
BactchExecutor {
 
   public void invokeExecJS(String instanceId, String namespace, String 
function,
                            WXJSObject[] args, boolean logTaskDetail) {
-     if (WXEnvironment.isApkDebugable()) {
+     if (WXEnvironment.isOpenDebugLog()) {
       mLodBuilder.append("callJS >>>> instanceId:").append(instanceId)
           .append("function:").append(function);
       if (logTaskDetail) {
@@ -1656,7 +1718,7 @@ public class WXBridgeManager implements Callback, 
BactchExecutor {
 
   private byte[] invokeExecJSWithResult(String instanceId, String namespace, 
String function,
                                        WXJSObject[] args,boolean 
logTaskDetail){
-    if (WXEnvironment.isApkDebugable()) {
+    if (WXEnvironment.isOpenDebugLog()) {
       mLodBuilder.append("callJS >>>> instanceId:").append(instanceId)
               .append("function:").append(function);
       if(logTaskDetail) {

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/886d859a/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 66c4df0..c107ee8 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
@@ -207,10 +207,9 @@ public class Constants {
       String LIST_DATA = "listData";
       String LIST_DATA_ITEM  ="alias";
       String LIST_DATA_ITEM_INDEX = "index";
-      String LIST_DATA_TEMPLATE_KEY = "templateKey";
-
-      String SLOT_TEMPLATE_TYPE = "templateType";
-      String LIST_DATA_ITEM_ID = "itemId";
+      String LIST_DATA_TEMPLATE_SWITCH_KEY = "switch";
+      String SLOT_TEMPLATE_CASE = "case";
+      String SLOT_TEMPLATE_DEFAULT = "default";
       String CELL_INDEX = "cellIndex";
       String TYPE_INDEX = "typeIndex";
     }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/886d859a/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 b05d46d..1025584 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
@@ -455,7 +455,7 @@ public class WXAttr implements Map<String, 
Object>,Cloneable {
   /**
    * filter dynamic state ment
    * */
-  private Map<String, Object> filterBindingStatement(Map attrs) {
+  public Map<String, Object> filterBindingStatement(Map attrs) {
     if(attrs == null || attrs.size() == 0){
       return attrs;
     }
@@ -511,6 +511,13 @@ public class WXAttr implements Map<String, 
Object>,Cloneable {
               return  true;
            }
         }
+
+        if(WXStatement.WX_ONCE.equals(key)){
+          if(mStatement == null){
+             mStatement = new WXStatement();
+          }
+          mStatement.put(key, true);
+        }
         return  false;
   }
 
@@ -519,11 +526,15 @@ public class WXAttr implements Map<String, 
Object>,Cloneable {
   }
 
   @Override
-  protected WXAttr clone(){
+  protected WXAttr clone() {
     WXAttr wxAttr = new WXAttr();
     wxAttr.skipFilterPutAll(attr);
-    wxAttr.mBindingAttrs = mBindingAttrs;
-    wxAttr.mStatement = mStatement;
+    if (mBindingAttrs != null) {
+      wxAttr.mBindingAttrs = new ArrayMap<>(mBindingAttrs);
+    }
+    if (mStatement != null){
+       wxAttr.mStatement = new WXStatement(mStatement);
+     }
     return wxAttr;
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/886d859a/android/sdk/src/main/java/com/taobao/weex/dom/WXDomModule.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/WXDomModule.java 
b/android/sdk/src/main/java/com/taobao/weex/dom/WXDomModule.java
index 7ab97a9..b764630 100644
--- a/android/sdk/src/main/java/com/taobao/weex/dom/WXDomModule.java
+++ b/android/sdk/src/main/java/com/taobao/weex/dom/WXDomModule.java
@@ -61,6 +61,9 @@ public final class WXDomModule extends WXModule {
   public static final String UPDATE_FINISH = "updateFinish";
   public static final String SCROLL_TO_ELEMENT = "scrollToElement";
   public static final String ADD_RULE = "addRule";
+
+  public static final String UPDATE_COMPONENT_DATA = "updateComponentData";
+
   public static final String GET_COMPONENT_RECT = "getComponentRect";
 
   public static final String WXDOM = "dom";
@@ -97,7 +100,9 @@ public final class WXDomModule extends WXModule {
     try {
       Action action = Actions.get(method,args);
       if(action == null){
-        WXLogUtils.e("Unknown dom action.");
+         WXLogUtils.e("Unknown dom action "
+                 +  method + " "  + args.toJSONString());
+         return null;
       }
       if(action instanceof DOMAction){
         postAction((DOMAction)action, CREATE_BODY.equals(method) || 
ADD_RULE.equals(method));

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/886d859a/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 d062a8a..dde66dc 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
@@ -134,6 +134,27 @@ public class WXDomObject extends CSSNode implements 
Cloneable,ImmutableDomObject
     mDomThreadNanos += (System.nanoTime() - startNanos);
   }
 
+  /**
+   * diff with tranverse tree, only tranverse update tree
+   * */
+  public void traverseUpdateTree(Consumer...consumers){
+    if (consumers == null) {
+      return;
+    }
+    if(!hasUpdate()){
+      return;
+    }
+    for (Consumer consumer:consumers){
+      consumer.accept(this);
+    }
+    int count = childCount();
+    WXDomObject child;
+    for (int i = 0; i < count; ++i) {
+      child = getChild(i);
+      child.traverseTree(consumers);
+    }
+  }
+
 
   public int getViewPortWidth() {
     return mViewPortWidth;
@@ -230,15 +251,13 @@ public class WXDomObject extends CSSNode implements 
Cloneable,ImmutableDomObject
     this.mRef = (String) map.get("ref");
     Object style = map.get("style");
     if (style != null && style instanceof JSONObject) {
-      WXStyle styles = new WXStyle();
-      styles.putAll((JSONObject) style,false);
+      WXStyle styles = new WXStyle((JSONObject) style,false);
       this.mStyles = styles;
       this.transition = WXTransition.fromMap(styles, this);
     }
     Object attr = map.get("attr");
     if (attr != null && attr instanceof JSONObject) {
       WXAttr attrs = new WXAttr((JSONObject) attr);
-      //WXJsonUtils.putAll(attrs, (JSONObject) attr);
       this.mAttributes = attrs;
     }
     Object event = map.get("event");
@@ -470,7 +489,7 @@ public class WXDomObject extends CSSNode implements 
Cloneable,ImmutableDomObject
     if (mAttributes == null) {
       mAttributes = new WXAttr();
     }
-    mAttributes.putAll(updates);
+    mAttributes.skipFilterPutAll(updates);
     if(hasNewLayout()){
       markUpdateSeen();
     }
@@ -658,7 +677,7 @@ public class WXDomObject extends CSSNode implements 
Cloneable,ImmutableDomObject
     if (sDestroy.get()) {
       return null;
     }
-    if(cloneThis){
+    if(isCloneThis()){
       return  this;
     }
     WXDomObject dom = null;

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/886d859a/android/sdk/src/main/java/com/taobao/weex/dom/WXEvent.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/WXEvent.java 
b/android/sdk/src/main/java/com/taobao/weex/dom/WXEvent.java
index fe7f8cf..3e99cfa 100644
--- a/android/sdk/src/main/java/com/taobao/weex/dom/WXEvent.java
+++ b/android/sdk/src/main/java/com/taobao/weex/dom/WXEvent.java
@@ -35,21 +35,29 @@ public class WXEvent extends ArrayList<String> implements 
Serializable, Cloneabl
 
   private static final long serialVersionUID = -8186587029452440107L;
 
+
+  /**
+   *  event data format
+   *  {
+   *  type: 'appear',
+   *  params: [
+   *  { '@binding': 'index' },
+   *   'static',
+   *   { '@binding': 'item.name' },
+   *  { '@binding': '$event' }
+   *  ]
+   *  }
+   * */
+  public static final String EVENT_KEY_TYPE = "type";
+  public static final String EVENT_KEY_ARGS = "params";
+
+
   /**
    * dynamic binding event args, can be null, only weex use
    * */
   private ArrayMap mEventBindingArgs;
   private ArrayMap<String, List<Object>> mEventBindingArgsValues;
 
-
-  @Override
-  public WXEvent clone() {
-    WXEvent event = (WXEvent) super.clone();
-    event.mEventBindingArgs = mEventBindingArgs;
-    event.mEventBindingArgsValues = mEventBindingArgsValues;
-    return  event;
-  }
-
   @Override
   public void clear() {
     if(mEventBindingArgs != null){
@@ -63,13 +71,13 @@ public class WXEvent extends ArrayList<String> implements 
Serializable, Cloneabl
 
 
   public boolean remove(String o) {
-     if(mEventBindingArgs != null){
-        mEventBindingArgs.remove(o);
-     }
-     if(mEventBindingArgsValues != null){
-        mEventBindingArgsValues.remove(o);
-     }
-     return super.remove(o);
+    if(mEventBindingArgs != null){
+      mEventBindingArgs.remove(o);
+    }
+    if(mEventBindingArgsValues != null){
+      mEventBindingArgsValues.remove(o);
+    }
+    return super.remove(o);
   }
 
   /**
@@ -89,14 +97,14 @@ public class WXEvent extends ArrayList<String> implements 
Serializable, Cloneabl
     if(event instanceof CharSequence){
       String eventName = event.toString();
       if(!contains(eventName)){
-          add(eventName);
+        add(eventName);
       }
     }else if(event instanceof JSONObject){
       JSONObject bindings = (JSONObject) event;
       String eventName = bindings.getString(WXEvent.EVENT_KEY_TYPE);
       Object args = bindings.get(WXEvent.EVENT_KEY_ARGS);
       if (eventName != null) {
-           putEventBindingArgs(eventName, args);
+        putEventBindingArgs(eventName, args);
       }
     }
   }
@@ -116,41 +124,40 @@ public class WXEvent extends ArrayList<String> implements 
Serializable, Cloneabl
   }
 
   public void putEventBindingArgs(String event, Object args){
-      if(!contains(event)){
-          add(event);
-      }
-      if(args != null){
-        if(mEventBindingArgs == null){
-          mEventBindingArgs = new ArrayMap();
-        }
-        mEventBindingArgs.put(event, ELUtils.bindingBlock(args));
+    if(!contains(event)){
+      add(event);
+    }
+    if(args != null){
+      if(mEventBindingArgs == null){
+        mEventBindingArgs = new ArrayMap();
       }
+      mEventBindingArgs.put(event, ELUtils.bindingBlock(args));
+    }
   }
 
   public void putEventBindingArgsValue(String event, List<Object> value){
     if(mEventBindingArgsValues == null){
-        mEventBindingArgsValues = new ArrayMap();
+      mEventBindingArgsValues = new ArrayMap();
     }
     if(value == null){
       mEventBindingArgsValues.remove(event);
     }else{
-       mEventBindingArgsValues.put(event, value);
+      mEventBindingArgsValues.put(event, value);
     }
   }
 
 
-  /**
-   *  event data format
-   *  {
-   *  type: 'appear',
-   *  params: [
-   *  { '@binding': 'index' },
-   *   'static',
-   *   { '@binding': 'item.name' },
-   *  { '@binding': '$event' }
-   *  ]
-   *  }
-   * */
-  public static final String EVENT_KEY_TYPE = "type";
-  public static final String EVENT_KEY_ARGS = "params";
+
+  @Override
+  public WXEvent clone() {
+    WXEvent event = new WXEvent();
+    event.addAll(this);
+    if(mEventBindingArgs != null) {
+      event.mEventBindingArgs = new ArrayMap(mEventBindingArgs);
+    }
+    event.mEventBindingArgsValues = null; //this should not be clone, it 
dynamic args
+    return  event;
+  }
+
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/886d859a/android/sdk/src/main/java/com/taobao/weex/dom/WXStyle.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/WXStyle.java 
b/android/sdk/src/main/java/com/taobao/weex/dom/WXStyle.java
index 6dc444a..ff1842a 100644
--- a/android/sdk/src/main/java/com/taobao/weex/dom/WXStyle.java
+++ b/android/sdk/src/main/java/com/taobao/weex/dom/WXStyle.java
@@ -26,11 +26,14 @@ import android.text.Layout;
 import android.text.TextUtils;
 
 import com.taobao.weex.common.Constants;
+import com.taobao.weex.dom.binding.ELUtils;
+import com.taobao.weex.dom.binding.WXStatement;
 import com.taobao.weex.dom.flex.CSSAlign;
 import com.taobao.weex.dom.flex.CSSFlexDirection;
 import com.taobao.weex.dom.flex.CSSJustify;
 import com.taobao.weex.dom.flex.CSSPositionType;
 import com.taobao.weex.dom.flex.CSSWrap;
+import com.taobao.weex.el.parse.Parser;
 import com.taobao.weex.ui.component.WXText;
 import com.taobao.weex.ui.component.WXTextDecoration;
 import com.taobao.weex.utils.WXUtils;
@@ -41,6 +44,9 @@ import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
 
+import static com.taobao.weex.dom.binding.ELUtils.COMPONENT_PROPS;
+import static com.taobao.weex.dom.binding.ELUtils.EXCLUDES_BINDING;
+
 /**
  * Store value of component style
  *
@@ -54,11 +60,20 @@ public class WXStyle implements Map<String, 
Object>,Cloneable {
   private Map<String,Map<String,Object>> mPesudoStyleMap = new ArrayMap<>();// 
clz_group:{styleMap}
   private Map<String,Object> mPesudoResetStyleMap = new ArrayMap<>();
 
+  /**
+   * dynamic binding attrs, can be null, only weex use
+   * */
+  private ArrayMap<String, Object>  mBindingStyle;
 
   public WXStyle(){
     mStyles = new ArrayMap<>();
   }
 
+  public WXStyle(Map<String, Object> mStyles, boolean byPesudo) {
+    this();
+    this.putAll(filterBindingStyles(mStyles), byPesudo);
+  }
+
   @Nullable
   public String getBlur() {
     if(get(Constants.Name.FILTER) == null) {
@@ -749,6 +764,7 @@ public class WXStyle implements Map<String, 
Object>,Cloneable {
   protected WXStyle clone(){
     WXStyle style = new WXStyle();
     style.mStyles.putAll(this.mStyles);
+    style.mBindingStyle = mBindingStyle;
 
     for(Entry<String,Map<String,Object>> 
entry:this.mPesudoStyleMap.entrySet()){
       Map<String,Object> valueClone = new ArrayMap<>();
@@ -759,4 +775,42 @@ public class WXStyle implements Map<String, 
Object>,Cloneable {
     style.mPesudoResetStyleMap.putAll(this.mPesudoResetStyleMap);
     return style;
   }
+
+
+  /**
+   * filter dynamic state ment
+   * */
+  private Map<String, Object> filterBindingStyles(Map styles) {
+    if(styles == null || styles.size() == 0){
+      return styles;
+    }
+    Set<Map.Entry<String,Object>> entries = styles.entrySet();
+    Iterator<Entry<String,Object>> it =  entries.iterator();
+    while (it.hasNext()){
+      Map.Entry<String,Object> entry = it.next();
+      if(filterBindingStyle(entry.getKey(), entry.getValue())){
+        it.remove();
+      }
+    }
+    return styles;
+  }
+
+  /**
+   * filter dynamic attrs and statements
+   * */
+  private boolean filterBindingStyle(String key, Object value) {
+    if(ELUtils.isBinding(value)){
+        if(mBindingStyle == null){
+          mBindingStyle = new ArrayMap<String, Object>();
+        }
+        value = ELUtils.bindingBlock(value);
+        mBindingStyle.put(key, value);
+        return  true;
+    }
+    return  false;
+  }
+
+  public ArrayMap<String, Object> getBindingStyle() {
+    return mBindingStyle;
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/886d859a/android/sdk/src/main/java/com/taobao/weex/dom/action/AbstractAddElementAction.java
----------------------------------------------------------------------
diff --git 
a/android/sdk/src/main/java/com/taobao/weex/dom/action/AbstractAddElementAction.java
 
b/android/sdk/src/main/java/com/taobao/weex/dom/action/AbstractAddElementAction.java
index cbe5a53..b6a27fb 100644
--- 
a/android/sdk/src/main/java/com/taobao/weex/dom/action/AbstractAddElementAction.java
+++ 
b/android/sdk/src/main/java/com/taobao/weex/dom/action/AbstractAddElementAction.java
@@ -27,9 +27,11 @@ import com.taobao.weex.common.WXErrorCode;
 import com.taobao.weex.dom.DOMAction;
 import com.taobao.weex.dom.DOMActionContext;
 import com.taobao.weex.dom.RenderAction;
+import com.taobao.weex.dom.WXCellDomObject;
 import com.taobao.weex.dom.WXDomObject;
 import com.taobao.weex.tracing.Stopwatch;
 import com.taobao.weex.tracing.WXTracing;
+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.WXVContainer;
@@ -132,8 +134,19 @@ public abstract class AbstractAddElementAction extends 
TraceableAction implement
     }
     Stopwatch.split("createComponent");
 
-    context.addDomInfo(domObject.getRef(), component);
+    boolean needAddDomInfo = true;
+    if(domObject.getType().equals(WXBasicComponentType.CELL_SLOT)
+            && domObject instanceof WXCellDomObject){
+       needAddDomInfo = false;
+    }
+
+    if(needAddDomInfo) {
+      context.addDomInfo(domObject.getRef(), component);
+    }
+
+
     context.postRenderTask(this);
+
     addAnimationForDomTree(context, domObject);
 
 //    instance.commitUTStab(IWXUserTrackAdapter.DOM_MODULE, 
WXErrorCode.WX_SUCCESS);

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/886d859a/android/sdk/src/main/java/com/taobao/weex/dom/action/Actions.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/action/Actions.java 
b/android/sdk/src/main/java/com/taobao/weex/dom/action/Actions.java
index c284997..9f60765 100644
--- a/android/sdk/src/main/java/com/taobao/weex/dom/action/Actions.java
+++ b/android/sdk/src/main/java/com/taobao/weex/dom/action/Actions.java
@@ -42,6 +42,7 @@ import static com.taobao.weex.dom.WXDomModule.REMOVE_ELEMENT;
 import static com.taobao.weex.dom.WXDomModule.REMOVE_EVENT;
 import static com.taobao.weex.dom.WXDomModule.SCROLL_TO_ELEMENT;
 import static com.taobao.weex.dom.WXDomModule.UPDATE_ATTRS;
+import static com.taobao.weex.dom.WXDomModule.UPDATE_COMPONENT_DATA;
 import static com.taobao.weex.dom.WXDomModule.UPDATE_FINISH;
 import static com.taobao.weex.dom.WXDomModule.UPDATE_STYLE;
 
@@ -121,6 +122,11 @@ public class Actions {
           return null;
         }
         return new 
InvokeMethodAction(args.getString(0),args.getString(1),args.getJSONArray(2));
+      case UPDATE_COMPONENT_DATA:
+        if(args == null || args.size() < 3){
+          return null;
+        }
+        return new UpdateComponentDataAction(args.getString(0), 
args.getJSONObject(1), args.getString(2));
     }
 
     return null;

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/886d859a/android/sdk/src/main/java/com/taobao/weex/dom/action/AddElementAction.java
----------------------------------------------------------------------
diff --git 
a/android/sdk/src/main/java/com/taobao/weex/dom/action/AddElementAction.java 
b/android/sdk/src/main/java/com/taobao/weex/dom/action/AddElementAction.java
index 2958ea5..87f5d56 100644
--- a/android/sdk/src/main/java/com/taobao/weex/dom/action/AddElementAction.java
+++ b/android/sdk/src/main/java/com/taobao/weex/dom/action/AddElementAction.java
@@ -20,13 +20,15 @@ package com.taobao.weex.dom.action;
 
 import com.alibaba.fastjson.JSONObject;
 import com.taobao.weex.WXSDKInstance;
-import com.taobao.weex.adapter.IWXUserTrackAdapter;
 import com.taobao.weex.common.WXErrorCode;
 import com.taobao.weex.dom.DOMActionContext;
 import com.taobao.weex.dom.RenderActionContext;
+import com.taobao.weex.dom.WXCellDomObject;
 import com.taobao.weex.dom.WXDomObject;
 import com.taobao.weex.tracing.Stopwatch;
 import com.taobao.weex.tracing.WXTracing;
+import com.taobao.weex.ui.component.ComponentUtils;
+import com.taobao.weex.ui.component.WXBasicComponentType;
 import com.taobao.weex.ui.component.WXComponent;
 import com.taobao.weex.ui.component.WXVContainer;
 import com.taobao.weex.utils.WXLogUtils;
@@ -60,6 +62,10 @@ final class AddElementAction extends 
AbstractAddElementAction {
                          .append("!(comp instanceof WXVContainer)");
       return null;
     }
+    if(domObject.getType().equals(WXBasicComponentType.CELL_SLOT)
+            && domObject instanceof WXCellDomObject){
+      return ComponentUtils.buildTree(domObject, (WXVContainer) comp);
+    }
     return generateComponentTree(context, domObject, (WXVContainer) comp);
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/886d859a/android/sdk/src/main/java/com/taobao/weex/dom/action/UpdateAttributeAction.java
----------------------------------------------------------------------
diff --git 
a/android/sdk/src/main/java/com/taobao/weex/dom/action/UpdateAttributeAction.java
 
b/android/sdk/src/main/java/com/taobao/weex/dom/action/UpdateAttributeAction.java
index bbeeea1..0591f73 100644
--- 
a/android/sdk/src/main/java/com/taobao/weex/dom/action/UpdateAttributeAction.java
+++ 
b/android/sdk/src/main/java/com/taobao/weex/dom/action/UpdateAttributeAction.java
@@ -60,9 +60,11 @@ class UpdateAttributeAction extends TraceableAction 
implements DOMAction, Render
       }
       return;
     }
-
+    domObject.getAttrs().filterBindingStatement(mData);
     domObject.updateAttr(mData);
-    context.postRenderTask(this);
+    if(mData.size() > 0) {
+       context.postRenderTask(this);
+    }
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/886d859a/android/sdk/src/main/java/com/taobao/weex/dom/action/UpdateComponentDataAction.java
----------------------------------------------------------------------
diff --git 
a/android/sdk/src/main/java/com/taobao/weex/dom/action/UpdateComponentDataAction.java
 
b/android/sdk/src/main/java/com/taobao/weex/dom/action/UpdateComponentDataAction.java
new file mode 100644
index 0000000..347c886
--- /dev/null
+++ 
b/android/sdk/src/main/java/com/taobao/weex/dom/action/UpdateComponentDataAction.java
@@ -0,0 +1,69 @@
+/**
+ * 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.dom.action;
+
+import android.text.TextUtils;
+
+import com.alibaba.fastjson.JSONObject;
+import com.taobao.weex.bridge.SimpleJSCallback;
+import com.taobao.weex.dom.RenderAction;
+import com.taobao.weex.dom.RenderActionContext;
+import com.taobao.weex.ui.component.WXComponent;
+import com.taobao.weex.ui.component.list.template.CellDataManager;
+import com.taobao.weex.ui.component.list.template.WXRecyclerTemplateList;
+import com.taobao.weex.utils.WXLogUtils;
+
+
+/**
+ * Created by furture on 2018/1/23.
+ */
+
+public class UpdateComponentDataAction implements RenderAction {
+
+    private String virtualComponentId;
+    private JSONObject data;
+    private String callback;
+
+    public UpdateComponentDataAction(String virtualComponentId,
+                                     JSONObject data, String callback) {
+        this.virtualComponentId = virtualComponentId;
+        this.data = data;
+        this.callback = callback;
+    }
+
+    @Override
+    public void executeRender(RenderActionContext context) {
+        String ref = CellDataManager.getListRef(virtualComponentId);
+        if(TextUtils.isEmpty(ref)){
+            WXLogUtils.e("wrong virtualComponentId split error " + 
virtualComponentId);
+            return;
+        }
+        WXComponent component = context.getComponent(ref);
+        if(component instanceof  WXRecyclerTemplateList){
+            WXRecyclerTemplateList templateList = (WXRecyclerTemplateList) 
component;
+            
templateList.getCellDataManager().updateVirtualComponentData(virtualComponentId,
 data);
+            templateList.notifyUpdateList();
+            SimpleJSCallback jsCallback = new 
SimpleJSCallback(component.getInstanceId(), callback);
+            jsCallback.invoke(true);
+        }else{
+            WXLogUtils.e("recycler-list wrong virtualComponentId " + 
virtualComponentId);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/886d859a/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 8202a46..dac03b2 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
@@ -39,6 +39,7 @@ public class ELUtils {
      * */
     public static final String IS_COMPONENT_ROOT = "@isComponentRoot";
 
+
     public static final String COMPONENT_PROPS = "@componentProps";
 
     public static final  String[] EXCLUDES_BINDING = {"clickEventParams"};

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/886d859a/android/sdk/src/main/java/com/taobao/weex/dom/binding/WXStatement.java
----------------------------------------------------------------------
diff --git 
a/android/sdk/src/main/java/com/taobao/weex/dom/binding/WXStatement.java 
b/android/sdk/src/main/java/com/taobao/weex/dom/binding/WXStatement.java
index ca20dca..6a760cb 100644
--- a/android/sdk/src/main/java/com/taobao/weex/dom/binding/WXStatement.java
+++ b/android/sdk/src/main/java/com/taobao/weex/dom/binding/WXStatement.java
@@ -63,6 +63,12 @@ public class WXStatement extends ArrayMap<String, Object> 
implements  Cloneable
      * */
     public static final String WX_IF = "[[match]]";
 
+
+    /**
+     * once statement
+     * */
+    public static final  String WX_ONCE = "[[once]]";
+
     public WXStatement() {
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/886d859a/android/sdk/src/main/java/com/taobao/weex/el/parse/Block.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/el/parse/Block.java 
b/android/sdk/src/main/java/com/taobao/weex/el/parse/Block.java
index 5d15220..6c3e29a 100644
--- a/android/sdk/src/main/java/com/taobao/weex/el/parse/Block.java
+++ b/android/sdk/src/main/java/com/taobao/weex/el/parse/Block.java
@@ -57,7 +57,6 @@ class Block extends Token {
         return token.execute(context);
     }
 
-    /**
     @Override
     public String toString() {
         if(getType() == TYPE_ARRAY){
@@ -68,5 +67,5 @@ class Block extends Token {
             }
             return "{" + tokens + '}';
         }
-    }*/
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/886d859a/android/sdk/src/main/java/com/taobao/weex/el/parse/Operator.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/el/parse/Operator.java 
b/android/sdk/src/main/java/com/taobao/weex/el/parse/Operator.java
index d592579..d597be8 100644
--- a/android/sdk/src/main/java/com/taobao/weex/el/parse/Operator.java
+++ b/android/sdk/src/main/java/com/taobao/weex/el/parse/Operator.java
@@ -93,7 +93,6 @@ class Operator extends Token {
         }
     }
 
-    /**
     @Override
     public String toString() {
         if(Operators.AND_NOT.equals(getToken())){
@@ -103,5 +102,5 @@ class Operator extends Token {
             return "{" + first +  getToken() + second + "}";
         }
         return "{" + self + getToken() + first + ":" + second + "}";
-    }*/
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/886d859a/android/sdk/src/main/java/com/taobao/weex/el/parse/Operators.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/el/parse/Operators.java 
b/android/sdk/src/main/java/com/taobao/weex/el/parse/Operators.java
index b2e1c02..a8de759 100644
--- a/android/sdk/src/main/java/com/taobao/weex/el/parse/Operators.java
+++ b/android/sdk/src/main/java/com/taobao/weex/el/parse/Operators.java
@@ -18,6 +18,9 @@
  */
 package com.taobao.weex.el.parse;
 
+import com.taobao.weex.WXEnvironment;
+import com.taobao.weex.ui.component.list.template.CellRenderContext;
+
 import java.lang.reflect.Array;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -63,6 +66,12 @@ public class Operators {
         if(context == null){
             return  null;
         }
+        if(context instanceof CellRenderContext){
+            if(WXEnvironment.isApkDebugable()){
+                throw new IllegalArgumentException("rong context 
CellRenderContext, you should pass it's stack");
+            }
+            context = ((CellRenderContext) context).stack;
+        }
         if(context instanceof ArrayStack){
             ArrayStack stack = (ArrayStack) context;
             for(int index=stack.size()-1; index >= 0; index--){
@@ -257,7 +266,7 @@ public class Operators {
         }
         Object leftValue =  null;
         if(left != null){
-            leftValue  = left.execute(context);;
+            leftValue  = left.execute(context);
         }
         Object rightValue = null;
         if(right != null) {

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/886d859a/android/sdk/src/main/java/com/taobao/weex/el/parse/Token.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/el/parse/Token.java 
b/android/sdk/src/main/java/com/taobao/weex/el/parse/Token.java
index 88a6ff8..44f9135 100644
--- a/android/sdk/src/main/java/com/taobao/weex/el/parse/Token.java
+++ b/android/sdk/src/main/java/com/taobao/weex/el/parse/Token.java
@@ -74,11 +74,10 @@ public class Token {
         throw new IllegalArgumentException("unhandled token type " + type);
     }
 
-    /***
     @Override
     public String toString() {
         return "{" + token + "," + type + '}';
-    }*/
+    }
 
     public String getToken() {
         return token;

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/886d859a/android/sdk/src/main/java/com/taobao/weex/ui/component/ComponentUtils.java
----------------------------------------------------------------------
diff --git 
a/android/sdk/src/main/java/com/taobao/weex/ui/component/ComponentUtils.java 
b/android/sdk/src/main/java/com/taobao/weex/ui/component/ComponentUtils.java
new file mode 100644
index 0000000..b28a94f
--- /dev/null
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/ComponentUtils.java
@@ -0,0 +1,122 @@
+/**
+ * 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 com.taobao.weex.WXEnvironment;
+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.utils.WXLogUtils;
+
+/**
+ * Created by furture on 2018/1/25.
+ */
+
+public class ComponentUtils {
+
+    private static final String TAG = "ComponentUtils";
+
+    /**
+     * init component  if component is lazy,
+     * if component is not lazy, do nothing
+     * */
+    public static void initLazyComponent(WXComponent component, WXVContainer 
mParent){
+        if(component.isLazy()){
+            component.lazy(false);
+            if(mParent != null){
+                int index = mParent.indexOf(component);
+                mParent.createChildViewAt(index);
+            }else {
+                component.createView();
+            }
+            component.applyLayoutAndEvent(component);
+            component.bindData(component);
+        }
+    }
+
+    /**
+     * build component tree and dom tree for template list
+     * */
+    public static synchronized final WXComponent buildTree(WXDomObject 
domObject, WXVContainer parent){
+        DOMActionContext domActionContext = 
WXSDKManager.getInstance().getWXDomManager().getDomContext(parent.getInstanceId());
+        if(domActionContext == null){
+            return null;
+        }
+        DomTreeBuilder builder = new DomTreeBuilder();
+        domObject.traverseTree(
+                domActionContext.getAddDOMConsumer(),
+                domActionContext.getApplyStyleConsumer()
+        );
+        return builder.buildComponentTree(domActionContext, domObject, parent);
+    }
+
+
+    /**
+     * dom tree build
+     * */
+    static class DomTreeBuilder extends TraceableAction {
+
+        private WXComponent buildComponentTree(DOMActionContext context, 
WXDomObject dom, WXVContainer parent) {
+            if (dom == null) {
+                return null;
+            }
+            long startNanos = System.nanoTime();
+            dom.setCloneThis(true);
+            WXComponent component = 
WXComponentFactory.newInstance(context.getInstance(), dom, parent);
+            if (component != null) {
+                component.mTraceInfo.domThreadStart = dom.mDomThreadTimestamp;
+                component.mTraceInfo.rootEventId = mTracingEventId;
+                component.mTraceInfo.domQueueTime = mDomQueueTime;
+            }
+            context.registerComponent(dom.getRef(), component);
+            if (component instanceof WXVContainer) {
+                WXVContainer container = (WXVContainer) component;
+                WXDomObject parentDom = (WXDomObject) container.getDomObject();
+                for (int i = 0; i < dom.childCount(); ++i) {
+                    WXDomObject child = dom.getChild(i);
+                    if (child != null) {
+                        WXComponent childComponent = 
buildComponentTree(context, child, container);
+                        container.addChild(childComponent);
+                        WXDomObject childDomObject = (WXDomObject) 
childComponent.getDomObject();
+                        if(childDomObject != child) {
+                            int index = parentDom.index(child);
+                            parentDom.add(childDomObject, index);
+                            if(index >= 0) {
+                                parentDom.remove(child);
+                                i--;
+                            }
+                            RuntimeException exception = new 
IllegalArgumentException(childDomObject.getClass().getName()
+                                    + " not support clone this");
+                            WXLogUtils.e("weex", exception);
+                            if(WXEnvironment.isApkDebugable()){
+                                throw  exception;
+                            }
+                        }
+                    }
+                }
+            }
+            dom.setCloneThis(false);
+            if (component != null) {
+                component.mTraceInfo.domThreadNanos = System.nanoTime() - 
startNanos;
+            }
+            return component;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/886d859a/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 0aff8a5..2e234ba 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
@@ -79,6 +79,7 @@ import com.taobao.weex.tracing.Stopwatch;
 import com.taobao.weex.tracing.WXTracing;
 import com.taobao.weex.ui.IFComponentHolder;
 import com.taobao.weex.ui.animation.WXAnimationModule;
+import com.taobao.weex.ui.component.binding.Statements;
 import com.taobao.weex.ui.component.pesudo.OnActivePseudoListener;
 import com.taobao.weex.ui.component.pesudo.PesudoStatus;
 import com.taobao.weex.ui.component.pesudo.TouchActivePseudoListener;
@@ -124,7 +125,7 @@ public abstract class  WXComponent<T extends View> 
implements IWXObject, IWXActi
   public static final String PROP_FS_WRAP_CONTENT = "w";
 
   private int mFixedProp = 0;
-  public static int mComponentNum = 0;
+  public static volatile int mComponentNum = 0;
   /** package **/ T mHost;
 
   private volatile WXVContainer mParent;
@@ -158,6 +159,7 @@ public abstract class  WXComponent<T extends View> 
implements IWXObject, IWXActi
   private boolean mNeedLayoutOnAnimation = false;
   private String mLastBoxShadowId;
 
+
   public WXTracing.TraceInfo mTraceInfo = new WXTracing.TraceInfo();
 
   public static final int TYPE_COMMON = 0;
@@ -165,6 +167,7 @@ public abstract class  WXComponent<T extends View> 
implements IWXObject, IWXActi
 
   private boolean waste = false;
 
+
   //Holding the animation bean when component is uninitialized
   public void postAnimation(WXAnimationModule.AnimationHolder holder) {
     this.mAnimationHolder = holder;
@@ -348,6 +351,12 @@ public abstract class  WXComponent<T extends View> 
implements IWXObject, IWXActi
         if(mDomObj.getEvents() != null && 
mDomObj.getEvents().getEventBindingArgsValues() != null){
              eventArgsValues = 
mDomObj.getEvents().getEventBindingArgsValues().get(type);
         }
+        if(params != null){
+          String componentId = Statements.getComponentId(this);
+          if(componentId != null) {
+            params.put("componentId", componentId);
+          }
+        }
         mInstance.fireEvent(mCurrentRef, type, params,domChanges, 
eventArgsValues, callback);
     }
   }
@@ -371,6 +380,9 @@ public abstract class  WXComponent<T extends View> 
implements IWXObject, IWXActi
    * @return true for lazy
    */
   public boolean isLazy() {
+    if(mLazy){
+      return true;
+    }
     return mParent != null && mParent.isLazy();
   }
 
@@ -1974,51 +1986,85 @@ public abstract class  WXComponent<T extends View> 
implements IWXObject, IWXActi
     }
   }
 
+  protected boolean isRippleEnabled() {
+    try {
+      Object obj = 
getDomObject().getAttrs().get(Constants.Name.RIPPLE_ENABLED);
+      return WXUtils.getBoolean(obj, false);
+    } catch (Throwable t) {
+      //ignore
+    }
+    return false;
+  }
+
+
+
   public boolean isWaste() {
     return waste;
   }
 
+  /**
+   * mark node waste,
+   * if node is waster should hidden, and dom tree should allow not show
+   * */
   public void setWaste(boolean waste) {
     if(this.waste != waste){
       this.waste = waste;
       WXDomObject domObject = (WXDomObject) getDomObject();
       if(waste){
-          getDomObject().getStyles().put(Constants.Name.VISIBILITY, 
Constants.Value.HIDDEN);
-          if(domObject.getAttrs().getStatement() == null) {
-            domObject.setVisible(false);
-            if (getHostView() != null) {
-                getHostView().setVisibility(View.GONE);
-            }
-            return;
-          }
-          
if(Constants.Value.VISIBLE.equals(domObject.getAttrs().get(Constants.Name.VIF_FALSE))){
-            domObject.setVisible(true);
-            if(getHostView() != null){
-               getHostView().setVisibility(View.VISIBLE);
-             }
-          }else{
-            domObject.setVisible(false);
-            if(getHostView() != null){
-              getHostView().setVisibility(View.GONE);
-            }
-          }
+          //update dom not show, and put style to hidden
+         domObject.setVisible(false);
+         domObject.getStyles().put(Constants.Name.VISIBILITY, 
Constants.Value.HIDDEN);
+         //if component not init, mark lazy init when use, reduce view count
+         if(getHostView() == null){
+           if(!mLazy){
+              lazy(true);
+           }
+         }else{
+           getHostView().setVisibility(View.GONE);
+         }
       }else{
-        domObject.setVisible(true);
-        if(getHostView() != null){
+         domObject.setVisible(true);
+         domObject.getStyles().put(Constants.Name.VISIBILITY, 
Constants.Value.VISIBLE);
+         if(getHostView() == null){
+             if(mLazy) { // when parent is lazy just mark node lazy false
+               if(mParent != null && mParent.isLazy()){
+                  lazy(false);
+               }else{
+                  ComponentUtils.initLazyComponent(this, mParent);
+               }
+             }
+         }else{
            getHostView().setVisibility(View.VISIBLE);
-        }
-        getDomObject().getStyles().put(Constants.Name.VISIBILITY, 
Constants.Value.VISIBLE);
+         }
       }
     }
   }
 
-  protected boolean isRippleEnabled() {
-    try {
-      Object obj = 
getDomObject().getAttrs().get(Constants.Name.RIPPLE_ENABLED);
-      return WXUtils.getBoolean(obj, false);
-    } catch (Throwable t) {
-      //ignore
-    }
-    return false;
+
+  /** component key id in native,
+   *  differ with ref, ref + position
+   *  */
+  public  String getViewTreeKey(){
+     if(mViewTreeKey == null){
+        if(getParent() == null){
+          mViewTreeKey = getRef();
+        }else{
+          mViewTreeKey = getRef() + "_" + getParent().indexOf(this);
+        }
+     }
+     return mViewTreeKey;
+  }
+
+  private String mViewTreeKey;
+
+
+  /**
+   * node is lazy
+   * */
+  private boolean mLazy = false;
+
+  /***/
+  public void lazy(boolean lazy) {
+    mLazy = lazy;
   }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/886d859a/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 9dea0ff..3357882 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
@@ -21,14 +21,12 @@ package com.taobao.weex.ui.component.binding;
 
 
 import android.os.AsyncTask;
-import android.util.Log;
 
 import com.taobao.weex.WXEnvironment;
 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;
@@ -87,10 +85,14 @@ public class Layouts {
         try{
             long start = System.currentTimeMillis();
             doLayout(component, layoutContext);
-            if(WXEnvironment.isApkDebugable()){
+            if(WXEnvironment.isOpenDebugLog() && 
WXRecyclerTemplateList.ENABLE_TRACE_LOG) {
                 WXLogUtils.d(WXRecyclerTemplateList.TAG, "WXTemplateList 
doSafeLayout" +
-                        
component.getDomObject().getAttrs().get(Constants.Name.Recycler.SLOT_TEMPLATE_TYPE)
 + Thread.currentThread().getName() +  " doSafeLayout  used " +
-                                (System.currentTimeMillis() - start));
+                        
component.getDomObject().getAttrs().get(Constants.Name.Recycler.SLOT_TEMPLATE_CASE)
 + Thread.currentThread().getName() + " doSafeLayout  used " +
+                        (System.currentTimeMillis() - start));
+            }
+            if(!(component.getLayoutHeight() > 0)){
+                WXLogUtils.e(WXRecyclerTemplateList.TAG, " WXTemplateList 
doSafeLayout wrong template " +
+                        
component.getDomObject().getAttrs().get(Constants.Name.Recycler.SLOT_TEMPLATE_CASE)
  + " cell height " + component.getLayoutHeight());
             }
         }catch (Exception e){
             if(WXEnvironment.isApkDebugable()){
@@ -102,7 +104,7 @@ public class Layouts {
     private static void doLayout(WXComponent component, final  
CSSLayoutContext layoutContext){
         WXDomObject domObject = (WXDomObject) component.getDomObject();
         final WXSDKInstance instance = component.getInstance();
-        domObject.traverseTree(new WXDomObject.Consumer() {
+        domObject.traverseUpdateTree(new WXDomObject.Consumer() {
             @Override
             public void accept(WXDomObject dom) {
                 if(instance == null || instance.isDestroy()){
@@ -111,18 +113,24 @@ public class Layouts {
                 if(!dom.hasUpdate()){
                     return;
                 }
+                if(!dom.isShow()){ //not show just skip
+                   return;
+                }
                 dom.layoutBefore();
             }
         });
         if(instance != null && !instance.isDestroy()){
             domObject.calculateLayout(layoutContext);
         }
-        domObject.traverseTree( new WXDomObject.Consumer() {
+        domObject.traverseUpdateTree( new WXDomObject.Consumer() {
             @Override
             public void accept(WXDomObject dom) {
                 if(instance == null || instance.isDestroy()){
                     return;
                 }
+                if(!dom.isShow()){
+                    return;
+                }
                 if (dom.hasUpdate()) {
                     dom.layoutAfter();
                 }
@@ -140,7 +148,6 @@ public class Layouts {
      * */
     public static final void setLayout(WXComponent component, boolean force){
         if(component.isWaste()){
-            setLayoutWaste(component, force);
             return;
         }
         WXDomObject domObject = (WXDomObject) component.getDomObject();

Reply via email to