Android 巧妙封裝宏多,基于Retrofit+RxJava網(wǎng)絡(luò)框架“Leopard”---完整淺析

Leopard

《Android 巧妙封裝籍铁,基于Retrofit+RxJava網(wǎng)絡(luò)框架“Leopard”---完整淺析》

轉(zhuǎn)載請(qǐng)注明來(lái)自 傻小孩b_移動(dòng)開(kāi)發(fā)
http://www.reibang.com/users/d388bcf9c4d3
喜歡的可以關(guān)注我褂微,不定期總結(jié)文章称近!您的支持是我的動(dòng)力哈链韭!

前言

Leopard 意為獵豹特碳,在所有貓科動(dòng)物中始苇。獵豹體型最小搁拙,速度快云挟、最穩(wěn)定矫限。這也是筆者想用這個(gè)名字命名這個(gè)Kit的原因哺哼。希望這個(gè)Kit能對(duì)部分開(kāi)發(fā)者對(duì)于網(wǎng)絡(luò)框架封裝的一些思路有所幫助佩抹,筆者也在奮斗路上堅(jiān)持總結(jié)進(jìn)步中,共勉取董!最后棍苹,有任何問(wèn)題可以提issuse給我,或者直接聯(lián)系本人(QQ:708854877 傻小孩b)茵汰,喜歡可以為我點(diǎn)個(gè)star枢里,你們的支持是我最大的動(dòng)力~謝謝!

Leopard蹂午,目前實(shí)現(xiàn)功能

提供一個(gè)滿足日常需求的HTTP線程安全請(qǐng)求封裝Library栏豺,底層由Retrofit+Okhttp+RxJava支持,通過(guò)構(gòu)建者builder設(shè)計(jì)模式實(shí)現(xiàn)豆胸。目前實(shí)現(xiàn)POST奥洼、GET(支持自定義頭文件、表單鍵值對(duì)請(qǐng)求晚胡、自定義數(shù)據(jù)源等基本請(qǐng)求)灵奖、文件上傳管理(支持單文件上傳與多文件上傳,不限制文件類型)估盘、文件下載管理(支持單文件下載與多文件下載瓷患、不限制文件類型、支持大文件下載與斷點(diǎn)下載)

演示

Leopard演示.jpg

Leopard忿檩,引用方法:

注:目前只支持Android Studio版本引用尉尾。

1.1 版本 使用方法:

一、在application中的build.gradle引入:

repositories {
    maven { url = 'https://dl.bintray.com/yuancloud/maven/' }
    ...
}

compile 'cn.yuancloud.app:leopardkit:1.1'

詳情使用方法可以看kit里面的sample工程燥透,下面也會(huì)舉例使用方法沙咏。

Leopard,源碼淺析

一班套、構(gòu)建者模式

通常肢藐,大部分開(kāi)發(fā)者都會(huì)用單例模式去封裝網(wǎng)絡(luò)框架。的確吱韭,對(duì)于網(wǎng)絡(luò)請(qǐng)求嚴(yán)重消耗內(nèi)存的對(duì)象吆豹,單例模式很大程度減少了內(nèi)存開(kāi)銷啊。但是理盆,單例模式職責(zé)太單一痘煤,靈活性真的不高。所以在這里我強(qiáng)烈建議用構(gòu)建者模式猿规,需要什么資源只要通知單一職責(zé)構(gòu)建者Builder即可衷快,這樣不僅僅可以減少內(nèi)存開(kāi)銷、又可以靈活性構(gòu)建需要的對(duì)象姨俩,一舉兩得蘸拔。

二师郑、7個(gè)Factory支持

