Retrofit源碼設(shè)計(jì)模式解析(下)

本文將接著《Retrofit源碼設(shè)計(jì)模式解析(上)》蹂楣,繼續(xù)分享以下設(shè)計(jì)模式在Retrofit中的應(yīng)用:

  1. 適配器模式
  2. 策略模式
  3. 觀察者模式
  4. 單例模式
  5. 原型模式
  6. 享元模式

一赏参、適配器模式

在上篇說明CallAdapter.Factory使用工廠模式時(shí)志笼,提到CallAdapter本身采用了適配器模式。適配器模式將一個(gè)接口轉(zhuǎn)換成客戶端希望的另一個(gè)接口把篓,使接口本不兼容的類可以一起工作纫溃。

Call接口是Retrofit內(nèi)置的發(fā)送請(qǐng)求給服務(wù)器并且返回響應(yīng)體的調(diào)用接口,包括同步韧掩、異步請(qǐng)求紊浩,查詢、取消疗锐、復(fù)制等功能坊谁。

public interface Call<T> extends Cloneable {
    // 同步執(zhí)行請(qǐng)求
    Response<T> execute() throws IOException;
    // 異步執(zhí)行請(qǐng)求
    void enqueue(Callback<T> callback);
    // 省略代碼

    // 取消請(qǐng)求
    void cancel();
    // 復(fù)制請(qǐng)求
    Call<T> clone();
}

而客戶端可能希望更適合業(yè)務(wù)邏輯的接口回調(diào),比如響應(yīng)式的接口回調(diào)滑臊。那么口芍,就需要對(duì)Call進(jìn)行轉(zhuǎn)換,CallAdapter就上場(chǎng)了雇卷。CallAdapter包含兩個(gè)方法:

public interface CallAdapter<T> {
    // 返回請(qǐng)求后,轉(zhuǎn)換的參數(shù)Type類型
    Type responseType();
    // 接口適配
    <R> T adapt(Call<R> call);
}

如果客戶端沒有配置CallAdapter鬓椭,Retrofit會(huì)采用默認(rèn)的實(shí)現(xiàn)DefaultCallAdapterFactory直接返回Call對(duì)象,而如果配置了RxJavaRxJavaCallAdapterFactory實(shí)現(xiàn)关划,就會(huì)將Call<R>轉(zhuǎn)換為Observable<R>小染,供客戶端調(diào)用。

static final class SimpleCallAdapter implements CallAdapter<Observable<?>> {

    // 省略代碼
    @Override 
    public <R> Observable<R> adapt(Call<R> call) {
      Observable<R> observable = Observable.create(new CallOnSubscribe<>(call))
          .lift(OperatorMapResponseToBodyOrError.<R>instance());
      if (scheduler != null) {
        return observable.subscribeOn(scheduler);
      }
      return observable;
    }
  }

總結(jié)下贮折,適配器模式包含四種角色:

  • Target:目標(biāo)抽象類
  • Adapter:適配器類
  • Adaptee:適配者類
  • Client:客戶端類

CallAdapter對(duì)應(yīng)Target裤翩,其adapt方法返回客戶端類Client需要的對(duì)象;RxJavaCallAdapterFactoryget方法返回SimpleCallAdapter對(duì)象(或ResultCallAdapter對(duì)象)實(shí)現(xiàn)了CallAdapter<Observable<?>>脱货,對(duì)應(yīng)Adapter岛都;Call<R>對(duì)應(yīng)Adaptee適配者類,包含需要被適配的方法振峻。

另外臼疫,適配器模式有對(duì)象適配器和類適配器兩種實(shí)現(xiàn)。類適配器中的Adapter需要繼承自Adaptee扣孟,對(duì)象適配則是采用復(fù)合的方式烫堤,Adapter持有Adaptee的引用。類適配器模式會(huì)使Adaptee的方法暴露給Adapter,根據(jù)“復(fù)合優(yōu)先于繼承”的思想鸽斟,推薦使用對(duì)象適配器模式拔创。

值得說明的是,這里SimpleCallAdapter并沒有通過域的方式持有Call<R>富蓄,而是直接在CallAdapterget方法中將Call<R>以入?yún)⑿问絺魅胧T铩km然并不是教科書式的對(duì)象適配器模式,但使用卻更加靈活立倍、方便灭红。

