玩轉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.總結

一句話,高手勿噴。