這里的Factory,包括Converter.Factory與Interceptor支持调窍。目前包括Retrofit底層已經(jīng)實(shí)現(xiàn)的GsonConverterFactory與RxJavaCallAdapterFactory宝冕,Leopard 添加了額外5個(gè)Factory,下面具體簡(jiǎn)單說(shuō)明下額外的5個(gè)Factory與Retrofit底層已經(jīng)實(shí)現(xiàn)的Factory邓萨。
(1)GsonConverterFactory
Retrofit底層支持Gson地梨,這個(gè)Factory提供當(dāng)你需要調(diào)整json里面的一些格式的時(shí)候可以使用。
(2)RxJavaCallAdapterFactory
當(dāng)你需要結(jié)合RxJava的時(shí)候先誉,而不是僅僅使用原生Retrofit請(qǐng)求響應(yīng)回調(diào)的Call湿刽。這時(shí)候你需要回調(diào)一個(gè)觀察者(Observable)的時(shí)候,必須構(gòu)造的時(shí)候添加這個(gè)Factory褐耳。
(3)RequestComFactory
默認(rèn)必須要添加的Factory诈闺,為了攔截請(qǐng)求時(shí)候的request與response。
(4)RequestJsonFactory
當(dāng)你需要向你的服務(wù)器請(qǐng)求非鍵值對(duì)铃芦,而是自定義對(duì)象轉(zhuǎn)后后的json數(shù)據(jù)的時(shí)候雅镊。必須構(gòu)造的時(shí)候添加這個(gè)Factory,底層會(huì)自動(dòng)識(shí)別幫你轉(zhuǎn)化刃滓。
(5)UploadFileFactory
顧名思義仁烹,當(dāng)你需要進(jìn)行上傳文件的時(shí)候,在構(gòu)造client的時(shí)需要添加這個(gè)Factory咧虎,底層文件類型頭信息會(huì)自動(dòng)生成卓缰。
(6)DownLoadFileFactory
顧名思義,當(dāng)你需要進(jìn)行下載文件的時(shí)候砰诵,在構(gòu)造client的時(shí)需要添加這個(gè)Factory征唬,底層會(huì)自動(dòng)根據(jù)文件類型自動(dòng)生成頭信息,默認(rèn)開(kāi)啟斷點(diǎn)續(xù)傳茁彭,下載過(guò)程可以通過(guò)DownLoadManager管理控制总寒。
(7)HeaderAddFactory
當(dāng)你需要自定義頭文件的時(shí)候,理肺,在構(gòu)造client的時(shí)需要添加這個(gè)Factory摄闸。底層會(huì)自動(dòng)幫你添加到請(qǐng)求頭。

三妹萨、關(guān)于基本請(qǐng)求

RxJava的好處年枕,可以保證線程執(zhí)行安全。由于網(wǎng)絡(luò)請(qǐng)求不能執(zhí)行在主線程乎完,因此在Leopard中熏兄,將所有網(wǎng)絡(luò)執(zhí)行都放在io線程中,確保線程執(zhí)行安全。例如以下配置:

final Observable.Transformer schedulersTransformer = new Observable.Transformer() {
    @Override
    public Object call(Object observable) {
        return ((Observable) observable)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                ;
    }
};

在Leopard中霍弹,有基本的已經(jīng)寫(xiě)好的6個(gè)入口,開(kāi)發(fā)者可以根據(jù)自己的需求去繼承自定義入口

    @POST("{path}")
    Observable<ResponseBody> post(
            @Path(value = "path", encoded = true) String path,
            @QueryMap Map<String, Object> map);

    @GET("{path}")
    Observable<ResponseBody> get(
            @Path(value = "path", encoded = true) String path,
            @QueryMap Map<String, Object> map);

    @POST("{path}")
    Observable<ResponseBody> postJSON(
            @Path(value = "path", encoded = true) String path,
            @Body RequestBody route);

    @GET("{path}")
    Observable<ResponseBody> getJSON(
            @Path(value = "path", encoded = true) String path,
            @Body RequestBody route);

    @Multipart
    @POST("{path}")
    Observable<ResponseBody> uploadFile(
            @Path(value = "path", encoded = true) String url,
            @PartMap() Map<String, RequestBody> maps);

    //支持大文件
//    @Streaming
    @GET
    Observable<ResponseBody> downloadFile(
            @Url String fileUrl);

詳細(xì)的源碼解析會(huì)在筆者博客簡(jiǎn)書(shū)分析娃弓。

四典格、關(guān)于下載

對(duì)于Leopard的下載管理模式,借鑒了Android原生DownLoadManager下載管理的模式--DownLoadManager與DownLoadTask結(jié)合的機(jī)制台丛。DownLoadTask負(fù)責(zé)單一職責(zé)耍缴,為每個(gè)下載 任務(wù)提供下載服務(wù)(緩存管理、開(kāi)始挽霉、暫停防嗡、停止等功能)。DownLoadManager作為多DownLoadTask管理者侠坎,為多任務(wù)提供所有的下載服務(wù)蚁趁。下面是下載的具體實(shí)現(xiàn)邏輯圖。

Leopard Download.png

詳細(xì)的源碼解析會(huì)在筆者博客簡(jiǎn)書(shū)分析实胸。

