经过文档一的描述,我们已经可以把app的生命周期传递到js。只要app在调用js桥的方法的时候,传了name属性,对应的方法就可以通过js的map正确的传递到对应js页面。这里我们详细描述一下,app的生命周期是如何精准的传递到js的,了解后我们就能明白js是如何传递到app对应的页面的。
name页面的名字属性是核心:
首先,一个原生页面就一定有一个对应的js页面。比如有注册zhuce.activity这个原生页面,就有一个zhuce.js页面与之对应。他们之间的桥梁是name这个属性。
zhuce.activity 注册页面在页面加载后,立马调用了js的onLoad属性,然后js在全局收到了onLoad这个action,此时js取出name = zhuce,发现在原生有一个叫zhuce的页面onLoad了,此时js会立马找到一个叫Zhuce的js的页面类立马实例化,实例化后得到zhuce的js对象,先放到js的pageMaps中,以下是js的核心代码:
let action = json.action //因为这里action=zhuce,我下面就简单的按zhuce页面来写
let page_name = json.name // 这里得到zhuce
let PageClassStr = page_name.upper() //首字母大写,转为Zhuce
if(action == "onLoad"){
let page_obj = eval('new PageClassStr()') //根据Zhuce动态运算得到Zhuce页面的对象实例
window.pageMaps[page_name] = page_obj //注册页面放到全局的map中,key就是zhuce
}
好了,现在可以把app传递过来的生命周期全部转接到注册页面了。
if(page_obj[action] != null){
page_obj[action] (json) //如果page_obj 这个页面实现了action方法,就传json参数并调用
}
生命周期封装:
很明显,页面会创建就一定有销毁。当js收到app传递过来onUnload方法,说明这个原生页面被销毁了,js也会干掉对应的js对象。
所以保证原生页面的生命周期正确被调用很重要。同时,原生页面要正确的被释放,比如从我的页面打开登录页面,然后点了登录返回,此时登录页面应该被销毁并触发onUnload方法,这很重要,这样才能确保资源被正确的释放。
总结一下:
在BaseActivity和BaseFragment封装中,一定要正确触发onLoad, onShow, onHide, onUnload。
全局一个桥,如何区分页面的?
了解了上面的js的操作逻辑,其实实现对应的原生页面也不难了。在正式说明之前,需要说明一个重要的约定,即任何一个页面都一定有一个具体的子类。比如登录页面一定有一个DengluActivity,我们不是动态从父类实例化的,我们是从一个确定的子类来的,这非常重要。后面说到原因。因为每个页面可能未来操作不太一样,而且每个页面的数据事件都是在子类各自实现的。
首先在原生需要定义一个map,这个map主要实现两个功能:
(1)给一个页面的page字符串,需要知道对应页面的具体的类名,用于push的时候动态反射实例化。
(2)如果page对应的页面实例化后,需要再保存对应的存在的页面对象。
因为安卓tab的原因,我们设计了BasePageInterface接口来统一BaseActivity和BaseFragment. 所以这个map我们这样设计:
(1)首先map放哪,我觉得应该可以放到静态变量中,ios因为只有一个类,我放到了BaseActivity中。假设你放到全局变量中:pageMap
(2)大概长什么样子?
let pageMap: [String: BasePageInterface] = {
"denglu": {
"Class": "DengluActivity",//登录页面的类名,用来反射实例化对象
"instance": null, //BasePageInterface类型,登录页面的实例化后的对象
} ,
//其他页面
}
有了这个page后,虽然全局只有一个桥,但js用页面的name可以找到精准的对应的页面。
现在我们再回到封装中,以BaseActivity为例(BaseFragment同理),页面的初始化的时候一定要完善name字段,每个页面都有name属性。
在BaseActivity的onLoad里面
pageMap[this.name].instance = this //当前页面已经是一个实例,指针放到map中。
js("onLoad") //调用js的onLoad,上一篇已经说明过了
很明显,有一个对称的操作:
在BaseActivity的onUnload里面
pageMap[this.name].instance = null //当前页面已经销毁,从map中移除实例
js("onUnload") //调用js的onUnload,上一篇已经说明过了,
初始化tab需要初始化完善一些map需要的信息:
好了。现在我们创建4个tab页面的时候,这4个tab页面一启动就存在了,所以我们需要手动完善下map:
pageMap["shouye"].instance = shouye //其他4个页面同理
app一启动,有默认有5个instance存在于map中了,其他页面基本是封装好后,js来自动化管理控制了。假设没操作这步,很明显js在使用name找页面的时候是找不到对应的tab页面的。
技术实战:
push协议:
协议名:push
参数:
{
"name": "denglu" //push新页面的name,app需要根据name取出Class实例化
"options": "", //json格式的参数,后面细说
}
push的时候,app需要根据name取出Class实例化,然后打开新页面,可以知道,因为是封装的原因,新页面创建后,在内部onLoad会自动把自己放到pageMap中。
当然我们要触发push依赖点击事件,这个是下一篇文件VM表单控件触发的说完才能触发push,不过可以先写push这个方法。我们循循渐进。