1. 程式人生 > >實現PHP伺服器+Android客戶端(Retrofit+RxJava)第四天客戶端與伺服器通訊的實現

實現PHP伺服器+Android客戶端(Retrofit+RxJava)第四天客戶端與伺服器通訊的實現

我的上一篇文章已經介紹了retrofit+rxjava的配置(包括快取),從這一篇開始就開始講我要實現的這個app網路請求部分的構思,也就是要請求那些資料,資料的型別等等。

我要實現的客戶端

看圖:
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述

看了介面基本應該能知道要實現的效果了。我這裡就分塊說好了
“發現”有以下幾塊
1. 頭條
2. 文字
3. 圖片
4. 視訊
“更多”我暫時還沒想好要實現什麼效果
首先不登入也能使用發現功能,區別在於“更多”,沒有登入的使用者在“更多”的功能上應該有所區別。

頭條

先不管下拉重新整理和上拉載入更多,輪播圖的部分也先不說。首先顯示這個頁面我們就需要先載入一些資料,一次載入多少,資料的格式等是這裡需要考慮的。
看效果頁面就知道需要載入的資料包括圖片(輪播圖的圖片,每一個item的圖片),item中的文字。上面是直接就能看到的,還有我們點選輪播圖或者item之後會載入一個網頁,也就是說每一個item裡還有一個url資料。
資料就三種描述文字、圖片、url三種,該如何組合呢?我們都知道圖片的傳輸是比較消耗資源的,像淘寶是有單獨的圖片伺服器的,注意圖片也不儲存在資料庫中,用的好像是檔案的方式,就我們自己做一個app的話,就不用這麼高的要求,直接用一個伺服器就得了,但是不要把圖片存到資料庫,所以這裡我自己伺服器這邊的做法是這樣的,用一個單獨的資料夾來儲存圖片,把圖片的路徑存在資料庫中。
來說說為什麼輪播圖要單獨區分。首先分類清晰,便於擴充套件,然後載入資料的時候,不可能從同一個表中去載入輪播圖的資料和item的資料,如果載入的是同一個表的資料,那就不用搞什麼輪播圖了都和其他資料的優先順序一樣的。
做個總結,頭條頁的資料暫時是這樣的:
輪播圖

class  SlideViewItem{
long id;
String description; //點選之後跳轉去的頁面的內容的簡單描述
long time;//資料釋出時間
String picUrl; //圖片地址
String Url;//點選之後跳轉地址
}

下面的item

class  HeadlineItem{
long id;
String title;  //item標題
String description; //點選之後跳轉去的頁面的內容的簡單描述
long time;//資料釋出時間
String picUrl; //圖片地址
String Url;//點選之後跳轉地址
}

伺服器和客戶端通訊我記得一開始自己瞎搞的時候,第一個遇到的問題就是這個時間的問題,看了一些網上的文章包括公司做了一些專案後,總的感覺客戶端用long型別來表示時間,伺服器端將時間儲存為bigint還是一個不錯的選擇,用著也方便,這個long型別的時間表示的是到1970年1月1號0時到現在的毫秒數。
除了時間,還有中文亂碼也是新手常遇到的問題,這裡只要保證統一編碼就行了,比如都用utf-8,建立資料庫的時候Character set用utf-8,Collation用utf8_general_ci,再有就是php連線資料庫程式碼如下:

mysql_connect(?,?,?);
mysql_query("set names 'utf8'");
mysql_select_db(?);

就多了mysql_query(“set names ‘utf8’”);這麼一句,沒有的話插入中文會失敗,還有php程式碼最好也要儲存成utf-8格式。

文字

文字頁的資料和頭條是一模一樣的,但是為了後續的擴充套件性,也單獨寫了一個類

