1. 程式人生 > >Android產品研發(九)-->App網路傳輸協議

Android產品研發(九)-->App網路傳輸協議

上一篇文章中我們講解了如何在App中統計資料,其實現主要分為兩種:使用第三方服務統計和自身實現資料統計。一般而言我們使用第三方統計服務已經可以很好的滿足我們的也無需求了,只有部分資料敏感型的App,由於其資料敏感性在app中實現資料統計服務是一個更好的選擇,更多關於App資料統計相關的內容可參考我的:Android產品研發(八)–>App資料統計

而本文將要介紹的是App的網路傳輸協議。App與伺服器互動就會涉及到資訊的交換,而資訊的互動就必然需要一套完整的資料協議。這裡首先需要明確一點的是什麼是網路傳輸協議呢?這裡首先套用一段百度百科的定義:

網路傳輸協議或簡稱為傳送協議(Communications Protocol[1] ),是指計算機通訊的共同語言。現在最普及的計算機通訊為網路通訊,所以“傳送協議”一般都指計算機通訊的傳送協議,如TCP/IP、NetBEUI等。然而,傳送協議也存在於計算機的其他形式通訊,例如,面向物件程式設計裡面物件之間的通訊;作業系統內不同程式之間的訊息,都需要有一個傳送協議,以確保傳信雙方能夠溝通無間。

簡單而言網路傳輸協議就是App端與伺服器端互動的時候約定好的內容格式。比如我們常見的Json格式,xml格式等,這些都是網路傳輸協議,而現在在App開發中比較常見的網路傳輸協議有三種:xmljsonprotobuf

而我們下面將分別分析其各自的使用利弊以及解析方案。

- 網路傳輸協議-XML

xml是一種最早的網路傳輸協議,常見於java web開發中,不單單作為網路層的引數協議,還常見於各種配置檔案中,在移動開發中也常見但是已不是主流的網路傳輸協議。

優點:可讀性強,解析方便;
缺點:效率不高,資源消耗過大;
解析方式:DOM解析,SAX解析,PULL解析;

(1)DOM解析:
解析器讀入整個文件,然後構建一個駐留記憶體的樹結構,然後程式碼就可以使用 DOM 介面來操作這個樹結構。優點:整個文件樹在記憶體中,便於操作;支援刪除、修改、重新排列等多種功能;缺點:將整個文件調入記憶體(包括無用的節點),浪費時間和空間;使用場合:一旦解析了文件還需多次訪問這些資料;硬體資源充足(記憶體、CPU)
(2)SAX解析:
SAX ,事件驅動型解析方式。當解析器發現元素開始、元素結束、文字、文件的開始或結束等時,傳送事件,程式設計師編寫響應這些事件的程式碼,儲存資料。優點:不用事先調入整個文件,佔用資源少;SAX解析器程式碼比DOM解析器程式碼小,適於Applet,下載。缺點:不是持久的;事件過後,若沒儲存資料,那麼資料就丟了;無狀態性;從事件中只能得到文字,但不知該文字屬於哪個元素;使用場合:Applet;只需XML文件的少量內容,很少回頭訪問;機器記憶體少;
(3)PULL解析:
PULL解析方式是Android專門為移動裝置上解析XML檔案而設計的一種解析方式,顯而易見的其更加適用於移動裝置解析xml檔案。Pull解析和Sax解析很相似,Pull解析和Sax解析不一樣的地方是pull讀取xml檔案後觸發相應的事件呼叫方法返回的是數字還有pull可以在程式中控制想解析到哪裡就可以停止解析。

- 網路傳輸協議-JSON

JSON是在移動端比較常見的網路傳輸協議,它較xml格式更叫的簡單和“小”,因此比xml更適合移動端對流量和記憶體的控制。

優點:較XML格式更加小巧;
缺點:傳輸效率也不是太別高,但相較於xml提高了很多;
解析方式:Gson解析,JSONObject方式解析,FastJson解析

(1)Gson解析:
Gson解析方式是Google開源的一套解析方式,通過提供的Gson jar包,通過靜態方法直接由字串解析成java物件,簡單方便。
具體使用方法,可參考:Google Gson 使用簡介

(2)JSONObject解析:
JSONObject在org.json下面的包中,其也是一個解析Json字串的工具類,具體使用方式可參考:

JSONObject與JSONArray的使用

(3)FastJson解析:
FastJson是阿里巴巴開源的一個解析Json資料的類庫,能夠將json字串解析成java物件。這裡有其介紹,英文水平不好就不獻醜了…

  • Provide best performance in server side and Android client.

  • Provide simple toJSONString() and parseObject() methods to convert Java objects to JSON and vice-versa

  • Allow pre-existing unmodifiable objects to be converted to and from JSON

  • Extensive support of Java Generics

  • Allow custom representations for objects

  • Support arbitrarily complex objects (with deep inheritance hierarchies and extensive use of generic types)

- 網路傳輸協議-ProtoBuf

