The message/event mechanism is a mechanism found in almost all development languages. It is not unique to deviceone. In some languages, it is called message (Event), and in some places it is called (Message). In fact, the principle is similar. It's just that some implementation methods are a little more complicated. Our deviceone unified name is called message.
Basic Concepts of Messages
There are some beginners who are not familiar with this mechanism. Let’s briefly introduce some basic concepts. If you are familiar with it, you can skip this part.
A message can be understood as a data structure, including the following basic parts:
1. Message source: It is the source of the message and the object that sends the message
2. Message name: It is the unique identifier of the message
3. Message data: the data attached after the message is sent, the data may be empty
Messages can be divided into two types:
1. System message: a message sent by the operating system or deviceone system. The name of the message is fixed.
2. Custom message: The message is defined by the developer himself and sent by himself. The name of the message is arbitrary and can be defined arbitrarily.
Example:
For example, if the user clicks a do_Button button, a system message will be triggered, which contains 3 parts:
1. Message source: button object in user click
2. Message name: touch
3. Message data: This message does not come with data
For example, the user triggers a custom event through the do_Button button, which contains 3 parts:
1.Message source: button object
2. Message name: User can define it as desired, it can be called aaa, bbb, ccc
3. Message data: The attached data is set when the message is triggered
Publish/Subscribe Mode
The publish/subscribe pattern is one of the most commonly used design patterns and is the core of the messaging mechanism. Its characteristic is to reduce coupling so that two independent objects do not depend on each other. A brief introduction, familiar students can skip it.
Let us first illustrate this problem with a simple example from reality, refer to the picture below:
We can see from this picture
1. Consumers and publishers do not know each other. Consumers do not need to know which publisher the magazine they want is published; publishers do not need to know who specifically ordered the magazine they want to publish. Book.
2. Both consumers and publishers must know the post office.
3. Consumers need to tell the post office the name and address of the consumer and the name of the magazine they want to subscribe to
4. Multiple consumers can subscribe to the same magazine
5. After the post office receives the magazine, it will notify consumers one by one and deliver the magazine to consumers at the same time.
After reading the above real-life examples, let’s look at the abstract description to make it clearer. Look at the picture below:
corresponds to the actual example description above:
1. The system/developer and the function object do not depend on each other. The system/developer only triggers a message and does not care who receives it
2. The system/developer and function objects must be able to obtain the message source object
3. When a function object subscribes to a message, it needs to indicate the name of the message and the reference to the function object
4. Multiple function objects can subscribe to messages with the same message source and the same name
5. When the message source triggers a message, it will notify all subscribers one by one and pass the data to the callback function object
After reading the abstract description, let’s finally look at the actual example of deviceone development, taking do_Button as an example.
1. When the user clicks on a button and touches it, the system will obtain the button object as the message source and fire a "touch" message. Any function object that subscribes to the "touch" message will receive it. This message does cause the function to execute.
//获取button对象 var btn_hello = ui("btn_hello"); //定义函数对象 function f(){ //当btn_hello这个按钮接收到手指点击就会执行下面的代码 deviceone.print("f 函数接收到点击触发消息") } function f(){ //当btn_hello这个按钮接收到手指点击就会执行下面的代码 deviceone.print("f 函数接收到点击触发消息") } //f,f订阅button的touch消息 btn_hello.on("touch",f); btn_hello.on("touch",f);
2. We can define two custom messages "message1" and "message2" for the button object, and have two function objects subscribe to these two messages respectively. But in the end, the developer must trigger this message by calling the fire function. This is the difference from the system message.
//获取button对象 var btn_hello = ui("btn_hello"); //定义函数对象 function f(d){ //当btn_hello这个按钮接收到开发者触发的消息message就会执行下面的代码 deviceone.print("f 函数接收到message消息,消息的数据是:"+d) } function f(d){ //当btn_hello这个按钮接收到开发者触发的消息message就会执行下面的代码 deviceone.print("f 函数接收到message消息,消息的数据是:"+d) } //f,f订阅button的touch消息 btn_hello.on("message",f); btn_hello.on("message",f); //触发消息 btn_hello.fire("message","data"); btn_hello.fire("message","data");
看到这里,你肯定会奇怪,为什么我们要在button上自定义对象?这有神马意义?其实确实没有意义也没有必要,这里只是拿button举例子,在常规的开发中,基本不会这么用。
消息的使用
前面讲了这么多,现在才是deviceone消息的使用。使用其实很简单,上面的例子基本说明的了系统事件和自定义事件的使用方法。
有几个概念再说明一下
1.deviceone的所有对象,包括UI,MM,SM对象都可以是消息源
// SM对象可以是消息源 var page = sm("do_Page"); page.on("loaded",function()){ // 这个是page对象的系统消息,这个消息不需要手动触发,系统会自动触发 } page.on("message",function(d)){ // 这个是page对象的自定义消息 } page.fire("message","data"); // MM对象可以是消息源 var http = mm("do_Http"); http.on("result",function()){ // 这个是http对象的系统消息,这个消息不需要手动触发,接受到http服务端的反馈后会自动触发 } http.on("message",function(d)){ // 这个是http对象的自定义消息 } http.fire("message","data"); //UI对象可以是消息源 var alayout = ui("alayout_id"); alayout.on("touch",function()){ // 这个是alayout对象的系统消息,这个消息不需要手动触发,手机点击就会触发 } alayout.on("message",function(d)){ // 这个是alayout对象的自定义消息 } alayout.fire("message","data");
2.消息源对象有作用域,所以订阅和触发的消息源必须是是一个作用域的同一个对象。这里结合数据分享和数据传递文档来理解。
看以下的例子,test1.ui和test2.ui有可能在一个page作用域,也有可能不在一个作业域,只有在一个作用域fire的消息才能正确送达回调函数。
判断是否一样,可以通过打印page的地址 page.getAddress().
//在test.ui.js里订阅消息 var page = sm("do_Page"); deviceone.print(page.getAddress()); page.on("message",function(d)){ deviceone.print(d); } //在test.ui.js触发消息 var page = sm("do_Page"); deviceone.print(page.getAddress()); page.fire("message","data");
如果不在同一page作用域,则可以把消息订阅在2个page都能共享到的app作用域
上面的代码改成:
//在test.ui.js里订阅消息 var app = sm("do_App"); app.on("message",function(d)){ deviceone.print(d); } //在test.ui.js触发消息 var app = sm("do_App"); app.fire("message","data");
3.同样的函数对象可以重复订阅一个对象源的消息,触发消息的时候会使函数执行多次,这是初学者经常犯的错误。
var page = sm("do_Page"); var count = ; function f(){ deviceone.print("执行次数"+(count++)); } page.on("message",f); page.on("message",f); page.fire("message");
看上面的例子,如果执行的话,会打印2此,因为订阅了2次,或许你会说谁会写这样的代码?实际情况肯定没有这么容易看出来执行了重复的on函数,实际情况经常是比如在点击事件里执行on函数,每点击一下按钮,就重复订阅一次。
4.消息的订阅一定要在消息的触发之前,这是初学者经常犯的错误。
var page = sm("do_Page"); var count = ; function f(){ deviceone.print("执行次数"+(count++)); } page.fire("message"); page.on("message",f);
看上面的例子,如果执行的话,会没有效果,或许你会说谁会写这样的代码?实际情况肯定没有这么容易看出来顺序反了,实际情况经常是比如on函数执行在某一个函数的回调函数里,你无法确定回调函数啥时候执行,是否是在fire之前执行。一般碰到这种情况可以加几个deviceone.print打印一下看看是on先执行还是fire先执行。
5.有订阅就有取消订阅,取消订阅是off函数,之所以很少用,是因为closePage的时候会自动把当前page作用域订阅的消息全部释放。
但是如果消息订阅在app作用域,就要注意,可能需要手动去取消订阅。否则就会出现触发消息的时候会使函数执行多次的问题。
var page = sm("do_Page"); var count = ; function f(){ deviceone.print("执行次数"+(count++)); } page.on("message",f); page.fire("message"); .page.off("message"); page.fire("message");
看上面的例子,打印只会执行一次,因为fire一次后就取消订阅了。