Weex框架源码分析(Android)(一)
一、weexSDK初始化流程
WXSDKEngine.initialize(Application application,InitConfig config);
//WXSDKEngine的init方法已经被弃用,weex的初始化需要使用下面这个initialize方法
public static void initialize(Application application,InitConfig config){
synchronized (mLock) {
//如果已经初始化过那么直接return
if (mIsInit) {
return;
}
long start = System.currentTimeMillis();
WXEnvironment.sSDKInitStart = start;
if(WXEnvironment.isApkDebugable()){
WXEnvironment.sLogLevel = LogLevel.DEBUG;
}else{
if(WXEnvironment.sApplication != null){
WXEnvironment.sLogLevel = LogLevel.WARN;
}else {
WXLogUtils.e(TAG,"WXEnvironment.sApplication is " + WXEnvironment.sApplication);
}
}
doInitInternal(application,config);
WXEnvironment.sSDKInitInvokeTime = System.currentTimeMillis()-start;
WXLogUtils.renderPerformanceLog("SDKInitInvokeTime", WXEnvironment.sSDKInitInvokeTime);
//监测weex表现的的一个检测器的初始化
WXPerformance.init();
mIsInit = true;
}
}
此方法最终会调用doInitInternal(application,config),其余部分的代码叔要是设置apk的debug和log模式,计算weexSDK初始化所需时间等。那么接下来看doInitInternal(application,config)的代码。
private static void doInitInternal(final Application application,final InitConfig config){
//这里给WXEnvironment中的application赋值,方便后续使用
WXEnvironment.sApplication = application;
if(application == null){//application为空的话报错
WXLogUtils.e(TAG, " doInitInternal application is null");
WXExceptionUtils.commitCriticalExceptionRT(null,
WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT,
"doInitInternal",
WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT.getErrorMsg() + "WXEnvironment sApplication is null",
null);
}
//weex环境初始化标识设置为false
WXEnvironment.JsFrameworkInit = false;
//通过单例模式获取一个WXBridgeManager的唯一实例,使用WXBridgeManager开启一个安全的线程初始化weex框架。
//开启安全线程的细节暂时不深究,这里主要看weex框架的初始化流程
WXBridgeManager.getInstance().post(new Runnable() {
@Override
public void run() {
//开始初始化时间
long start = System.currentTimeMillis();
//获取WXSDKManager实例
WXSDKManager sm = WXSDKManager.getInstance();
//使用sm监听weex框架初始化,我们可以通过WXSDKManager.registerStatisticsListener()
//注册一个监听器
sm.onSDKEngineInitialize();
//设置weex框架配置项
if(config != null ) {
sm.setInitConfig(config);
}
//初始化so文件加载器,后两个参数分别为初始化时的加载器和监听器。
WXSoInstallMgrSdk.init(application,
sm.getIWXSoLoaderAdapter(),
sm.getWXStatisticsListener());
//加载so库文件,如不设置自定义的IWXSoLoaderAdapter,那么采用系统默认方式加载
boolean isSoInitSuccess = WXSoInstallMgrSdk.initSo(V8_SO_NAME, 1, config!=null?config.getUtAdapter():null);
if (!isSoInitSuccess) {//加载失败报错
WXExceptionUtils.commitCriticalExceptionRT(null,
WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT,
"doInitInternal",
WXErrorCode.WX_KEY_EXCEPTION_SDK_INIT.getErrorMsg() + "isSoInit false",
null);
return;
}
//使用WXSDKManager初始化jsFramwork,就是讲weexSdk中assets下的js文件拷贝到缓存目录中,使用so的native方法执行
sm.initScriptsFramework(config!=null?config.getFramework():null);
//计算初始化所用时间
WXEnvironment.sSDKInitExecuteTime = System.currentTimeMillis() - start;
WXLogUtils.renderPerformanceLog("SDKInitExecuteTime", WXEnvironment.sSDKInitExecuteTime);
}
});
//注册weexSDK内置的一系列Component和Module
register();
}
二、组件(Component)注册流程
按照weex官网的流程,首先我们会调用WXSDKEngine的registerComponent(String type, Class<? extends WXComponent> clazz)方法。
我们在WXSDKEngine源码中找到这个方法:
public static boolean registerComponent(String type, Class<? extends WXComponent> clazz) throws WXException {
return WXComponentRegistry.registerComponent(type, new SimpleComponentHolder(clazz),new HashMap<String, Object>());
}
我们发现该方法实际上是调用了WXComponentRegistry.registerComponent(xx,xx,xx)方法,我们先对SimpleComponentHolder留意,后续会用到。那么我们跟踪到WXComponentRegistry中查看registerComponent方法的实现。
public static synchronized boolean registerComponent(final String type, final IFComponentHolder holder, final Map<String, Object> componentInfo) throws WXException {
if (holder == null || TextUtils.isEmpty(type)) {
return false;
}
//execute task in js thread to make sure register order is same as the order invoke register method.
//在js线程执行这个注册组件的任务,以确保我们注册组件的顺序与调用注册方法的顺序一致。
WXBridgeManager.getInstance()
.post(new Runnable() {
@Override
public void run() {
try {
Map<String, Object> registerInfo = componentInfo;
if (registerInfo == null){
registerInfo = new HashMap<>();
}
//设置注册信息
registerInfo.put("type",type);
//holder是之前让大家留意的SimpleComponentHolder类
registerInfo.put("methods",holder.getMethods());
//生成原生组件映射
registerNativeComponent(type, holder);
//将组件注册信息传递到jsFramwork,生成js中解析vue中原生component是所需的Json映射
registerJSComponent(registerInfo);
//sComponentInfos是js解析需要使用的类,包含所有组件的注册信息
sComponentInfos.add(registerInfo);
} catch (WXException e) {
WXLogUtils.e("register component error:", e);
}
}
});
return true;
}
以上有几行代码需要在跟踪代码进一步分析:
1、holder.getMethods();
此处的holder对象即之前让大家留意的new SimpleComponentHolder(clazz),我们跟踪源码看一下这个方法的实现
public static Pair<Map<String,Invoker>,Map<String,Invoker>> getMethods(Class clz){
Map<String, Invoker> methods = new HashMap<>();
Map<String, Invoker> mInvokers = new HashMap<>();
Annotation[] annotations;
Annotation anno;
try {
for (Method method : clz.getMethods()) {
try {
annotations = method.getDeclaredAnnotations();
for (int i = 0, annotationsCount = annotations.length;
i < annotationsCount; ++i) {
anno = annotations[i];
if(anno == null){
continue;
}
if (anno instanceof WXComponentProp) {
String name = ((WXComponentProp) anno).name();
methods.put(name, new MethodInvoker(method,true));
break;
}else if(anno instanceof JSMethod){
JSMethod methodAnno = (JSMethod)anno;
String name = methodAnno.alias();
if(JSMethod.NOT_SET.equals(name)){
name = method.getName();
}
mInvokers.put(name, new MethodInvoker(method,methodAnno.uiThread()));
break;
}
}
} catch (ArrayIndexOutOfBoundsException | IncompatibleClassChangeError e) {
//ignore: getDeclaredAnnotations may throw this
}
}
}catch (IndexOutOfBoundsException e){
e.printStackTrace();
//ignore: getMethods may throw this
}
return new Pair<>(methods,mInvokers);
}
代码很简单,我们可以看出这个方法获取了要注册的Component的所有属性和方法,并把它们方法两个map集合中,最后将两个map封装成Pair返回。
时间上就是通过对WXComponent.Class对象的解析获取了其所有的属性和方法(通过WXComponentProp和JSMethod注解)。
获取成功后通过registerInfo.put("methods",holder.getMethods());将这些属性和方法信息放到组件的注册信息中。
2、registerNativeComponent(type, holder);
此方法属于用于生成原生组件的映射,用于对js文件的解析,我们同样来看一下此方法的实现。
//WXComponentRegistry.java
private static boolean registerNativeComponent(String type, IFComponentHolder holder) throws WXException {
try {
holder.loadIfNonLazy();
sTypeComponentMap.put(type, holder);
}catch (ArrayStoreException e){
e.printStackTrace();
//ignore: ArrayStoreException: java.lang.String cannot be stored in an array of type java.util.HashMap$HashMapEntry[]
}
return true;
}
holder.loadIfNonLazy();这行代码调用了SimpleComponentHolder的loadIfNonLazy方法对holder进行了加载,实际上是将组件属性和方法信息保存在SimpleComponentHolder类型的对象holder中,之后将holder保存到sTypeComponentMap中,这是一个component组件的映射集合Map,它是一个静态变量。后续与sComponentInfos配合实现对js文件中component组件的解析(将编译成的Json对象映射解析成原生组件)。
loadIfNonLazy()方法实现如下,比较简单,不在详细说明,看注释即可。
//SimpleComponentHolder.java
@Override
public void loadIfNonLazy() {
//获取类中所有注解
Annotation[] annotations = mClz.getDeclaredAnnotations();
for (Annotation annotation :
annotations) {
if (annotation instanceof Component){
if(!((Component) annotation).lazyload() && mMethodInvokers == null){
//通过此方法获得组件类的方法和属性,并保存
generate();
}
return;
}
}
}
private synchronized void generate(){
if(WXEnvironment.isApkDebugable()) {
WXLogUtils.d(TAG, "Generate Component:" + mClz.getSimpleName());
}
//通过getMethods()方法获取属性和方法信息
Pair<Map<String, Invoker>, Map<String, Invoker>> methodPair = getMethods(mClz);
//保存属性和方法信息到自身
mPropertyInvokers = methodPair.first;
mMethodInvokers = methodPair.second;
}
3、registerJSComponent(registerInfo);
此方法用于将组件的属性和方法信息转换成对象的Json对象。
//WXComponentRegistry.java
private static boolean registerJSComponent(Map<String, Object> componentInfo) throws WXException {
ArrayList<Map<String, Object>> coms = new ArrayList<>();
coms.add(componentInfo);
WXSDKManager.getInstance().registerComponents(coms);
return true;
}
//WXSDKManager.java
public void registerComponents(List<Map<String, Object>> components) {
mBridgeManager.registerComponents(components);
}
最终调用的是WXBridgeManager的invokeRegisterComponents方法。实现如下,我们结合注释说明一下实现过程。
//WXBridgeManager.java
/**
* Registered component
*/
public void registerComponents(final List<Map<String, Object>> components) {
//js线程处理器或者组件的集合为空则之间返回
if (mJSHandler == null || components == null
|| components.size() == 0) {
return;
}
//在JsThred中进行组件注册
post(new Runnable() {
@Override
public void run() {
invokeRegisterComponents(components, mRegisterComponentFailList);
}
}, null);
}
//注册组件
private void invokeRegisterComponents(List<Map<String, Object>> components, List<Map<String, Object>> failReceiver) {
//failReceiver是一个注册失败的组件的集合
if (components == failReceiver) {
throw new RuntimeException("Fail receiver should not use source.");
}
//jsFramwork初始化未完成就将组件放入到注册失败的集合中
if (!isJSFrameworkInit()) {
WXLogUtils.e("[WXBridgeManager] invokeRegisterComponents: framework.js uninitialized.");
for (Map<String, Object> comp : components) {
failReceiver.add(comp);
}
return;
}
if (components == null) {
return;
}
//将通过组件的映射信息将其转化为Json
WXJSObject[] args = {new WXJSObject(WXJSObject.JSON,
WXJsonUtils.fromObjectToJSONString(components))};
try {
//通过调用WXBridge的native方法execJS(),调用main.js中的registerComponent方法注册组件
mWXBridge.execJS("", null, METHOD_REGISTER_COMPONENTS, args);
} catch (Throwable e) {
WXLogUtils.e("[WXBridgeManager] invokeRegisterComponents ", e);
WXExceptionUtils.commitCriticalExceptionRT(null,
WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_CONTENT_FAILED,
METHOD_REGISTER_COMPONENTS,
WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_CONTENT_FAILED.getErrorMsg()
+ args.toString()
+ WXLogUtils.getStackTrace(e),
null);
}
}
三、模块(Module)注册流程
下面是相关实现代码,只写一下简单的注释,模块注册流程与组件注册很类似,不再详细说明,感兴趣可以尝试自己阅读源码分析一下。
//WXSDKEngine
public static boolean registerModule(String moduleName, Class<? extends WXModule> moduleClass) throws WXException {
return registerModule(moduleName, moduleClass,false);
}
public static <T extends WXModule> boolean registerModule(String moduleName, Class<T> moduleClass,boolean global) throws WXException {
return moduleClass != null && registerModule(moduleName, new TypeModuleFactory<>(moduleClass), global);
}
public static <T extends WXModule> boolean registerModule(String moduleName, ModuleFactory factory, boolean global) throws WXException {
//在WXSDKEngine中最终调用WXModuleManager.registerModule(moduleName, factory,global)
return WXModuleManager.registerModule(moduleName, factory,global);
}
//WXModuleManager
/**
* Register module to JavaScript and Android
*/
public static boolean registerModule(final String moduleName, final ModuleFactory factory, final boolean global) throws WXException {
if (moduleName == null || factory == null) {
return false;
}
if (TextUtils.equals(moduleName, WXDomModule.WXDOM)) {
WXLogUtils.e("Cannot registered module with name 'dom'.");
return false;
}
try {
//这句代码不知道为啥写,因为后面执行了相同的代码,就是将持有Module类信息的TypeModuleFactory对象保存到sModuleFactoryMap中 //去。不知道是不是源码写错了,有高见的同学请赐教
sModuleFactoryMap.put(moduleName, new ModuleFactoryImpl(factory));
} catch (Throwable e) {
}
//execute task in js thread to make sure register order is same as the order invoke register method.
WXBridgeManager.getInstance()
.post(new Runnable() {
@Override
public void run() {
if (sModuleFactoryMap != null && sModuleFactoryMap.containsKey(moduleName)) {
WXLogUtils.w("WXComponentRegistry Duplicate the Module name: " + moduleName);
}
try {
//原生代码中注册module模块的类信息
registerNativeModule(moduleName, factory);
} catch (WXException e) {
WXLogUtils.e("registerNativeModule" + e);
}
if (global) {
try {
WXModule wxModule = factory.buildInstance();
wxModule.setModuleName(moduleName);
sGlobalModuleMap.put(moduleName, wxModule);
} catch (Exception e) {
WXLogUtils.e(moduleName + " class must have a default constructor without params. ", e);
}
}
registerJSModule(moduleName, factory);
}
});
return true;
}
//原生代码中注册module模块的类信息
static boolean registerNativeModule(String moduleName, ModuleFactory factory) throws WXException {
if (factory == null) {
return false;
}
try {
if (!sModuleFactoryMap.containsKey(moduleName) ) {
//将持有Module类信息的TypeModuleFactory对象保存到sModuleFactoryMap中去
sModuleFactoryMap.put(moduleName, new ModuleFactoryImpl(factory));
}
}catch (ArrayStoreException e){
e.printStackTrace();
//ignore:
//may throw this exception:
//java.lang.String cannot be stored in an array of type java.util.HashMap$HashMapEntry[]
WXLogUtils.e("[WXModuleManager] registerNativeModule Error moduleName:" + moduleName + " Error:" + e.toString());
}
return true;
}
//在Js中注册module模块的方法和名称信息
static boolean registerJSModule(String moduleName, ModuleFactory factory) {
Map<String, Object> modules = new HashMap<>();
modules.put(moduleName, factory.getMethods());
WXSDKManager.getInstance().registerModules(modules);
return true;
}
//WXBridgeManager
private void invokeRegisterModules(Map<String, Object> modules, List<Map<String, Object>> failReceiver) {
if (modules == null || !isJSFrameworkInit()) {
if (!isJSFrameworkInit()) {
WXLogUtils.d("[WXinvokeRegisterModulesBridgeManager] invokeRegisterModules: framework.js uninitialized.");
}
failReceiver.add(modules);
return;
}
//将modules转换成WXJSObject
WXJSObject[] args = {new WXJSObject(WXJSObject.JSON,
WXJsonUtils.fromObjectToJSONString(modules))};
try {
//调用WXBrige的native方法在js中注册module
mWXBridge.execJS("", null, METHOD_REGISTER_MODULES, args);
try {
Iterator<String> iter = modules.keySet().iterator();
while (iter.hasNext()) {
String module = iter.next();
if (module != null) {
WXModuleManager.resetModuleState(module, true);
WXLogUtils.e("[WXBridgeManager]invokeRegisterModules METHOD_REGISTER_MODULES success module:" + module);
}
}
} catch (Throwable e) {
}
} catch (Throwable e) {
WXExceptionUtils.commitCriticalExceptionRT(null,
WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_MODULES,
"invokeRegisterModules", WXErrorCode.WX_KEY_EXCEPTION_INVOKE_REGISTER_MODULES.getErrorMsg() +
" \n " + e.getMessage() + modules.entrySet().toString(),
null );
WXLogUtils.e("[WXBridgeManager] invokeRegisterModules:", e);
}
}
---------------------
Weex框架源码分析(Android)(一)的更多相关文章
- Android Small插件化框架源码分析
Android Small插件化框架源码分析 目录 概述 Small如何使用 插件加载流程 待改进的地方 一.概述 Small是一个写得非常简洁的插件化框架,工程源码位置:https://github ...
- 介绍开源的.net通信框架NetworkComms框架 源码分析
原文网址: http://www.cnblogs.com/csdev Networkcomms 是一款C# 语言编写的TCP/UDP通信框架 作者是英国人 以前是收费的 售价249英镑 我曾经花了 ...
- YII框架源码分析(百度PHP大牛创作-原版-无广告无水印)
YII 框架源码分析 百度联盟事业部——黄银锋 目 录 1. 引言 3 1.1.Yii 简介 3 1.2.本文内容与结构 3 2.组件化与模块化 4 2.1.框架加载和运行流程 4 ...
- 源码分析Android Handler是如何实现线程间通信的
源码分析Android Handler是如何实现线程间通信的 Handler作为Android消息通信的基础,它的使用是每一个开发者都必须掌握的.开发者从一开始就被告知必须在主线程中进行UI操作.但H ...
- Spark RPC框架源码分析(一)简述
Spark RPC系列: Spark RPC框架源码分析(一)运行时序 Spark RPC框架源码分析(二)运行时序 Spark RPC框架源码分析(三)运行时序 一. Spark rpc框架概述 S ...
- Spark RPC框架源码分析(二)RPC运行时序
前情提要: Spark RPC框架源码分析(一)简述 一. Spark RPC概述 上一篇我们已经说明了Spark RPC框架的一个简单例子,Spark RPC相关的两个编程模型,Actor模型和Re ...
- Spark RPC框架源码分析(三)Spark心跳机制分析
一.Spark心跳概述 前面两节中介绍了Spark RPC的基本知识,以及深入剖析了Spark RPC中一些源码的实现流程. 具体可以看这里: Spark RPC框架源码分析(二)运行时序 Spark ...
- nodejs的Express框架源码分析、工作流程分析
nodejs的Express框架源码分析.工作流程分析 1.Express的编写流程 2.Express关键api的使用及其作用分析 app.use(middleware); connect pack ...
- laravel框架源码分析(一)自动加载
一.前言 使用php已有好几年,laravel的使用也是有好长时间,但是一直对于框架源码的理解不深,原因很多,归根到底还是php基础不扎实,所以源码看起来也比较吃力.最近有时间,所以开启第5.6遍的框 ...
随机推荐
- 【bzoj3105】【cqoi2013】【新Nim游戏】【线性基+贪心】
Description 传统的Nim游戏是这种:有一些火柴堆,每堆都有若干根火柴(不同堆的火柴数量能够不同).两个游戏者轮流操作,每次能够选一个火柴堆拿走若干根火柴.能够仅仅拿一根,也能够拿走整堆火柴 ...
- JavaWeb开发环境搭建
Tomcat 的主要配置 Tomcat:tomcat是实现了一个JavaEE标准的最小的Webserver,是Apche组织开发的,免费的server,能够在网络中直接下载. 最新的版本号应该是8的版 ...
- javascript 数组总结
数组的创建: 数组可以使用Array构造函数来创建,或者使用[]快速创建. 1. Array构造函数创建数组: 无参数,创建空数组: var arry = new Array(); 参数为一个数字,指 ...
- OpenStack二三事(2)
使用devstack在virtualbox上安装openstack还真是比較麻烦,到处都是坑.近期碰到的坑是在tempest上,在执行verify-tempest-config时,代码中import了 ...
- 【EasyUi DataGrid】批量删除
DataGrid是我们做网页经常使用到的组件之中的一个,对它的操作也无非是增删改查操作.单条数据的增删改相对来说比較简单.添加.改动能够直接在DataGrid中进行,也能够用弹出框的形式把数据装载在文 ...
- apache ua Custom Log Formats
RewriteEngine OnRewriteBase / RewriteCond %{HTTP_USER_AGENT} (android|bb\d+|meego).+mobile|avantgo|b ...
- mac 配置hadoop 2.6(单机和伪分布式)
一.准备工作: 安装jdk >= 1.7: http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133 ...
- Android开发:setAlpha()方法
paint.setAlpha() 即透明度.其取值范围是0---255,数值越小,越透明,颜色上表现越淡. 实际上当设成10以下就会有透明的效果了.
- 2.EF的数据审计日志
转载:采用EntityFramework.Extended 对EF进行扩展(Entity Framework 延伸系列2) 数据审计日志: 先说一下这个审计的概念,就是对所有的实体的操作(增,删,改) ...
- CSS3径向渐变实现优惠券波浪造型
效果看下图: 左右的波浪边框用CSS搞定这个效果.利用CSS radial-gradient() 函数 CSS 语法: background: radial-gradient(shape size a ...