ProtoBuf是Google開源的一套二進位制流網路傳輸協議,它獨立於語言,獨立於平臺。google 提供了多種語言的實現:java、c#、c++、go 和 python,每一種實現都包含了相應語言的編譯器以及庫檔案。由於它是一種二進位制的格式,比使用 xml 進行資料交換快許多。可以把它用於分散式應用之間的資料通訊或者異構環境下的資料交換。作為一種效率和相容性都很優秀的二進位制資料傳輸格式,可以用於諸如網路傳輸、配置檔案、資料儲存等諸多領域。

優點:傳輸效率快(比xml和json快10-20倍),文件型協議;
缺點:使用不太方便;

這裡簡單解釋一下什麼是文件型協議,向我們的xml和json一般在使用的時候都需要儲存一份說明文件和一個實際的java類,而protobuf在使用的時候其定義的格式就是說明文件,簡單明瞭而且可以將其編譯成各個平臺的類庫,以java平臺為例,其程式設計成jar之後,若定義檔案發生了變化,則在使用jar包的話就會報錯,必須重新編譯,這也就保證了App端與伺服器端的協議統一性。

網路傳輸協議實踐

由於ProtoBuf的傳輸效率和文件型協議的特性,公司產品選擇了Protobuf作為網路傳輸協議。下面我就以一個簡單的登入操作,介紹一下對ProtoBuf的實際應用。

(1)定義ProtoBuf檔案
這裡寫圖片描述

(2)定義登入網路操作請求介面

// 提交簡訊驗證碼,如果該手機號碼沒有註冊過,則直接給使用者註冊
message SmsLogin {
    message Request {
        required string phone = 1; // 手機號碼
        required string verifyCode = 2; // 驗證碼
    }

    message Response {
        /*
         * 0:成功;-1:登入失敗;-2:驗證碼錯誤;-3:驗證碼已經失效;-4:手機號碼格式不正確;-5:不是內測使用者不能登入
         */
        required int32 ret = 1;
        optional com.uu.facade.passport.pb.bean.UserAppSessionTicket sessionTicket = 2;
        optional string phone = 3; // 手機號碼
        optional string imgUrl = 4; // 使用者影象url
        optional com.uu.facade.base.common.UserStatus userStatus = 5; // 使用者狀態
    }

}

可以看到在Protobuf中定義網路請求,分為兩個部分,請求部分和應答部分,其message request定義的是請求資訊,而message response定義的是應答資訊。
請求資訊中的欄位就是我們請求中需要傳遞的欄位,應答資訊中的欄位就是App端獲取的伺服器端的應答資訊集合。

每個欄位都有修飾符,那麼修飾符是做什麼的呢?
在protobuf中定義了三種修飾符,分別為:required,optional,repeated。其中:

  • required:表示的是這個欄位必須要傳遞,不可為空;

  • optional:表示的是這個欄位可傳可不傳,可以為空;

  • repeated:表示這個欄位傳遞的是列表資料

在message的定義過程中,message還可以巢狀另外的message資訊,比如應答資訊中的UserStatus,其和java中物件的概念很類似。

(3)將proto檔案編譯成jar包
這裡就不在具體介紹怎麼講proto檔案編譯成jar了,google已經提供了相應的編譯工具。

(4)在Android程式碼中使用
由於我們將proto檔案編譯成了jar包,首先我們需要將jar引入到我們的工程,然後就可以使用了。這裡簡單看一下具體的使用程式碼。

/**
     * 請求伺服器簡訊登陸
     *
     * @param phone
     * @param code
     */
    private void requestSmsLogin(String phone, String code) {
        showProgress(false);// 顯示進度條
        LoginInterface.SmsLogin.Request.Builder request = LoginInterface.SmsLogin.Request.newBuilder();
        request.setPhone(phone); // 設定手機號
        request.setVerifyCode(code); // 設定驗證碼
        NetworkTask task = new NetworkTask(Cmd.CmdCode.SmsLogin_SSL_VALUE);
        task.setBusiData(request.build().toByteArray());
        NetworkUtils.executeNetwork(task, new HttpResponse.NetWorkResponse<UUResponseData>() {
            @Override
            public void onSuccessResponse(UUResponseData responseData) {
                if (responseData.getRet() == 0) {
                    try {
                        // 顯示通用下發訊息
                        showResponseCommonMsg(responseData.getResponseCommonMsg());
                        // 解析請求應答資訊
                        LoginInterface.SmsLogin.Response response = LoginInterface.SmsLogin.Response.parseFrom(responseData.getBusiData());
                        // 判斷是否請求成功
                        if (response.getRet() == 0) {
                            ...doSomeThing()...
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        showDefaultNetworkSnackBar();
                    }
                }
            }

            @Override
            public void onError(VolleyError errorResponse) {
                showDefaultNetworkSnackBar();
            }

            @Override
            public void networkFinish() {
                // 取消進度條顯示
                dismissProgress();
            }
        });
    }

可以發現我們在程式碼中直接有對應的登入請求message類,這樣我們就可以直接通過java類呼叫了,O(∩_∩)O哈哈~。

總結:

本文主要介紹了App開發過程中常見了三種網路傳輸協議,以及各自的優劣勢,還重點介紹了protobuf協議的使用方式等。大家在選擇的時候可以根據具體的產品需求來確定到底選擇哪一個,當然了這裡我還是比較推薦protobuf的。