玩转OneNET物联网平台之MQTT服务⑤ —— OneNet智能灯+MVP框架

  • 2019 年 10 月 29 日
  • 筆記

授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力。希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石。。。

QQ技术互动交流群:ESP8266&32 物联网开发 群号622368884,不喜勿喷

一、你如果想学基于Arduino的ESP8266开发技术

一、基础篇

  1. ESP8266开发之旅 基础篇① 走进ESP8266的世界
  2. ESP8266开发之旅 基础篇② 如何安装ESP8266的Arduino开发环境
  3. ESP8266开发之旅 基础篇③ ESP8266与Arduino的开发说明
  4. ESP8266开发之旅 基础篇④ ESP8266与EEPROM
  5. ESP8266开发之旅 基础篇⑤ ESP8266 SPI通信和I2C通信
  6. ESP8266开发之旅 基础篇⑥ Ticker——ESP8266定时库

二、网络篇

  1. ESP8266开发之旅 网络篇① 认识一下Arduino Core For ESP8266
  2. ESP8266开发之旅 网络篇② ESP8266 工作模式与ESP8266WiFi库
  3. ESP8266开发之旅 网络篇③ Soft-AP——ESP8266WiFiAP库的使用
  4. ESP8266开发之旅 网络篇④ Station——ESP8266WiFiSTA库的使用
  5. ESP8266开发之旅 网络篇⑤ Scan WiFi——ESP8266WiFiScan库的使用
  6. ESP8266开发之旅 网络篇⑥ ESP8266WiFiGeneric——基础库
  7. ESP8266开发之旅 网络篇⑦ TCP Server & TCP Client
  8. ESP8266开发之旅 网络篇⑧ SmartConfig——一键配网
  9. ESP8266开发之旅 网络篇⑨ HttpClient——ESP8266HTTPClient库的使用
  10. ESP8266开发之旅 网络篇⑩ UDP服务
  11. ESP8266开发之旅 网络篇⑪ WebServer——ESP8266WebServer库的使用
  12. ESP8266开发之旅 网络篇⑫ 域名服务——ESP8266mDNS库
  13. ESP8266开发之旅 网络篇⑬ SPIFFS——ESP8266 Flash文件系统
  14. ESP8266开发之旅 网络篇⑭ web配网
  15. ESP8266开发之旅 网络篇⑮ 真正的域名服务——DNSServer
  16. ESP8266开发之旅 网络篇⑯ 无线更新——OTA固件更新

三、应用篇

  1. ESP8266开发之旅 应用篇① 局域网应用 ——炫酷RGB彩灯
  2. ESP8266开发之旅 应用篇② OLED显示天气屏
  3. ESP8266开发之旅 应用篇③ 简易版WiFi小车

四、高级篇

  1. ESP8266开发之旅 进阶篇① 代码优化 —— ESP8266内存管理
  2. ESP8266开发之旅 进阶篇② 闲聊Arduino IDE For ESP8266配置
  3. ESP8266开发之旅 进阶篇③ 闲聊 ESP8266 Flash
  4. ESP8266开发之旅 进阶篇④ 常见问题 —— 解决困扰
  5. ESP8266开发之旅 进阶篇⑤ 代码规范 —— 像写文章一样优美
  6. ESP8266开发之旅 进阶篇⑥ ESP-specific APIs说明

1.前言

    在上一篇博文 玩转OneNET物联网平台之MQTT服务④ —— 远程控制LED(设备自注册)+ Android App控制 中,博主提供了OneNet智能灯的Mqtt协议的配套App。那么,为了方便大家开发以及拓展,博主这里简述一下源码设计。

2.源码下载

  • 请到博主技术交流群群文件下载:
    在这里插入图片描述

3.源码分析

3.1 App开发工具

  • Android Studio,官方认证工具,请自行配置好Java环境以及AS工具,目前博主属于最新版本。

3.2 代码整体结构

  • 把上面下载下来的源码导入Android Studio之后,可以看到如下结构:
    在这里插入图片描述
    博主这里为了开发方便,分出了三个module:
  • app_common,常用公共模块,比如各种工具类(打印日志工具,时间格式转换工具)
    在这里插入图片描述
  • app_ormlib,数据库服务(这里没有用到,为了后面拓展预留)
    在这里插入图片描述
  • app_widget,常用UI,基础组件,包括封装基础activity类,recyclerview,以及我广泛应用的mvp设计框架
    在这里插入图片描述
  • app:这里就是我们主要的业务代码。
    在这里插入图片描述

3.3 MVP框架解析

  • 至于什么叫做MVP,博主这里不讲,请自行百度。以下代码构成了MVP的主体框架:
    在这里插入图片描述
    Model:专注于处理数据
    View:专注于页面显示
    Presenter:协调Model和View的调用关系
  • 接下来,看基于MVP架构的业务代码:
    在这里插入图片描述
    通过名字就可以快速知道对应的具体业务:
  • 配置MQTT页面:OneNetConfigXXXX
  • 列表主页面:MainXXXXX
  • 关于应用页面:AboutMeXXXX
  • 拓展页面:XXXXXXX

接下来,我们挑一个页面来讲解,方便大家了解MVP工作方式。

3.4 Main控制主页面解析

3.4.1 MVP协议

