Weex事件传递机制(二)

Weex事件传递机制

1.Weex组件事件绑定过程

Weex组件的事件绑定发生在WXComponent的方法applyLayoutAndEvent上:

  public void applyLayoutAndEvent(WXComponent component) {
    if(!isLazy()) {
      if (component == null) {
        component = this;
      }
      setLayout(component.getDomObject());
      setPadding(component.getDomObject().getPadding(), component.getDomObject().getBorder());
      addEvents();

    }
  }

提取和component一一对应的mDomObj对象,设置layout和padding。最后设置事件到自己的成员变量set中:

  private void addEvents() {
    int count = mDomObj.getEvents().size();
    for (int i = 0; i < count; ++i) {
      addEvent(mDomObj.getEvents().get(i));
    }
    setActiveTouchListener();
  }

获取mDomObj所有的事件,设置到addEvent

  public void addEvent(String type) {
    if (TextUtils.isEmpty(type)) {
      return;
    }
    mAppendEvents.add(type);
    View view = getRealView();
    /**
     *   处理1.CLICK 2.FOCUS 3.手势 4.滑动
     */
    if (type.equals(Constants.Event.CLICK) && view != null) {
      addClickListener(mClickEventListener);
    }
    else if ((type.equals( Constants.Event.FOCUS) || type.equals( Constants.Event.BLUR)) ) {
      addFocusChangeListener(new OnFocusChangeListener() {
        public void onFocusChange(boolean hasFocus) {
          Map<String, Object> params = new HashMap<>();
          params.put("timeStamp", System.currentTimeMillis());
          fireEvent(hasFocus ? Constants.Event.FOCUS : Constants.Event.BLUR, params);
        }
      });
    } else if (view != null && needGestureDetector(type)) {
      if (view instanceof WXGestureObservable) {
        if (wxGesture == null) {
          wxGesture = new WXGesture(this, mContext);
        }
        mGestureType.add(type);
        ((WXGestureObservable) view).registerGestureListener(wxGesture);
      } else {
        WXLogUtils.e(view.getClass().getSimpleName() + " don't implement " +
                     "WXGestureObservable, so no gesture is supported.");
      }
    }
    else {
      Scrollable scroller = getParentScroller();
      if (type.equals(Constants.Event.APPEAR) && scroller != null) {
        scroller.bindAppearEvent(this);
      }
      if (type.equals(Constants.Event.DISAPPEAR) && scroller != null) {
        scroller.bindDisappearEvent(this);
      }
    }
  }

2.Weex组件事件触发传递

2.1事件传递到JS 引擎

模拟普通的点击事件触发流程:
点击对应view,事件触发

  private OnClickListener mClickEventListener = new OnClickListener() {
    @Override
    public void onHostViewClick() {
      Map<String, Object> param= WXDataStructureUtil.newHashMapWithExpectedSize(1);
      Map<String, Object> position = WXDataStructureUtil.newHashMapWithExpectedSize(4);
      int[] location = new int[2];
      mHost.getLocationOnScreen(location);
      position.put("x", WXViewUtils.getWebPxByWidth(location[0],mInstance.getViewPortWidth()));
      position.put("y", WXViewUtils.getWebPxByWidth(location[1],mInstance.getViewPortWidth()));
      position.put("width", WXViewUtils.getWebPxByWidth(mDomObj.getLayoutWidth(),mInstance.getViewPortWidth()));
      position.put("height", WXViewUtils.getWebPxByWidth(mDomObj.getLayoutHeight(),mInstance.getViewPortWidth()));
      param.put(Constants.Name.POSITION, position);
      fireEvent(Constants.Event.CLICK,param);
    }
  };

将这次点击事件对应的view坐标和宽高打包成param,以fireEvent()发送出去之后。
传递路径:fireEvent()->WXBridgeManager.getInstance().fireEventOnNode():

  public void fireEventOnNode(final String instanceId, final String ref,
                        final String type, final Map<String, Object> data,final Map<String, Object> domChanges) {
    /**
     *  1.第一步,addJSTask()将刚才的事件再做了一次封装,扔到mNextTickTasks队列去等待执行
     *  2.第二步,sendMessage()发送CALL_JS_BATCH消息,从mNextTickTasks取出所有事件进行处理
     */
    addJSTask(METHOD_FIRE_EVENT, instanceId, ref, type, data,domChanges);
    sendMessage(instanceId, WXJSBridgeMsgType.CALL_JS_BATCH);
  }

对应的Handler也是WXBridgeManager自身,handlerMessage()后转到invokeCallJSBatch去处理()

  private void invokeCallJSBatch(Message message) {
    try {
      Object instanceId = message.obj;

      Object task = null;
      Stack<String> instanceStack = mNextTickTasks.getInstanceStack();
      int size = instanceStack.size();
      for (int i = size - 1; i >= 0; i--) {
        instanceId = instanceStack.get(i);
        task = mNextTickTasks.remove(instanceId);
        if (task != null && !((ArrayList) task).isEmpty()) {
          break;
        }
      }
      task = ((ArrayList) task).toArray();

      WXJSObject[] args = {new WXJSObject(WXJSObject.String, instanceId), new WXJSObject(WXJSObject.JSON, WXJsonUtils.fromObjectToJSONString(task))};

      /**
       *  起主要作用,后面会发起IWXBridge 与JS 引擎进行 jni交互 
       */
      invokeExecJS(String.valueOf(instanceId), null, METHOD_CALL_JS, args);
    } catch (Throwable e) {
    }

    // If task is not empty, loop until it is empty
    if (!mNextTickTasks.isEmpty()) {
      mJSHandler.sendEmptyMessage(WXJSBridgeMsgType.CALL_JS_BATCH);
    }
  }

循环取出所有需要执行的指令,一个个发起调用.

2.2 JS 引擎的回调

然后等待JS 引擎处理完毕,通过IWXBridge的callNative()返回处理结果,而IWXBridge的通常实例WXBridge最后也会交给WXBridgeManager的callNative()进行处理,而WXBridgeManager会根据instanceId,也就是WxSDKInstance对应的instanceId交给对应的WxDomModule来处理:

            WXDomModule dom = getDomModule(instanceId);
            dom.callDomMethod(task);
    public void callDomMethod(JSONObject task) {
        if (task == null) {
            return;
        }
        String method = (String) task.get(WXBridgeManager.METHOD);
        JSONArray args = (JSONArray) task.get(WXBridgeManager.ARGS);
        callDomMethod(method, args);
    }

    public Object callDomMethod(String method, JSONArray args) {
        if (method == null) {
            return null;
        }
        try {
            switch (method) {
                case CREATE_BODY:
                    if (args == null) {
                        return null;
                    }
                    createBody((JSONObject) args.get(0));
                    break;
                case UPDATE_ATTRS:
                    if (args == null) {
                        return null;
                    }
                    updateAttrs((String) args.get(0), (JSONObject) args.get(1));
                    break;
                //...省略其他cases
            }

        } catch (IndexOutOfBoundsException e) {
        } catch (ClassCastException cce) {
        }
        return null;
    }

具体按照V-Dom的变化发送对应的改变事件,这边简单的通过模拟点击图片,改变一个文本的内容,所以会发指令集UPDATE_FINISH+UPDATE_ATTRS过来,WxDomModule将对应的指令发给WxDomHandler,由handler具体负责后面的渲染重绘工作。后面的处理流程跟渲染过程差不多,不再细谈。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值