五他嫡、關(guān)于上傳

常規(guī)做法,上傳與鍵值對(duì)Reqtuest有類似的操作邏輯庐完。將File做為鍵值對(duì)的value钢属,將上傳File的文件信息作為key,然后向服務(wù)器進(jìn)行g(shù)et請(qǐng)求即可门躯。這里要處理的是對(duì)文件上傳進(jìn)度的監(jiān)聽(tīng)淆党,對(duì)于okhttp3底層封裝的RequestBody,并沒(méi)有對(duì)進(jìn)度字節(jié)流作為緩存處理讶凉,因此在Leopard中需要重寫(xiě)RequestBody染乌,才能對(duì)上傳緩存做處理。下面是上傳具體邏輯圖缀遍。

LeoPard UpLoad.png

詳細(xì)的源碼解析會(huì)在筆者博客簡(jiǎn)書(shū)分析慕匠。

Leopard,使用方法(自動(dòng)化構(gòu)建)

為了減少使用者使用復(fù)雜度域醇,leopard里面有集成好自動(dòng)構(gòu)建的對(duì)象台谊,采用的是單例模式。不過(guò)筆者還是推薦根據(jù)需求自定義譬挚,使用方法如下:

0.初始化
// 初始化主機(jī)域名與上下文
// 建議傳入getApplication
LeopardHttp.init("http://wxwusy.applinzi.com/leopardWeb/app/",this);
1.基本請(qǐng)求

首先在請(qǐng)求參數(shù)的時(shí)候必須定義一個(gè)model锅铅,并且繼承Leopard里面的類BaseEnetity,具體定義的model如下例子:

public class RequestPostModel extends BaseEnetity{
    @Override
    public String getRuqestURL() {
        return "sample/post.php";//你的訪問(wèn)url
    }

  //請(qǐng)求參數(shù)
    private String data;
    private String time;

    public RequestPostModel(String data, String time) {
        this.data = data;
        this.time = time;
    }

  //必須構(gòu)建get set方法
    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }

    public String getTime() {
        return time;
    }

    public void setTime(String time) {
        this.time = time;
    }
}
1.1 post與get鍵值對(duì)請(qǐng)求
1.1.1 POST
 /**
     *
     * @param type 請(qǐng)求類型减宣,具體看HttpMethod盐须,提供了四種請(qǐng)求類型
     * @param context 上下文
     * @param enetity 請(qǐng)求model
     * @param httpRespondResult 回調(diào)接口
     */
    LeopardHttp.SEND(HttpMethod.POST,getActivity(),new RequestPostModel("leopard", Utils.getNowTime()), new HttpRespondResult(getActivity()) {
            @Override
            public void onSuccess(String content) {//json
                resonseData.setText("onSuccess \n"+content);
            }

            @Override
            public void onFailure(Throwable error, String content) {
                resonseData.setText("onFailure \n"+content);
            }
        });
1.1.2 GET
 /**
     *
     * @param type 請(qǐng)求類型,具體看HttpMethod漆腌,提供了四種請(qǐng)求類型
     * @param context 上下文
     * @param enetity 請(qǐng)求model
     * @param httpRespondResult 回調(diào)接口
     */
    LeopardHttp.SEND(HttpMethod.GET,getActivity(),new RequestGetModel("leopard", Utils.getNowTime()), new HttpRespondResult(getActivity()) {
            @Override
            public void onSuccess(String content) {//json
                resonseData.setText("onSuccess \n"+content);
            }

            @Override
            public void onFailure(Throwable error, String content) {
                resonseData.setText("onFailure \n"+content);
            }
        });
1.2 post與get自定義Json對(duì)象請(qǐng)求
1.2.1 POST JSON
 /**
     *
     * @param type 請(qǐng)求類型贼邓,具體看HttpMethod阶冈,提供了四種請(qǐng)求類型
     * @param enetity 請(qǐng)求model
     * @param httpRespondResult 回調(diào)接口
     */
    LeopardHttp.SEND(HttpMethod.POST_JSON,getActivity(),new RequestPostJsonModel("leopard", Utils.getNowTime()), new HttpRespondResult(getActivity()) {
            @Override
            public void onSuccess(String content) {//json
                resonseData.setText("onSuccess \n"+content);
            }

            @Override
            public void onFailure(Throwable error, String content) {
                resonseData.setText("onFailure \n"+content);
            }
        });