/**   * mvp 主页面协议 presenter层   */  public interface IMainContract {      // model层      interface IMainModel extends IBaseModel {          void loadData(Context context, ICallBack<List<OneNetDeviceModel>> callBack);          void updateDeviceDetail(Context context,OneNetDeviceModel model, ICallBack<String> callBack);      }      //view层      interface IMainView extends IBaseView {          void showLoading(String loadmsg);          void dismissLoading(OnDismissCallbackListener callback);          void refreshList(List<OneNetDeviceModel> list);      }  }

3.4.2 Model层-数据处理

  • 我们关注Main相关的代码:
public class MainModel implements IMainContract.IMainModel {        SimpleTask task;      //获取设备列表      @Override      public void loadData(Context context, final ICallBack<List<OneNetDeviceModel>> callBack) {            if(task != null && task.getStatus()== AsyncTask.Status.RUNNING){              task.cancel(true);          }          task = new SimpleTask() {                GetOneNetDeviceListEntity entity;                @Override              protected void onPreExecute() {                  entity = new GetOneNetDeviceListEntity();              }                @Override              protected Object doInBackground(String... strings) {                  return entity.request();              }                @Override              protected void onPostExecute(Object o) {                  String result = (String) o;                  if("200".equals(result)){                     if(entity.data != null && entity.data.devices.size()!=0) {                         List<OneNetDeviceModel> list = new ArrayList<>();                         for(OneNetDeviceModel model:entity.data.devices){                             if(!model.getId().equals(PreferenceUtil.getInstance().getDeviceId())){                                 list.add(model);                             }                         }                           callBack.onSuccess(list);                     }                  }else {                      callBack.onFaild(result);                  }              }          };          task.startTask();      }    //更新设备信息      @Override      public void updateDeviceDetail(Context context, final OneNetDeviceModel model, final ICallBack<String> callBack) {          if(task != null && task.getStatus()== AsyncTask.Status.RUNNING){              task.cancel(true);          }          task = new SimpleTask() {                UpdateOneNetDeviceDetailEntity entity;                @Override              protected void onPreExecute() {                  entity = new UpdateOneNetDeviceDetailEntity(model.getId());              }                @Override              protected Object doInBackground(String... strings) {                  return entity.request(model);              }                @Override              protected void onPostExecute(Object o) {                  String result = (String) o;                  if("200".equals(result)){                      callBack.onSuccess("更新成功");                  }else {                      callBack.onFaild(result);                  }              }          };          task.startTask();      }  }  

3.4.3 View层-UI处理

/**   * @author wty   * @Description 控制页面   **/  public class MainActivity extends BaseActivity<MainPresenter> implements IMainContract.IMainView {        @Bind(R.id.listview)      XRecyclerView listview;        DeviceListAdapter adapter;          public static void startActivity(Activity activity) {          Intent intent = new Intent(activity, MainActivity.class);          activity.startActivity(intent);      }        @Override      public MainPresenter getPresenter() {          return new MainPresenter();      }        @Override      public void onInitView(Bundle savedInstanceState) {          /**           * 第一个参数是服务器地址           * 第二个参数是用户名           * 第三个参数是密码           * 第四个参数是客户端ID           * 第五个参数是主题           **/          MqttManager                  .getInstance()                  .creatConnect(                          AppConstant.RequestUrl.ONENET_MQTT,                          PreferenceUtil.getInstance().getProductId(),                          PreferenceUtil.getInstance().getApiKey(),                          PreferenceUtil.getInstance().getDeviceId(),                          "esp8266");            getDefaultNavigation().setTitle("OneNet智能灯");          getDefaultNavigation().getLeftButton().setButton("配置", new View.OnClickListener() {              @Override              public void onClick(View v) {                  OneNetMqttConfigActivity.startActivity(MainActivity.this);                  finish();              }          });          getDefaultNavigation().getRightButton().setButton("关于应用", new View.OnClickListener() {              @Override              public void onClick(View v) {                  AboutActivity.startActivity(MainActivity.this);              }          });            LinearLayoutManager layoutManager = new LinearLayoutManager(this);          layoutManager.setOrientation(LinearLayoutManager.VERTICAL);          listview.setLayoutManager(layoutManager);          listview.setPullRefreshEnabled(false);          listview.setLoadingMoreEnabled(false);          List<OneNetDeviceModel> data = new ArrayList<>();          adapter = new DeviceListAdapter(this,data,mPresenter);          listview.setAdapter(adapter);            mPresenter.refreshList(MainActivity.this);      }        @Override      protected boolean isEnableStatusBar() {          return true;      }        @Override      protected List<String> validate() {          List<String> list = super.validate();          return list;      }        @Override      protected void onDestroy() {          super.onDestroy();          MqttManager.release();      }        @Override      public int getLayoutResource() {          return R.layout.activity_main;      }        @Override      public void refreshList(List<OneNetDeviceModel> list) {          adapter.retsetData(list);      }  }  

3.4.4 Presenter层-中间协调层

/**   * 主页面 presenter   */  public class MainPresenter extends BasePresenter<IMainContract.IMainView> {        private IMainContract.IMainModel mMainModel;        public MainPresenter(){          mMainModel = new MainModel();      }        public void refreshList(Context context){          mView.showLoading("获取设备列表中...");            mMainModel.loadData(context, new ICallBack<List<OneNetDeviceModel>>() {              @Override              public void onSuccess(final List<OneNetDeviceModel> list) {                  mView.refreshList(list);                  mView.dismissLoading();              }                @Override              public void onFaild(String msg) {                  mView.dismissLoading(new OnDismissCallbackListener(msg, SweetAlertDialog.ERROR_TYPE));              }          });      }        public void updateDeviceDetail(final Context context, OneNetDeviceModel model){          mView.showLoading("更新设备信息中...");            mMainModel.updateDeviceDetail(context,model, new ICallBack<String>() {              @Override              public void onSuccess(final String result) {                  mView.dismissLoading();                  refreshList(context);              }                @Override              public void onFaild(String msg) {                  mView.dismissLoading(new OnDismissCallbackListener(msg, SweetAlertDialog.ERROR_TYPE));              }          });      }  }  

基本上,每个页面都是按照这个MVP的设计思路去分析就可以了,非常简单。

4.总结

一句话,高手勿喷。