class  TextItem{
long id;
String title;  //item標題
String description; //點選之後跳轉去的頁面的內容的簡單描述
long time;//資料釋出時間
String picUrl; //圖片地址 String Url;//點選之後跳轉地址 }

圖片

圖片的話資料就少一些,不知道大家有沒有用過instagram(國外的app,現在使用需要翻牆),它的瀏覽圖片就是一個照片牆,圖片上也沒有文字,你點選圖片進去之後才會有一些時間、評論等等的詳細資訊。我這裡也就差不多照著做

class  PicItem{
long id;
String description; //點選之後跳轉去的頁面的內容的簡單描述
String picUrl; //圖片地址
String Url;//點選之後跳轉地址
}

視訊

視訊的話要顯示標題,以及觀看的人數,釋出時間等,具體如下:

class  VideoItem{
long id;
String description; //點選之後跳轉去的頁面的內容的簡單描述
long time;          //視訊釋出的時間
String picUrl;      //圖片地址
String Url;         //點選之後跳轉地址,也就是視訊的地址
int number;         //觀看人數
}

上面說了一些立馬要用到請求的資料型別,也就是我們的第一步已經實現了,接下來需要考慮的是一次請求,要請求多少資料,在請求不變的情況下怎麼載入最新的資料,需要知道的是對於一個使用者很多的應用,可能在1s內就有幾百萬使用者在同時上傳資料,像instagram,如果是採用簡單的按時間把所有上次請求之後的資料都載入下來,你一重新整理那就一次得載入超多資料,這是不現實的,那該如何去做這個重新整理?我這裡的做法也很簡單,每次固定載入20條,每次都加在最新資料,這是下拉重新整理,還有上拉載入更多的處理辦法也差不多,固定載入20條,按時間來載入。畢竟不太懂高大上的大資料,像百萬級的資料,等把千級的東西做出來再說,像那麼多的資料更多的應該是做分類吧!(我瞎猜的)這裡就不瞎掰了,就按上面講的簡單的方法來。
什麼是最新資料呢?這得看是怎麼存資料的,如果是靠時間來判斷是不可靠的,可能誰修改一下伺服器時間就亂了(插入資料的時候不會是根據客戶端提供的時間,有不同時區的情況,純按時間來比較的話明顯不準確),所以這裡我是靠id(資料庫id數升序自增)來判斷的,想想應該是沒什麼問題的,黑客能做的也就是冒充使用者傳送資料,光就傳送的資料只要不提供修改id的介面還不足以修改id(要是入侵了伺服器直接操作了資料庫那我就不管了!算他牛b好了吧),這樣就保證只要黑客入侵不了我們的伺服器就無法導致我們的伺服器資料出錯,當然還需要配合使用加密手段,對我們傳輸的資料進行加密,注意加密不能所有資料都加密,部分加密就行了(一般的加密演算法都會使得資料量變大)。
這裡我還想了一種保證id不會被改變得辦法,就我現在做的這個應用,所有和伺服器的通訊都是單向的,也就是隻有讀的操作,這樣的話在資料庫這邊就可以做限制,提供一個只能讀的賬號就行,如果後續添加了使用者上傳資料的功能,可以再建一個數據庫就行(其實大公司多資料庫這種做法很多,主要是為了把資料分類分清楚)。總的來說這種做法限制性還是比較大,如果要使用的話要做好規劃。

伺服器端如何傳資料

大致程式碼如下:

$sql = "select xx from xx";
$rst = mysql_query($sql);
$arr = array();
while($row=mysql_fetch_array($rst)){
$ret=new一個物件($row['屬性名']...);
$arr[]=$ret;
}
echo json_encode($arr);

上述的虛擬碼大致說一下:首先一個sql語句,隨後執行這條sql語句並宣告一個數組,迴圈取出查詢出來的資料封裝成物件放到陣列中,最後輸出這個物件陣列。伺服器端的大致實現就是這樣,具體程式碼看這裡:在這裡

客戶端如何接收資料

/**
     * 載入最新的count條資料,用於下拉重新整理和一開始載入的時候
     *
     * @param count
     * @return
     */
    @Headers("Cache-Control:max-age=640000")
    @GET("headlineitem.php")
    Observable<List<HeadlineItem>> getLatestItemInfo(@Query("count") int count);

    /**
     * 取小於這個id的count條資料,用於載入更多
     * @param count
     * @param id
     * @return
     */
    @GET("headlineitem.php")
Observable<List<HeadlineItem>> getItemInfo(@Query("count") int count,@Query("id") int id);

如何載入呢?看這裡:

Subscription s = App.getRetrofitInstance().getApiService()
                .getLatestItemInfo(AppConfig.headlineItemCount)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<List<HeadlineItem>>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable throwable) {
                        Log.d("sqqq", throwable.toString());
                    }

                    @Override
                    public void onNext(List<HeadlineItem> s) {
                        if(ifClear){
                            items.clear();
                        }
                        Log.d("sqqq",s.size()+"");
                        items.addAll(s);
                        view.refresh(false);
                    }
});

整個專案的程式碼(目前還沒有全部完成,還在持續更新中。。。上傳的也是部分):Sqq_Total