1.3post與get請(qǐng)求,帶頭部

POST 帶頭部請(qǐng)求


        HashMap<String,String> headers = new HashMap<>();
        headers.put("apikey","dqwijotfpgjweigowethiuhqwqpqeqp");
        headers.put("apiSecret","ojtowejioweqwcxzcasdqweqrfrrqrqw");
        headers.put("name","leopard");

  /**
     *
     * @param type 請(qǐng)求類型塑径,具體看HttpMethod女坑,提供了四種請(qǐng)求類型
     * @param context 上下文
     * @param enetity 請(qǐng)求model
     * @param header 請(qǐng)求頭文件
     * @param httpRespondResult 回調(diào)接口
     */
        LeopardHttp.SEND(HttpMethod.POST,getActivity(),new RequestPostModel("leopard", Utils.getNowTime()),headers, new HttpRespondResult(getActivity()) {
            @Override
            public void onSuccess(String content) {
                resonseData.setText("onSuccess \n"+content);

            }

            @Override
            public void onFailure(Throwable error, String content) {
                resonseData.setText("onFailure \n"+content);
            }
        });

GET 帶頭部請(qǐng)求


        HashMap<String,String> headers = new HashMap<>();
        headers.put("apikey","dqwijotfpgjweigowethiuhqwqpqeqp");
        headers.put("apiSecret","ojtowejioweqwcxzcasdqweqrfrrqrqw");
        headers.put("name","leopard");

  /**
     *
     * @param type 請(qǐng)求類型,具體看HttpMethod统舀,提供了四種請(qǐng)求類型
     * @param context 上下文
     * @param enetity 請(qǐng)求model
     * @param header 請(qǐng)求頭文件
     * @param httpRespondResult 回調(diào)接口
     */
        LeopardHttp.SEND(HttpMethod.GET,getActivity(),new RequestPostModel("leopard", Utils.getNowTime()),headers, new HttpRespondResult(getActivity()) {
            @Override
            public void onSuccess(String content) {
                resonseData.setText("onSuccess \n"+content);

            }

            @Override
            public void onFailure(Throwable error, String content) {
                resonseData.setText("onFailure \n"+content);
            }
        });

2.上傳管理

首先在上傳的時(shí)候必須先看下上傳封裝實(shí)體類FileUploadEnetity(部分代碼)

    .....
   private String url;
    private List<File> files = new ArrayList<>();

    public FileUploadEnetity(String url, File file) {
        this.url = url;
        this.files.add(file);
        initSize();
    }

    public FileUploadEnetity(String url, List<File> files) {
        this.url = url;
        this.files = files;
        initSize();
    }
    .....

在上傳的時(shí)候匆骗,允許開(kāi)發(fā)者上傳你一個(gè)或多個(gè)文件。如果是上傳一個(gè)文件的時(shí)候誉简,構(gòu)建的時(shí)候只需要傳入上傳地址與File類型的文件碉就;反之上傳多文件,構(gòu)建的時(shí)候只需要傳入上傳地址與List<File> 類型的文件隊(duì)列類型闷串。

2.1基本上傳
 /**
     * 上傳入口
     *
     * @param FileUploadEnetity 上傳封裝實(shí)體類
     * @param IProgress 上傳進(jìn)度回調(diào)接口
     */
    LeopardHttp.UPLOAD(new FileUploadEnetity("upload.php",fileList), new IProgress() {
                    @Override
                    public void onProgress(long progress, long total, boolean done) {
                         // progress 返回當(dāng)前上傳的進(jìn)度 瓮钥,total 返回當(dāng)前上傳的總文件大小
                        if (done){
                            progressDialog.dismiss();
                            Toast.makeText(getActivity(),"所有圖片上傳成功!烹吵!",Toast.LENGTH_SHORT).show();
                        }
                    }
                });

3.下載管理

首先底層斷點(diǎn)信息數(shù)據(jù)庫(kù)存儲(chǔ)由Greendao數(shù)據(jù)庫(kù)框架支持骏庸。其次,在下載的時(shí)候必須看下實(shí)體封裝類DownloadInfo 年叮,在進(jìn)行添加下載Task的時(shí)候具被,在構(gòu)建DownloadInfo 對(duì)象的時(shí)候,至少初始化下載地址只损、存儲(chǔ)文件名一姿。例如以下代碼:

