메시지/이벤트 메커니즘은 거의 모든 개발 언어에서 발견되는 메커니즘입니다. 이는 deviceone에만 국한되지 않으며 일부 언어에서는 메시지(Message)라고도 합니다. , 원칙은 비슷합니다. 일부 구현 방법이 조금 더 복잡하다는 것뿐입니다. 우리의 DeviceOne 통합 이름은 메시지라고 합니다.
메시지 기본 개념
이 메커니즘에 익숙하지 않은 초보자도 있습니다. 몇 가지 기본 개념을 간략하게 소개하겠습니다. 익숙하다면 이 부분을 건너뛰어도 됩니다.
메시지는 다음과 같은 기본 부분을 포함하는 데이터 구조로 이해될 수 있습니다.
1. 메시지 소스: 메시지의 소스이자 메시지를 보내는 객체입니다
2. 메시지 이름: 메시지의 고유 식별자입니다.
3. 메시지 데이터: 메시지 전송 후 첨부된 데이터, 데이터가 비어 있을 수 있음
메시지는 두 가지 유형으로 나눌 수 있습니다:
1. 시스템 메시지: 운영체제나 디바이스원 시스템에서 보내는 메시지입니다. 메시지 이름은 고정되어 있습니다.
2. 맞춤 메시지: 메시지는 개발자가 직접 정의하여 전송합니다. 메시지 이름은 임의이며 임의로 정의할 수 있습니다.
예:
예를 들어 사용자가 do_Button 버튼을 클릭하면 다음 세 부분이 포함된 시스템 메시지가 트리거됩니다.
1. 메시지 출처: 사용자 클릭의 버튼 개체
2. 메시지 이름: 터치
3. 메시지 데이터: 이 메시지에는 데이터가 포함되어 있지 않습니다
예를 들어, 사용자는 세 부분으로 구성된 do_Button 버튼을 통해 맞춤 이벤트를 트리거합니다.
1.메시지 소스: 버튼 객체
2. 메시지 이름: 사용자가 원하는 대로 정의할 수 있으며 aaa, bbb, ccc로 지정할 수 있습니다.
3. 메시지 데이터: 메시지가 실행될 때 첨부된 데이터가 설정됩니다
게시/구독 모드
Publish/Subscribe 패턴은 가장 일반적으로 사용되는 디자인 패턴 중 하나이며 메시징 메커니즘의 핵심입니다. 두 개의 독립된 객체가 서로 의존하지 않도록 결합을 줄이는 것이 특징입니다. 간단한 소개이므로 친숙한 학생들은 건너뛸 수 있습니다.
먼저 현실의 간단한 예를 들어 이 문제를 설명하겠습니다. 아래 그림을 참조하세요.
이 사진을 보면 알 수 있습니다
1. 소비자와 출판사는 서로 알지 못합니다. 소비자는 자신이 원하는 잡지가 어느 출판사에서 발행되는지 알 필요가 없습니다. 출판사는 자신이 출판하려는 잡지를 구체적으로 주문한 사람이 누구인지 알 필요가 없습니다.
2. 소비자와 출판사 모두 우체국을 알아야 합니다.
3. 소비자는 소비자의 이름과 주소, 구독하려는 잡지 이름을 우체국에 알려야 합니다
4. 여러 소비자가 동일한 잡지를 구독할 수 있습니다
5. 우체국은 잡지를 수령한 후 소비자에게 하나씩 알리고 동시에 소비자에게 잡지를 전달합니다.
위의 실제 사례를 읽은 후, 이해를 돕기 위해 추상적인 설명을 살펴보겠습니다.
은 위의 실제 예시 설명에 해당합니다.
1. 시스템/개발자와 함수 개체는 서로 의존하지 않습니다. 시스템/개발자는 메시지를 트리거할 뿐이며 메시지를 받는 사람은 상관하지 않습니다.
2. 시스템/개발자 및 함수 개체는 메시지 소스 개체를 얻을 수 있어야 합니다
3. 함수 개체가 메시지를 구독할 때 메시지 이름과 함수 개체에 대한 참조를 표시해야 합니다.
4. 여러 함수 개체가 동일한 메시지 소스와 동일한 이름을 가진 메시지를 구독할 수 있습니다
5. 메시지 소스가 메시지를 트리거하면 모든 구독자에게 하나씩 알리고 콜백 함수 개체에 데이터를 전달합니다.
추상적인 설명을 읽은 후, 마지막으로 do_Button을 예로 들어 deviceone 개발의 실제 예를 살펴보겠습니다.
1. 사용자가 버튼을 클릭하고 터치하면 시스템은 버튼 개체를 메시지 소스로 가져오고 "터치" 메시지를 구독하는 모든 함수 개체를 실행합니다. 이 메시지를 받으면 함수가 실행됩니다.
//获取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. 버튼 객체에 대해 두 개의 사용자 정의 메시지 "message1"과 "message2"를 정의하고 두 개의 함수 객체가 이 두 메시지를 각각 구독하도록 할 수 있습니다. 하지만 결국 개발자는 fire 함수를 호출하여 이 메시지를 트리거해야 합니다. 이것이 시스템 메시지와 다릅니다.
//获取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一次后就取消订阅了。