Weex Android SDK源码分析之界面渲染(下)
Posted 王永迪
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Weex Android SDK源码分析之界面渲染(下)相关的知识,希望对你有一定的参考价值。
前言
在你读本篇文章之前请确认您已经阅读 Weex Android SDK源码分析之界面渲染(上),否则建议您先阅读上篇文章有利于您更深刻的了解~
流程图
源码分析
回忆一下上篇文章的讲解,最终由WxBridgeManage调用WxBridge调用了so中native代码进行JS代码解析,那么解析完成之后是如何返回给android代码的呢?so返回的是什么数据呢?数据时如何转换的呢?数据与最终的UI有什么关系呢?最终是如何转换成view的呢?如何传递到activity中的呢?
带着这些的疑问,我们开始今天得讲解~
一、WXBridge —> 解析JS回调Android code
/**
* Js 使用此方法回调Android代码
* @param instanceId
* @param tasks 任务
* @param callback 下一个任务的ID
*/
public void callNative(String instanceId, String tasks, String callback)
WXBridgeManager.getInstance().callNative(instanceId, tasks, callback);
二、WXBridgeManager — > 分配渲染任务
/**
* Dispatch the native task to be executed.
*
* @param instanceId @link WXSDKInstance#mInstanceId
* @param tasks tasks to be executed
* @param callback next tick id 下一个挂钩子ID,so执行需要的
*/
void callNative(String instanceId, String tasks, String callback)
if (TextUtils.isEmpty(tasks))
return;
if (WXEnvironment.isApkDebugable())
mLodBuilder.append("[WXBridgeManager] callNative >>>>
instanceId:").append(instanceId)
.append(", tasks:")
.append(tasks).append(", callback:").append(callback);
WXLogUtils.d(mLodBuilder.substring(0));
mLodBuilder.setLength(0);
JSONArray array = JSON.parseArray(tasks);
int size = array.size();
if (size > 0)
try
JSONObject task;
for (int i = 0; i < size; ++i)
task = (JSONObject) array.get(i);
if (task != null && WXSDKManager.getInstance()
.getSDKInstance(instanceId) != null)
WXModuleManager
.callModuleMethod(instanceId, (String) task.get("module")
, (String) task.get("method")
,(JSONArray) task.get("args"));
catch (Exception e)
if (UNDEFINED.equals(callback)
|| mDestroyedInstanceId.equals(instanceId))
return;
// get next tick
getNextTick(instanceId, callback);
// 获取下一个需要渲染的JS数据
private void getNextTick(final String instanceId, final String callback)
addNextTickTask(instanceId, callback, "");
sendMessage(instanceId, WXJSBridgeMsgType.CALL_JS_BATCH);
// 添加渲染数据
private void addNextTickTask(String instanceId, Object... args)
if (args == null || args.length == 0)
return;
ArrayList<Object> argsList = new ArrayList<>();
for (Object arg : args)
argsList.add(arg);
WXHashMap<String, Object> task = new WXHashMap<>();
task.put(WXConst.KEY_METHOD, METHOD_CALLBACK);
task.put(WXConst.KEY_ARGS, args);
if (mNextTickTasks.get(instanceId) == null)
ArrayList<WXHashMap<String, Object>> list =
new ArrayList<WXHashMap<String, Object>>();
list.add(task);
mNextTickTasks.put(instanceId, list);
else
mNextTickTasks.get(instanceId).add(task);
三、WXModuleManager —> 回调module方法
// 执行module中的方法
static boolean callModuleMethod(String instanceId, String moduleStr
, String methodStr, JSONArray args)
final WXModule wxModule = findModule(instanceId, moduleStr, methodStr);
if (wxModule == null)
return false;
wxModule.mWXSDKInstance =
WXSDKManager.getInstance().getSDKInstance(instanceId);
HashMap<String, Method> methodsMap = sGlobalModuleMethodMap.get(wxModule);
methodsMap = methodsMap ==
null ? sInstanceModuleMethodMap.get(wxModule) : methodsMap;
if (methodsMap == null)
return false;
final Method moduleMethod = methodsMap.get(methodStr);
try
Type[] paramClazzs = moduleMethod.getGenericParameterTypes();
final Object[] params = new Object[paramClazzs.length];
Object value;
Type paramClazz;
for (int i = 0; i < paramClazzs.length; i++)
paramClazz = paramClazzs[i];
value = args.get(i);
if (paramClazz == JSONObject.class)
params[i] = value;
else
String sValue;
if (value instanceof String)
sValue = (String) value;
else
sValue = JSON.toJSONString(value);
if (paramClazz == int.class)
params[i] = Integer.parseInt(sValue);
else if (paramClazz == String.class)
params[i] = sValue;
else if (paramClazz == long.class)
params[i] = Long.parseLong(sValue);
else if (paramClazz == double.class)
params[i] = Double.parseDouble(sValue);
else if (paramClazz == float.class)
params[i] = Float.parseFloat(sValue);
else if (ParameterizedType.class.
isAssignableFrom(paramClazz.getClass()))
params[i] = JSON.parseObject(sValue, paramClazz);
else if (IWXObject.class.isAssignableFrom(paramClazz.getClass()))
params[i] = JSON.parseObject(sValue, paramClazz);
else
params[i] = JSON.parseObject(sValue, paramClazz);
// *** 找到道注解的方法体,进行执行 ***
WXModuleAnno anno = moduleMethod.getAnnotation(WXModuleAnno.class);
if (anno.runOnUIThread())
WXSDKManager.getInstance().postOnUiThread(new Runnable()
@Override
public void run()
try
// *** 执行module方法 ***
moduleMethod.invoke(wxModule, params);
catch (Exception e)
, 0);
else
moduleMethod.invoke(wxModule, params);
catch (Exception e)
return false;
finally
if (wxModule instanceof WXDomModule)
wxModule.mWXSDKInstance = null;
return true;
// 找到module 例如 WXDOMModule
private static WXModule findModule(String instanceId, String moduleStr, String methodStr)
// find WXModule
WXModule wxModule = sGlobalModuleMap.get(moduleStr);
Class<? extends WXModule> moduleClass = sModuleClazzMap.get(moduleStr);
if (wxModule == null)
HashMap<String, WXModule> moduleMap = sInstanceModuleMap.get(instanceId);
if (moduleMap == null)
moduleMap = new HashMap<>();
sInstanceModuleMap.put(instanceId, moduleMap);
// if cannot find the Module, create a new Module and save it
wxModule = moduleMap.get(moduleStr);
if (wxModule == null)
try
wxModule = moduleClass.getConstructor().newInstance();
catch (Exception e)
return null;
moduleMap.put(moduleStr, wxModule);
// set instance
wxModule.mWXSDKInstance =
WXSDKManager.getInstance().getSDKInstance(instanceId);
// find module method
HashMap<String, Method> methodsMap = sGlobalModuleMethodMap.get(wxModule);
methodsMap = methodsMap == null ?
sInstanceModuleMethodMap.get(wxModule) : methodsMap;
if (methodsMap == null)
methodsMap = getModuleMethods2Map(moduleClass);
sInstanceModuleMethodMap.put(wxModule, methodsMap);
return wxModule;
四、WXDomModule — > module 方法被触发
public final class WXDomModule extends WXModule
/**
* 创建 Body UI
* @param element info about how to create a body
*/
@WXModuleAnno(moduleMethod = true, runOnUIThread = false)
public void createBody(JSONObject element)
if (element == null)
return;
Message msg = Message.obtain();
WXDomTask task = new WXDomTask();
task.instanceId = mWXSDKInstance.getInstanceId();
task.args = new ArrayList<>();
task.args.add(element);
msg.what = WXDomHandler.MsgType.WX_DOM_CREATE_BODY;
msg.obj = task;
// *** 发送createBody消息 ***
WXSDKManager.getInstance().getWXDomManager().sendMessage(msg);
五、WXDomManager —> 发送createBody等消息
// 发送消息 createBody 或者 refresh等
public void sendMessage(Message msg)
if (msg == null || mDomHandler == null || mDomThread == null
|| !mDomThread.isWXThreadAlive() || mDomThread.getLooper() == null)
return;
mDomHandler.sendMessage(msg);
六、WXDomHandler — > 分发任务类型
// DOM 操作handler
class WXDomHandler implements Handler.Callback
/**
* The batch operation in dom thread will run at most once in 16ms.
*/
private static final int DELAY_TIME = 16;//ms
private WXDomManager mWXDomManager;
private boolean mHasBatch = false;
public WXDomHandler(WXDomManager domManager)
mWXDomManager = domManager;
@Override
public boolean handleMessage(Message msg)
if (msg == null)
return false;
int what = msg.what;
Object obj = msg.obj;
WXDomTask task = null;
if (obj instanceof WXDomTask)
task = (WXDomTask) obj;
if (!mHasBatch)
mHasBatch = true;
mWXDomManager.
sendEmptyMessageDelayed(WXDomHandler.MsgType.WX_DOM_BATCH, DELAY_TIME);
switch (what)
case MsgType.WX_DOM_CREATE_BODY:
// *** createBody ***
mWXDomManager.createBody(task.instanceId, (JSONObject) task.args.get(0));
break;
case MsgType.WX_DOM_UPDATE_ATTRS:
mWXDomManager.updateAttrs(task.instanceId,
(String) task.args.get(0), (JSONObject) task.args.get(1));
break;
case MsgType.WX_DOM_UPDATE_STYLE:
mWXDomManager.updateStyle(task.instanceId,
(String) task.args.get(0), (JSONObject) task.args.get(1));
break;
case MsgType.WX_DOM_ADD_DOM:
mWXDomManager.addDom(task.instanceId, (String) task.args.get(0),
(JSONObject) task.args.get(1), (Integer) task.args.get(2));
break;
case MsgType.WX_DOM_REMOVE_DOM:
mWXDomManager.removeDom(task.instanceId, (String) task.args.get(0));
break;
case MsgType.WX_DOM_MOVE_DOM:
mWXDomManager.moveDom(task.instanceId, (String) task.args.get(0), (String) task.args.get(1), (Integer) task.args.get(2));
break;
case MsgType.WX_DOM_ADD_EVENT:
mWXDomManager.addEvent(task.instanceId, (String) task.args.get(0),
(String) task.args.get(1));
break;
case MsgType.WX_DOM_REMOVE_EVENT:
mWXDomManager.removeEvent(task.instanceId,
(String) task.args.get(0), (String) task.args.get(1));
break;
case MsgType.WX_DOM_CREATE_FINISH:
mWXDomManager.createFinish(task.instanceId);
break;
case MsgType.WX_DOM_REFRESH_FINISH:
mWXDomManager.refreshFinish(task.instanceId);
break;
case MsgType.WX_DOM_BATCH:
mWXDomManager.batch();
mHasBatch = false;
break;
case MsgType.WX_DOM_SCROLLTO:
mWXDomManager.scrollToDom(task.instanceId,
(String) task.args.get(0), (JSONObject) task.args.get(1));
break;
default:
break;
return true;
public static class MsgType
public static final int WX_DOM_CREATE_BODY = 0x0;
public static final int WX_DOM_UPDATE_ATTRS = 0x01;
public static final int WX_DOM_UPDATE_STYLE = 0x02;
public static final int WX_DOM_ADD_DOM = 0x03;
public static final int WX_DOM_REMOVE_DOM = 0x04;
public static final int WX_DOM_MOVE_DOM = 0x05;
public static final int WX_DOM_ADD_EVENT = 0x06;
public static final int WX_DOM_REMOVE_EVENT = 0x07;
public static final int WX_DOM_SCROLLTO = 0x08;
public static final int WX_DOM_CREATE_FINISH = 0x09;
public static final int WX_DOM_REFRESH_FINISH = 0x0a;
public static final int WX_DOM_BATCH = 0xff;
七、WXDomManager — > DOM 管理
/**
* Invoke @link WXDomStatement for creating body according to the JSONObject.
* @param instanceId
* @link com.taobao.weex.WXSDKInstance#mInstanceId for the instance
* @param element the jsonObject according to which to create command object.
*/
void createBody(String instanceId, JSONObject element)
if (!isDomThread())
throw new WXRuntimeException
("Create body operation must be done in dom thread");
// *** 调用DOM声明进行元素创建
WXDomStatement statement = new WXDomStatement(instanceId, mWXRenderManager);
mDomRegistries.put(instanceId, statement);
statement.createBody(element);
八、WXDomStatement — > DOM声明
/**
* 创建根据JSONObject创造体命令对象,并且把命令对象添加到队列.
* @param element the jsonObject according to which to create command object.
*/
void createBody(JSONObject element)
if (mDestroy)
return;
WXSDKInstance instance =
WXSDKManager.getInstance().getSDKInstance(mInstanceId);
if (element == null)
if (instance != null)
instance.commitUTStab(WXConst.DOM_MODULE,
WXErrorCode.WX_ERR_DOM_CREATEBODY);
return;
WXDomObject domObject = parseInner(element);
Map<String, Object> style = new HashMap<>(5);
if (domObject.style == null ||
!domObject.style.containsKey(WXDomPropConstant.WX_FLEXDIRECTION))
style.put(WXDomPropConstant.WX_FLEXDIRECTION, "column");
if (domObject.style == null ||
!domObject.style.containsKey(WXDomPropConstant.WX_BACKGROUNDCOLOR))
style.put(WXDomPropConstant.WX_BACKGROUNDCOLOR, "#ffffff");
//If there is height or width in JS, then that value will override value here.
if (domObject.style == null ||
!domObject.style.containsKey(WXDomPropConstant.WX_WIDTH))
style.put(WXDomPropConstant.WX_WIDTH,
WXViewUtils.getWebPxByWidth(WXViewUtils.getWeexWidth(mInstanceId)));
if (domObject.style == null ||
!domObject.style.containsKey(WXDomPropConstant.WX_HEIGHT))
style.put(WXDomPropConstant.WX_HEIGHT,
WXViewUtils.getWebPxByWidth(WXViewUtils.getWeexHeight(mInstanceId)));
domObject.ref = WXDomObject.ROOT;
domObject.updateStyle(style);
transformStyle(domObject, true);
final WXComponent component =
mWXRenderManager.createBodyOnDomThread(mInstanceId, domObject);
AddDomInfo addDomInfo = new AddDomInfo();
addDomInfo.component = component;
mAddDom.put(domObject.ref, addDomInfo);
mNormalTasks.add(new IWXRenderTask()
@Override
public void execute()
mWXRenderManager.createBody(mInstanceId, component);
);
mDirty = true;
mFlushes.add(domObject.ref);
if (instance != null)
instance.commitUTStab(WXConst.DOM_MODULE, WXErrorCode.WX_SUCCESS);
九、WXRenderManager —-> DOM操作
public WXComponent createBodyOnDomThread(String instanceId, WXDomObject domObject)
WXRenderStatement statement = mRegistries.get(instanceId);
if (statement == null)
return null;
return statement.createBodyOnDomThread(domObject);
十、WXRenderStatement —> DOM对象转换组件
WXComponent createBodyOnDomThread(WXDomObject dom)
if (mWXSDKInstance == null)
return null;
WXDomObject domObject = new WXDomObject();
domObject.type = WXBasicComponentType.DIV;
domObject.ref = "god";
mGodComponent = (WXVContainer) WXComponentFactory.
newInstance(mWXSDKInstance, domObject, null, mInstanceId);
mGodComponent.createView(null, -1);
if (mGodComponent == null)
if (WXEnvironment.isApkDebugable())
WXLogUtils.e("rootView failed!");
//TODO error callback
return null;
FrameLayout frameLayout = (FrameLayout) mGodComponent.getView();
ViewGroup.LayoutParams layoutParams =
new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
frameLayout.setLayoutParams(layoutParams);
frameLayout.setBackgroundColor(Color.TRANSPARENT);
WXComponent component = generateComponentTree(dom, mGodComponent);
mGodComponent.addChild(component);
mRegistry.put(component.getRef(), component);
return component;
// dom 对象转换 component tree
private WXComponent generateComponentTree(WXDomObject dom, WXVContainer parent)
if (dom == null || parent == null)
return null;
WXComponent component = WXComponentFactory.newInstance(mWXSDKInstance, dom,
parent, mInstanceId, parent.isLazy());
mRegistry.put(dom.ref, component);
if (component instanceof WXVContainer)
WXVContainer parentC = (WXVContainer) component;
int count = dom.childCount();
WXDomObject child = null;
for (int i = 0; i < count; ++i)
child = dom.getChild(i);
if (child != null)
parentC.addChild(generateComponentTree(child, parentC));
return component;
十一、WXRenderManager— > WXComponent 转换
// 得到Wx组件进行最终创建
public void createBody(String instanceId, WXComponent component)
WXRenderStatement statement = mRegistries.get(instanceId);
if (statement == null)
return;
statement.createBody(component);
十二、WXRenderStatement —> WX组件生成view
/**
* 创建RootView;
* @see com.taobao.weex.dom.WXDomStatement#createBody(JSONObject)
*/
void createBody(WXComponent component)
long start = System.currentTimeMillis();
component.createView(mGodComponent, -1);
start = System.currentTimeMillis();
component.bind(null);
if (component instanceof WXScroller)
WXScroller scroller = (WXScroller) component;
if (scroller.getView() instanceof ScrollView)
mWXSDKInstance.setRootScrollView((ScrollView) scroller.getView());
// *** 创建成果rootview进行返回 ***
mWXSDKInstance.setRootView(mGodComponent.getRealView());
if (mWXSDKInstance.getRenderStrategy() != WXRenderStrategy.APPEND_ONCE)
mWXSDKInstance.onViewCreated(mGodComponent);
十三、WXSDKInstance —> 接受view回调给activity
public void onViewCreated(final WXComponent component)
if (mRenderListener != null && mContext != null)
runOnUiThread(new Runnable()
@Override
public void run()
if (mRenderListener != null && mContext != null)
mRootCom = component;
mRenderListener.onViewCreated(WXSDKInstance.this, component.getView());
);
十四、IndexActivity —> 接受view绘制UI
@Override
public void onViewCreated(WXSDKInstance wxsdkInstance, View view)
Log.d("TAG", "onViewCreated");
if (flContainer != null)
flContainer.addView(view);
结束语
整个UI绘制流程就是这样的,猜测大家一定会掌握的,希望对大家有所帮助,谢谢您的观看!!!
以上是关于Weex Android SDK源码分析之界面渲染(下)的主要内容,如果未能解决你的问题,请参考以下文章
Weex Android SDK源码分析之Module(navigator)
Weex Android SDK源码分析之Module(modal)
Weex Android SDK源码分析之Module(webview)
Weex Android SDK源码分析之Module(animation)