二、策略模式

完成一項(xiàng)任務(wù)口注,往往可以有多種不同的方式变擒,每一種方式稱為一個(gè)策略,我們可以根據(jù)環(huán)境或者條件的不同選擇不同的策略來完成該項(xiàng)任務(wù)寝志。針對(duì)這種情況娇斑,一種常規(guī)的做法是將多個(gè)策略寫在一個(gè)類中,通過if…else或者switch等條件判斷語句來選擇具體的算法材部。這種方式實(shí)現(xiàn)簡(jiǎn)單毫缆、快捷,但維護(hù)成本很高败富,當(dāng)添加新的策略時(shí)悔醋,需要修改源代碼,這違背了開閉原則和單一原則兽叮。仍以CallAdapter為例,不同的CallAdapter代表著不同的策略猾愿,當(dāng)我們調(diào)用這些不同的適配器的方法時(shí)鹦聪,就能得到不同的結(jié)果,這就是策略模式蒂秘。策略模式包含三種角色:

  • Context上下文環(huán)境——區(qū)別于AndroidContext泽本,這里代表操作策略的上下文;
  • Stragety抽象策略——即不同策略需要實(shí)現(xiàn)的方法姻僧;
  • ConcreteStragety策略實(shí)現(xiàn)——實(shí)現(xiàn)Stragety抽象策略规丽。

Retrofit中,配置Retrofit.Builder時(shí)addCallAdapterFactory撇贺,配置的類就對(duì)應(yīng)Context赌莺;不同的CallAdapter都需要提供adapt方法,CallAdapter<T>就對(duì)應(yīng)Stragety抽象策略松嘶。RxJavaCallAdapterFactoryget方法返回SimpleCallAdapter對(duì)象(或ResultCallAdapter對(duì)象)就對(duì)應(yīng)具體的策略實(shí)現(xiàn)艘狭。

這里可能會(huì)跟上篇中的工廠模式搞混,在說明工廠模式時(shí),主要是強(qiáng)調(diào)的是:

public abstract CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit);

通過get方法返回不同的CallAdapter對(duì)象巢音;策略模式強(qiáng)調(diào)的是這些不同CallAdapter對(duì)象的adapt方法的具體實(shí)現(xiàn)遵倦。

<R> T adapt(Call<R> call);

總結(jié)下:工廠模式強(qiáng)調(diào)的是生產(chǎn)不同的對(duì)象,策略模式強(qiáng)調(diào)的是這些不同對(duì)象的策略方法的具體實(shí)現(xiàn)官撼,是在創(chuàng)建對(duì)象之后梧躺。

三、觀察者模式

建立一種對(duì)象與對(duì)象之間的依賴關(guān)系傲绣,一個(gè)對(duì)象發(fā)生改變時(shí)將自動(dòng)通知其他對(duì)象燥狰,其他對(duì)象將相應(yīng)做出反應(yīng)。在此斜筐,發(fā)生改變的對(duì)象稱為觀察目標(biāo)龙致,而被通知的對(duì)象稱為觀察者,一個(gè)觀察目標(biāo)可以對(duì)應(yīng)多個(gè)觀察者顷链,而且這些觀察者之間沒有相互聯(lián)系目代,可以根據(jù)需要增加和刪除觀察者,使得系統(tǒng)更易于擴(kuò)展嗤练,這就是觀察者模式的模式動(dòng)機(jī)榛了。

舉個(gè)栗子:在Android編程中,常見的一種情況是界面上某個(gè)控件的狀態(tài)對(duì)其它控件有約束關(guān)系煞抬,比如霜大,需要根據(jù)某個(gè)EditText的輸入值決定某個(gè)按鈕是否可以點(diǎn)擊,就需要此EditText是可觀測(cè)的對(duì)象革答,而按鈕是EditText的觀測(cè)者战坤,當(dāng)EditText狀態(tài)發(fā)生改變時(shí),按鈕進(jìn)行相應(yīng)的操作残拐。