String url = "http://f1.market.xiaomi.com/download/AppStore/03f82a470d7ac44300d8700880584fe856387aac6/cn.wsy.travel.apk";
            DownloadInfo info = new DownloadInfo();
            info.setUrl(url);
            info.setFileName("IRecord_" + i + ".apk");
3.1基本下載(添加任務(wù)Task與啟動(dòng)下載)
    /**
     * 下載入口
     *
     * @param downloadInfo
     * @param iProgress
     * @return 擁有Task的下載實(shí)體
     */
   LeopardHttp.DWONLOAD(info, new IProgress() {
            @Override
            public void onProgress(long progress, long total, boolean done) {
                // progress 返回當(dāng)前上傳的進(jìn)度 ,total 返回當(dāng)前上傳的總文件大小
                //按鈕更新
                if (info.getState() == DownLoadManager.STATE_WAITING) {
                    holder.downBtn.setText("下載");
                }

                if (info.getState() == DownLoadManager.STATE_PAUSE) {
                    holder.downBtn.setText("繼續(xù)");
                }

                if (info.getState() == DownLoadManager.STATE_DOWNLOADING) {
                    holder.downBtn.setText("暫停");
                }
                if (done) {
                    //下載完成...
                }
            }
        });
3.2 DownLoadTask 單任務(wù)下載管理
3.2.1 開(kāi)始下載
// 傳入true表示從頭開(kāi)始下載
downloadInfo.getDownLoadTask().downLoad(true);
3.2.2 暫停下載
downloadInfo.getDownLoadTask().pause();
3.2.3 恢復(fù)下載
downloadInfo.getDownLoadTask().resume();
3.2.4 停止下載
downloadInfo.getDownLoadTask().stop();
3.2.5 重新下載
downloadInfo.getDownLoadTask().restart();
3.3 DownLoadManager 多任務(wù)下載管理
3.3.1 刪除所有下載任務(wù)
DownLoadManager.getManager().removeAllTask();
3.3.2 暫停所有任務(wù)
DownLoadManager.getManager().pauseAllTask();
3.3.3 停止所有任務(wù)
DownLoadManager.getManager().stopAllTask();
3.3.4 開(kāi)始所有任務(wù)
DownLoadManager.getManager().startAllTask();

Leopard跃惫,使用方法(手動(dòng)構(gòu)建)

前面封裝的單例模式LeopardHttp,是為了開(kāi)發(fā)者可以更加方便調(diào)用叮叹,自動(dòng)化構(gòu)建好了LeopardClient對(duì)象并且配置了相對(duì)應(yīng)需要的屬性。不過(guò)還是那句話爆存,為了能夠讓讀者可以更加靈活配置LeopardClient蛉顽,所以建議還是用構(gòu)建者模式構(gòu)建,可以根據(jù)需求再自定義攔截器或者自定義Factroy先较。

現(xiàn)在舉例子手動(dòng)構(gòu)建的部分代碼携冤,目前支持的功能有:

1.基本請(qǐng)求

1.1 POST與 GET 鍵值對(duì)請(qǐng)求
 LeopardClient.Builder()
                .addRequestComFactory(new RequestComFactory(respondResult))
                .addGsonConverterFactory(GsonConverterFactory.create())
                .addRxJavaCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .baseUrl(ADDRESS)
                .build()
                .GET(context, enetity, httpRespondResult);//get請(qǐng)求
             // .POST(context, enetity, httpRespondResult);//post請(qǐng)求
1.2 POST與 GET 自定義Json請(qǐng)求
 LeopardClient.Builder()
                .addRequestComFactory(new RequestComFactory(respondResult))
                .addGsonConverterFactory(GsonConverterFactory.create())
                .addRequestJsonFactory(RequestJsonFactory.create())
                .addRxJavaCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .baseUrl(ADDRESS)
                .build()
                .GET(context, enetity, httpRespondResult);//get請(qǐng)求
             // .POST(context, enetity, httpRespondResult);//post請(qǐng)求

2.下載管理

LeopardClient.Builder()
                .addRxJavaCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .addDownLoadFileFactory(DownLoadFileFactory.create(this.fileRespondResult, this.downloadInfo))
                .build()
                .downLoadFile(this.downloadInfo, callBack.fileRespondResult, downLoadTask);

3.上傳管理

 LeopardClient.Builder()
                .addRequestComFactory(new RequestComFactory(respondResult))
                .addGsonConverterFactory(GsonConverterFactory.create())
                .addRxJavaCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .baseUrl(ADDRESS)
                .addUploadFileFactory(UploadFileFactory.create())
                .build()
                .upLoadFiles(uploadEnetity,respondResult)

