页面跳转
Page是AppWorker应用中最重要的概念,我们详细介绍Page的一下相关问题,相关的App和UI的概念也会介绍,适合所有初学者。
一. 概念
Page是管理一组ui和相关逻辑的基本集合。如果了解Android和iOS的话,Page等同于Android的Activity和iOS的UIViewController。
从视觉上来看,一个Page是一个扩充全屏的一个View,这个View包含一个主ui,主UI又可以包含很多个子ui,这里的ui指一个ui文件。从逻辑上来说,一个Page通常管理业务逻辑的一个模块,比如登陆页面,首页等等,我们平常设计App的时候,每个页面通常就指一个Page。
二. 组织结构
1. Page栈
一个AppWorker的App包含一个do_App对象,包含多个Page(do_Page对象)。通过do_App维护一个栈来管理多个Page对象,如下图。
管理手段其实就2个方法:openPage和closePage,对应上面的图就是压栈和出栈。这个图表示App运行时当前的页面情况,Page1上面是Page2,Page2上面是Page3,Page6是栈顶,在当前时刻,用户只能看见Page6,因为Page是全屏不透明的。但是其它3个Page还是在应用的内存中,并没有释放。
do_Page是一个SM对象,但是是一个特殊的SM对象,通常一个SM对象在整个App没有退出前,在任何地方都只有一个对象实例,也就是在任何时刻获取这个对象的地址都是一样的。Page对象特殊在于它并不是唯一示例,但是由于用户只能操作Page栈顶的Page,所以不会有什么问题。
//比如do_App是一个SM对象,do_Album是一个SM对象,do_Page是一个SM对象
var app = sm("do_App");
var album = sm("do_Album");
var page = sm("do_Page");
print(app.getAddress());//任何时刻任何地方执行值都一样
print(album.getAddress());//任何时刻任何地方执行值都一样
print(page.getAddress());//返回的值可能不一样
2. Page交互设计
有一个常见问题就是App的设计思路沿用了浏览器加载网页的思路,不断的openPage而不closePage。正确的页面跳转交互设计应该是树状结构,而不应该是网状结构,如下图:
我们来比较一下,从page1到page3再到page8的过程中,Page栈的内容差异如下
正确的方式
page1—>page2
page1—>page2—>page3
page1—>page2
page1
page1—>page8
错误的方式
page1—>page2
page1—>page2—>page3
page1—>page2—>page3—>page8
我们可以看到错误的方式会导致栈一直增加,从不或者很少出栈,经常出现的问题是page1打开page2,page2又打开page1,导致循环,这样很快内存就会耗尽导致app闪退,而且这种方式导致数据的流转非常混乱。
为了避免栈太深,Android限制了最多只能16层。也就是page1打开page2,page2打开page3,一直到page16就无法再openPage了。
三. 生命周期
一个Page的开始是由openPage开始,到结束closePage,它的基本流程是如下图:
有一些问题需要进一步解释
1. 每个Page都有一个主ui文件,比如当前栈顶是app.js,在app.js里执行openPage代码
//app.js
app.on("loaded", function () {
d1.print("start open page");
app.openPage("source://view/index.ui");
});
执行完,那么新的page打开,这个page的主ui就是index.ui。但是index.ui.js里可能会加载一个或多个子ui,通常2种方式引进子ui
//index.ui.js
//第一种:通过add方法在现有ui上添加新的ui
var layout = ui("ALayout_1");
layout.add("idtest", "source://view/added.ui")
//第二种:很多容器组件可以添加多个子ui
var viewshower = ui("do_ViewShower_1");
var data = [ {
"id" : "test1",
"path" : "source://view/1.ui"
}, {
"id" : "test2",
"path" : "source://view/2.ui"
}, {
"id" : "test3",
"path" : "source://view/3.ui"
} ];
viewshower.addViews(data);
viewshower.showView("test2");
这样当前栈顶的page主ui就是index.ui,里面包含了子ui是 added.ui,1.ui,2.ui,3.ui
2. 上个例子,added.ui,2.ui都加载完,而且added.ui.js,2.ui.js都加载完,新的page才开始以动画的形式打开。为了提高效率和体验,可以把一些子ui以到page打开之后才加载。比如放到page的loaded事件里执行。
//index.ui.js
var page = sm("do_Page");
page.on("loaded",functioin(){
//在新的page页面弹出之后,才执行下面的代码
var layout = ui("ALayout_1");
layout.add("idtest", "source://view/added.ui")
})
上面的例子并没有加载1.ui和3.ui 是因为do_ViewShower组件处理过,只有showView的时候才去加载,而addViews的时候不加载,为了提高效率。
这里可以参考完整的例子,执行的时候可以看到在Logger看到加载的顺序打印。
3. Page的生命周期中还有pause和resume事件,平常用的不是很多,请参考API文档.
result事件用的非常多,下面还会详细说
四. 数据传递
涉及到2个部分,page和page之间的数据传递,单个page里的主ui和子ui之间的数据传递
1. Page与Page之间的数据传递
Page1需要在打开Page2的时候去传递一些数据给Page2,Page2关闭自身,需要通知Page1并传递一些数据,这个过程主要依靠openPage,closePage的data参数以及result事件来实现。
这一部分在文档数据分享和数据传递有了详细的介绍
2. 一个Page内数据传递
单个page里的主ui和子ui之间的数据传递主要依靠page对象的自定义消息的机制。一个ui订阅page的一个消息,另外一个ui触发这个消息。这一部分在文档事件机制有了详细的介绍
五. closePage多层
Page栈是通过openPage一层层的压栈,通过closePage一层层的出栈,并不能跳跃的关闭栈内任意Page,但是AppWorker支持一次closePage多层或关闭到某一特定层
二种方式
1. 一次关闭多层
2. 直接关闭到特定层,其中page1的唯一标示是’pageid1’
网友评论