觀察者模式包含四種角色:

  • Subject抽象主題——也就是被觀察對(duì)象途茫,Observable是JDK中內(nèi)置的類(java.util.Observable),當(dāng)需要定義被觀察對(duì)象時(shí)溪食,繼承自Observable即可囊卜;
  • ConcreteSubject具體主題——具體被觀察者,可以繼承Observable實(shí)現(xiàn)错沃,需要通知觀察者時(shí)栅组,調(diào)用notifyObservers
  • Observer抽象觀察者——Observer也是JDK內(nèi)置的枢析,定義了update方法玉掸;
  • ConcreteObserver具體觀察者——實(shí)現(xiàn)Observer接口定義的update方法,以便在狀態(tài)發(fā)生變化時(shí)更新自己登疗。
public interface Observer {
    void update(Observable observable, Object data);
}
public class Observable {

    List<Observer> observers = new ArrayList<Observer>();

    // 省略代碼
    public void notifyObservers(Object data) {
        int size = 0;
        Observer[] arrays = null;
        synchronized (this) {
            if (hasChanged()) {
                clearChanged();
                size = observers.size();
                arrays = new Observer[size];
                observers.toArray(arrays);
            }
        }
        if (arrays != null) {
            for (Observer observer : arrays) {
                observer.update(this, data);
            }
        }
    }
}

所有與網(wǎng)絡(luò)請(qǐng)求相關(guān)的庫(kù)一定會(huì)支持請(qǐng)求的異步發(fā)送排截,通過在庫(kù)內(nèi)部維護(hù)一個(gè)隊(duì)列嫌蚤,將請(qǐng)求添加到該隊(duì)列,同時(shí)注冊(cè)一個(gè)回調(diào)接口断傲,以便執(zhí)行引擎完成該請(qǐng)求后脱吱,將請(qǐng)求結(jié)果進(jìn)行回調(diào)。Retrofit也不例外认罩,Retrofit的網(wǎng)絡(luò)請(qǐng)求執(zhí)行引擎是OkHttp箱蝠,請(qǐng)求類是OkHttpCall,其實(shí)現(xiàn)了Call接口垦垂,enqueue方法如下宦搬,入?yún)?code>Callback對(duì)象。

void enqueue(Callback<T> callback);

OkHttpCallenqueue實(shí)現(xiàn)方法中劫拗,通過在okhttp3.Callback()的回調(diào)方法中調(diào)用上述入?yún)?code>Callback對(duì)象的方法间校,實(shí)現(xiàn)通知觀察者。