目前擴(kuò)展性,允許開(kāi)發(fā)者進(jìn)行繼承性擴(kuò)展的有:
1.自定義接入接口,允許開(kāi)發(fā)者根據(jù)需求接入新的接口闲勺。
繼承BaseServerApi接口即可
2.自定義擴(kuò)展Builder,允許開(kāi)發(fā)者自定義添加攔截器與Factory
繼承LeopardClient.Builder與LeopardClient即可
3.允許下載管理任務(wù)功能擴(kuò)展
允許開(kāi)發(fā)者可以擴(kuò)展下載管理任務(wù)功能曾棕,底層基本的開(kāi)始、暫停等方法不允許修改菜循。開(kāi)發(fā)者可以額外擴(kuò)展其他自定義功能翘地。

版本迭代中...

最后希望

后期我會(huì)針對(duì)基本請(qǐng)求、下載管理、上傳管理做深入分析衙耕。

希望有讀者閱讀的時(shí)候能夠看到筆者這句話:
“寫(xiě)框架的原因不在于有多少人能使用昧穿,希望是有更多人能夠參與進(jìn)來(lái),思考封裝抽象思維橙喘,提高代碼抽象編寫(xiě)能力粤咪。”

源碼地址:

Android 基于Retrofit+RxJava 封裝 Leopard 網(wǎng)絡(luò)框架-完整淺析
傻小孩b mark共勉渴杆,寫(xiě)給在成長(zhǎng)路上奮斗的你
喜歡就為我點(diǎn)下喜歡、給我個(gè)github的star吧~ 感謝各位讀者閱讀宪塔。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末磁奖,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子某筐,更是在濱河造成了極大的恐慌比搭,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件南誊,死亡現(xiàn)場(chǎng)離奇詭異身诺,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)抄囚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)霉赡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人幔托,你說(shuō)我怎么就攤上這事穴亏。” “怎么了重挑?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵嗓化,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我谬哀,道長(zhǎng)刺覆,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任史煎,我火速辦了婚禮谦屑,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘篇梭。我一直安慰自己伦仍,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布很洋。 她就那樣靜靜地躺著充蓝,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上谓苟,一...
    開(kāi)封第一講書(shū)人閱讀 51,125評(píng)論 1 297
  • 那天官脓,我揣著相機(jī)與錄音,去河邊找鬼涝焙。 笑死卑笨,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的仑撞。 我是一名探鬼主播赤兴,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼隧哮!你這毒婦竟也來(lái)了桶良?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤沮翔,失蹤者是張志新(化名)和其女友劉穎陨帆,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體采蚀,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡疲牵,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了榆鼠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纲爸。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖妆够,靈堂內(nèi)的尸體忽然破棺而出缩焦,到底是詐尸還是另有隱情,我是刑警寧澤责静,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布袁滥,位于F島的核電站,受9級(jí)特大地震影響灾螃,放射性物質(zhì)發(fā)生泄漏题翻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一腰鬼、第九天 我趴在偏房一處隱蔽的房頂上張望嵌赠。 院中可真熱鬧,春花似錦熄赡、人聲如沸姜挺。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)炊豪。三九已至凌箕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間词渤,已是汗流浹背牵舱。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留缺虐,地道東北人芜壁。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像高氮,于是被迫代替她去往敵國(guó)和親慧妄。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理剪芍,服務(wù)發(fā)現(xiàn)塞淹,斷路器,智...
    卡卡羅2017閱讀 134,651評(píng)論 18 139
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,070評(píng)論 25 707
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,803評(píng)論 6 342
  • [姑娘紊浩,你講話這么不負(fù)責(zé)任是要被踢的!] 寫(xiě)作是件異常孤獨(dú)的事兒疗锐。寫(xiě)作的人都是異常矛盾的人坊谁。寫(xiě)作的時(shí)候我們想要絕對(duì)...
    古月叨叨閱讀 560評(píng)論 7 2
  • HTML輔助器方法:負(fù)責(zé)渲染控件。將模型數(shù)據(jù)轉(zhuǎn)化為html信息滑臊。 Get請(qǐng)求:點(diǎn)擊A頁(yè)面的一個(gè)鏈接口芍,就會(huì)觸發(fā)一個(gè)由...
    余生筑閱讀 286評(píng)論 0 0