@Override 
public void enqueue(final Callback<T> callback) {
    // 省略代碼
    call.enqueue(new okhttp3.Callback() {
        @Override 
        public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
          throws IOException {
            Response<T> response;
            try {
                response = parseResponse(rawResponse);
            } catch (Throwable e) {
                callFailure(e);
                return;
            }
            callSuccess(response);
        }

    @Override 
    public void onFailure(okhttp3.Call call, IOException e) {
        try {
            callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }
    private void callSuccess(Response<T> response) {
        try {
            callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
            t.printStackTrace();
        }
   }

總結(jié)下:Call接口對(duì)應(yīng)Subject页慷,定義被觀察者的特性憔足,包含enqueue等;OkHttpCall對(duì)應(yīng)ConcreteSubject具體被觀察者酒繁,Callback對(duì)應(yīng)Observer抽象觀察者滓彰,Callback的實(shí)現(xiàn)類對(duì)應(yīng)ConcreteObserver具體觀察者。

四州袒、單例模式

單例模式可能是所有設(shè)計(jì)模式教程的第一個(gè)講到的模式揭绑,也是應(yīng)用最廣泛的模式之一。Retrofit中也使用了大量的單例模式郎哭,比如BuiltInConvertersresponseBodyConverter他匪、requestBodyConverter等,并且使用了餓漢式的單例模式彰居。由于這種單例模式應(yīng)用最廣诚纸,也是大家都清楚的,本節(jié)將擴(kuò)展下單例模式的其它實(shí)現(xiàn)方式陈惰。

** 懶漢式單例模式:**

public class Singleton {

    private static Singleton instance;

    private Singleton() {
        
    }
    
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

懶漢單例模式的優(yōu)點(diǎn)是單例只要有在使用是才被實(shí)例化,缺點(diǎn)是每次調(diào)用getInstance都進(jìn)行同步毕籽,造成不必要的同步開銷抬闯。

** DCL(Double Check Lock):**

public class Singleton {

    private static Singleton instance;

    private Singleton() {

    }

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

DCL是對(duì)懶漢單例模式的升級(jí),getInstance方法對(duì)instance進(jìn)行了兩次判空关筒,第一層判斷是為了避免不必要的同步溶握,第二層判斷是為了在null時(shí)創(chuàng)建實(shí)例,這里涉及到對(duì)象實(shí)例化過程的原子問題蒸播。在Java中睡榆,創(chuàng)建對(duì)象并非原子操作萍肆,而是包含分配內(nèi)存、初始化成員字段胀屿、引用指向等一連串操作塘揣,而多線程環(huán)境下,由于指令重排序的存在宿崭,初始化指令和引用指令可能是顛倒亲铡,那么可能當(dāng)線程執(zhí)行第一個(gè)判斷不為null返回的對(duì)象,卻是未經(jīng)初始化的(別的對(duì)象創(chuàng)建Singleton時(shí)葡兑,初始化指令和引用指令顛倒了)奖蔓。

** 靜態(tài)內(nèi)部類: **

public class Singleton {

    private Singleton() {
        
    }
    
    public static Singleton getInstance() {
        return SingletonHolder.instance;
    }

    private static class SingletonHolder {
        private static final Singleton instance = new Singleton();
    }
}

上述DCL也是可能失效的,具體可參考《有關(guān)“雙重檢查鎖定失效”的說明》讹堤。采用靜態(tài)內(nèi)部類吆鹤,加載Singleton類時(shí)并不會(huì)初始化instance,同時(shí)也能保證線程安全洲守,單例對(duì)象的唯一性疑务。

** 枚舉單例:**

public enum  Singleton {

    INSTANCE;
}

枚舉實(shí)例的創(chuàng)建默認(rèn)是線程安全的,并且在任何情況下都只有一個(gè)實(shí)例岖沛。上述單例模式存在反序列化會(huì)重新創(chuàng)建對(duì)象的情況暑始,而枚舉不存在這個(gè)問題。但Android編程中婴削,因?yàn)樾阅軉栴}廊镜,不推薦使用枚舉,所以唉俗,這種比較怪異的方式并不推薦嗤朴。

** 使用容器實(shí)現(xiàn)單例模式:**

public class Singleton {

    private static Map<String, Object> objectMap = new HashMap<>();
    
    public static void addObject(String key, Object instance) {
        if (!objectMap.containsKey(key)) {
            objectMap.put(key, instance);
        }
    }
    
    public static Object getObject(String key) {
        return objectMap.get(key);
    }
}

嚴(yán)格的講,這并不是標(biāo)準(zhǔn)的單例模式虫溜,但確實(shí)實(shí)現(xiàn)了單例的效果雹姊。

單例的核心原理是將構(gòu)造函數(shù)私有化,通過靜態(tài)方法獲取唯一實(shí)例衡楞。而怎么獲取唯一實(shí)例吱雏?在Java中可能存在線程安全、反序列化等問題瘾境,因此衍生出上述這幾個(gè)版本歧杏。在實(shí)際使用時(shí)需要根據(jù)并發(fā)環(huán)境、JDK版本以及資源消耗等因素綜合考慮迷守。

五犬绒、原型模式

原型模式是一種創(chuàng)建型模式,主要用于對(duì)象復(fù)制兑凿。使用原型模式創(chuàng)建對(duì)象比直接new一個(gè)對(duì)象在性能上要好的多凯力,因?yàn)?code>Object類的clone方法是一個(gè)本地方法茵瘾,它直接操作內(nèi)存中的二進(jìn)制流。使用原型模式的另一個(gè)好處是簡(jiǎn)化對(duì)象的創(chuàng)建咐鹤,使得創(chuàng)建對(duì)象就像在編輯文檔時(shí)的復(fù)制粘貼拗秘。基于以上優(yōu)點(diǎn)慷暂,在需要重復(fù)地創(chuàng)建相似對(duì)象時(shí)可以考慮使用原型模式聘殖。比如需要在一個(gè)循環(huán)體內(nèi)創(chuàng)建對(duì)象,假如對(duì)象創(chuàng)建過程比較復(fù)雜或者循環(huán)次數(shù)很多的話行瑞,使用原型模式不但可以簡(jiǎn)化創(chuàng)建過程奸腺,而且可以使系統(tǒng)的整體性能提高很多。

原型模式有三種角色:

  • Client客戶端血久;
  • Prototype原型——一般表現(xiàn)為抽象類或者接口突照,比如JDK中的Cloneable接口;
  • ConcretePrototype具體原型類——實(shí)現(xiàn)了Prototype原型氧吐。

OkHttpCall實(shí)現(xiàn)了Call接口讹蘑,Call接口繼承自CloneableOkHttpCallclone方法實(shí)現(xiàn)如下:

@Override 
public OkHttpCall<T> clone() {
    return new OkHttpCall<>(serviceMethod, args);
}

clone的實(shí)現(xiàn)就是重新new了一個(gè)一樣的對(duì)象筑舅,用于其他地方重用相同的Call座慰,在ExecutorCallbackCall中有用到:

static final class ExecutorCallbackCall<T> implements Call<T> {
    // 省略代碼
    @SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.
    @Override 
    public Call<T> clone() {
        return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());
    }
}

使用原型模式復(fù)制對(duì)象需要主要深拷貝與淺拷貝的問題。Object類的clone方法只會(huì)拷貝對(duì)象中的基本的數(shù)據(jù)類型翠拣,對(duì)于數(shù)組版仔、容器對(duì)象、引用對(duì)象等都不會(huì)拷貝误墓,這就是淺拷貝蛮粮。如果要實(shí)現(xiàn)深拷貝,必須將原型模式中的數(shù)組谜慌、容器對(duì)象然想、引用對(duì)象等另行拷貝。

六欣范、享元模式

享元模式是對(duì)象池的一種實(shí)現(xiàn)变泄,運(yùn)用共享技術(shù)有效地支持大量細(xì)粒度對(duì)象的復(fù)用。系統(tǒng)只使用少量的對(duì)象恼琼,而這些對(duì)象都很相似杖刷,狀態(tài)變化很小,可以實(shí)現(xiàn)對(duì)象的多次復(fù)用驳癌。由于享元模式要求能夠共享的對(duì)象必須是細(xì)粒度對(duì)象,因此它又稱為輕量級(jí)模式(Flyweight)役听,它是一種對(duì)象結(jié)構(gòu)型模式颓鲜。

享元模式包含三種角色:

  • Flyweight享元基類或接口表窘;
  • ConcreteFlyweight具體的享元對(duì)象;
  • FlyweightFactory享元工廠——負(fù)責(zé)管理享元對(duì)象池和創(chuàng)建享元對(duì)象甜滨。

Retrofitcreate方法創(chuàng)建ServiceMethod是通過loadServiceMethod方法實(shí)現(xiàn)乐严。loadServiceMethod方法就實(shí)現(xiàn)了享元模式。

private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();

ServiceMethod loadServiceMethod(Method method) {
    ServiceMethod result;
    synchronized (serviceMethodCache) {
        result = serviceMethodCache.get(method);
        if (result == null) {
            result = new ServiceMethod.Builder(this, method).build();
            serviceMethodCache.put(method, result);
        }
    }
    return result;
}

上篇講到代理模式的時(shí)候衣摩,提到了這個(gè)方法的緩存使用了LinkedHashMap昂验,系統(tǒng)中的Method接口數(shù)相對(duì)于請(qǐng)求次數(shù)是有數(shù)量級(jí)差距的,把這些接口的信息緩存起來是非常有必要的一個(gè)優(yōu)化手段艾扮,這樣的實(shí)現(xiàn)方式就是享元模式既琴。

在享元模式中共享的是享元對(duì)象的內(nèi)部狀態(tài),外部狀態(tài)需要通過環(huán)境來設(shè)置泡嘴。在實(shí)際使用中甫恩,能夠共享的內(nèi)部狀態(tài)是有限的,因此享元對(duì)象一般都設(shè)計(jì)為較小的對(duì)象酌予,它所包含的內(nèi)部狀態(tài)較少磺箕,這種對(duì)象也稱為細(xì)粒度對(duì)象。享元模式的目的就是使用共享技術(shù)來實(shí)現(xiàn)大量細(xì)粒度對(duì)象的復(fù)用抛虫。在經(jīng)典享元模式中松靡,它的鍵是享元對(duì)象的內(nèi)部狀態(tài),它的值就是享元對(duì)象本身建椰。上述serviceMethodCachekeymethod雕欺,valueServiceMethodmethod就是ServiceMethod的內(nèi)部狀態(tài)广凸。

總結(jié):Retrofit不愧是大師之作阅茶,設(shè)計(jì)模式的經(jīng)典教程。其源碼量并不大谅海,但系統(tǒng)的可擴(kuò)展性脸哀、可維護(hù)性極強(qiáng),是客戶端架構(gòu)設(shè)計(jì)的典范扭吁,非常值得學(xué)習(xí)撞蜂,五星推薦!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末侥袜,一起剝皮案震驚了整個(gè)濱河市蝌诡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌枫吧,老刑警劉巖浦旱,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異九杂,居然都是意外死亡颁湖,警方通過查閱死者的電腦和手機(jī)宣蠕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來甥捺,“玉大人抢蚀,你說我怎么就攤上這事×蹋” “怎么了皿曲?”我有些...
    開封第一講書人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)吴侦。 經(jīng)常有香客問我屋休,道長(zhǎng),這世上最難降的妖魔是什么妈倔? 我笑而不...
    開封第一講書人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任博投,我火速辦了婚禮,結(jié)果婚禮上盯蝴,老公的妹妹穿的比我還像新娘毅哗。我一直安慰自己,他們只是感情好捧挺,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開白布虑绵。 她就那樣靜靜地躺著,像睡著了一般闽烙。 火紅的嫁衣襯著肌膚如雪翅睛。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,046評(píng)論 1 285
  • 那天黑竞,我揣著相機(jī)與錄音捕发,去河邊找鬼。 笑死很魂,一個(gè)胖子當(dāng)著我的面吹牛扎酷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播遏匆,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼法挨,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了幅聘?” 一聲冷哼從身側(cè)響起凡纳,我...
    開封第一講書人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎帝蒿,沒想到半個(gè)月后荐糜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了批狐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖拨扶,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情焊唬,我是刑警寧澤坟岔,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站独令,受9級(jí)特大地震影響端朵,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜燃箭,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一冲呢、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧招狸,春花似錦敬拓、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至累榜,卻和暖如春营勤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背壹罚。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工葛作, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人猖凛。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓赂蠢,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親形病。 傳聞我的和親對(duì)象是個(gè)殘疾皇子客年,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,510評(píng)論 25 707
  • 簡(jiǎn)介 剛接觸Retrofit的時(shí)候,就寫了一篇簡(jiǎn)單的使用介紹:Retrofit 2.0基本使用方法,算是對(duì)Retr...
    Whyn閱讀 2,835評(píng)論 4 24
  • Retrofit通過注解的方法標(biāo)記HTTP請(qǐng)求參數(shù)漠吻,支持常用HTTP方法量瓜,統(tǒng)一返回值解析,支持異步/同步的請(qǐng)求方式...
    yhthu閱讀 1,155評(píng)論 1 15
  • 自己第一次接觸到比特幣的具體時(shí)間,已經(jīng)不記得了。只記得烫饼,大概是在三猎塞、四年前。 當(dāng)時(shí)的自己杠纵,一定是在圖書館看書的時(shí)候...
    孫小鑫的心閱讀 513評(píng)論 3 7
  • 簡(jiǎn)書,交流故事银亲,溝通想法慢叨! 一直在關(guān)注,從未發(fā)表過…… 話說务蝠,文章需要一個(gè)好的主題拍谐,然后一個(gè)好的開頭。 主題馏段? 沒...
    方知甬閱讀 215評(píng)論 0 1