ARouter路由框架解析

一酒甸、ARouter介紹及主要應(yīng)用場(chǎng)景:

1礁叔、介紹:

是ARouter是阿里巴巴開(kāi)源的Android平臺(tái)中對(duì)頁(yè)面、服務(wù)提供路由功能的中間件泼菌,提倡的是簡(jiǎn)單且夠用谍肤。

2、原生的路由方案存在的問(wèn)題

首先談一談原生的路由方案存在的問(wèn)題以及為什么需要路由框架哗伯。我們所使用的原生路由方案一般是通過(guò)顯式intent和隱式intent兩種方式實(shí)現(xiàn)的超升,而在顯式intent的情況下捷沸,因?yàn)闀?huì)存在直接的類(lèi)依賴(lài)的問(wèn)題盛卡,導(dǎo)致耦合非常嚴(yán)重新症;而在隱式intent情況下,則會(huì)出現(xiàn)規(guī)則集中式管理虐块,導(dǎo)致協(xié)作變得非常困難俩滥。而且一般而言配置規(guī)則都是在Manifest中的,這就導(dǎo)致了擴(kuò)展性較差贺奠。除此之外举农,使用原生的路由方案會(huì)出現(xiàn)跳轉(zhuǎn)過(guò)程無(wú)法控制的問(wèn)題,因?yàn)橐坏┦褂昧薙tartActivity()就無(wú)法插手其中任何環(huán)節(jié)了敞嗡,只能交給系統(tǒng)管理颁糟,這就導(dǎo)致了在跳轉(zhuǎn)失敗的情況下無(wú)法降級(jí)航背,而是會(huì)直接拋出運(yùn)營(yíng)級(jí)的異常。


image.png

這時(shí)候如果考慮使用自定義的路由組件就可以解決以上的一些問(wèn)題棱貌,比如通過(guò)URL索引就可以解決類(lèi)依賴(lài)的問(wèn)題玖媚;通過(guò)分布式管理頁(yè)面配置可以解決隱式intent中集中式管理Path的問(wèn)題;自己實(shí)現(xiàn)整個(gè)路由過(guò)程也可以擁有良好的擴(kuò)展性婚脱,還可以通過(guò)AOP的方式解決跳轉(zhuǎn)過(guò)程無(wú)法控制的問(wèn)題今魔,與此同時(shí)也能夠提供非常靈活的降級(jí)方式。

3障贸、為什么要用路由組件

為什么要用路由組件
前面提到的主要是開(kāi)發(fā)與協(xié)作中的問(wèn)題错森,而使用一款路由框架時(shí)還會(huì)涉及到其他的兩個(gè)大方面:一方面是組件化,而另一方面就是Native和H5的問(wèn)題篮洁。剛才所提到的主要是開(kāi)發(fā)和協(xié)作中作為開(kāi)發(fā)者所需要面對(duì)的問(wèn)題涩维,而一旦一款A(yù)PP達(dá)到一定體量的時(shí)候,業(yè)務(wù)就會(huì)膨脹得比較嚴(yán)重袁波,而開(kāi)發(fā)團(tuán)隊(duì)的規(guī)模也會(huì)越來(lái)越大瓦阐,這時(shí)候一般都會(huì)提出組件化的概念。組件化就是將APP按照一定的功能和業(yè)務(wù)拆分成多個(gè)小組件篷牌,不同的組件由不同的開(kāi)發(fā)小組來(lái)負(fù)責(zé)睡蟋,這樣就可以解決大型APP開(kāi)發(fā)過(guò)程中的開(kāi)發(fā)與協(xié)作的問(wèn)題,將這些問(wèn)題分散到小的APP中枷颊。目前而言組件化已經(jīng)有非常多比較成熟的方案了戳杀,而自定義路由框架也可以非常好地解決整個(gè)APP完成組件化之后模塊之間沒(méi)有耦合的問(wèn)題,因?yàn)闆](méi)有耦合時(shí)使用原生的路由方案肯定是不可以的夭苗。


image.png

另外一個(gè)問(wèn)題就是Native與H5的問(wèn)題豺瘤,因?yàn)楝F(xiàn)在的APP很少是純Native的,也很少會(huì)有純H5的听诸,一般情況下都是將兩者進(jìn)行結(jié)合。這時(shí)候就需要非常便捷并且統(tǒng)一的跳轉(zhuǎn)方案蚕泽,因?yàn)樵贖5中是無(wú)法使用StartActivity()跳轉(zhuǎn)到Native頁(yè)面的晌梨,而從Native跳轉(zhuǎn)到H5頁(yè)面也只能通過(guò)配置瀏覽器的方式實(shí)現(xiàn)。

4须妻、路由框架的特點(diǎn)

為了解決以上的問(wèn)題就需要實(shí)現(xiàn)一個(gè)自定義的路由框架仔蝌,而路由框架一般都具有以下的三種特點(diǎn):
分發(fā):把一個(gè)URL或者請(qǐng)求按照一定的規(guī)則分配給一個(gè)服務(wù)或者頁(yè)面來(lái)處理,這個(gè)流程就是分發(fā)荒吏,分發(fā)是路由框架最基本的功能敛惊,當(dāng)然也可以理解成為簡(jiǎn)單的跳轉(zhuǎn)。
管理:將組件和頁(yè)面按照一定的規(guī)則管理起來(lái)绰更,在分發(fā)的時(shí)候提供搜索瞧挤、加載锡宋、修改等操作,這部分就是管理特恬,也是路由框架的基礎(chǔ)执俩,上層功能都是建立在管理之上。
控制:就像路由器一樣癌刽,路由的過(guò)程中役首,會(huì)有限速、屏蔽等一些控制操作显拜,路由框架也需要在路由的過(guò)程中衡奥,對(duì)路由操作做一些定制性的擴(kuò)展,比方剛才提到的AOP远荠,后期的功能更新矮固,也是圍繞這個(gè)部分來(lái)做的。

5矮台、ARouter的7個(gè)優(yōu)勢(shì)

image.png

優(yōu)勢(shì)一:直接解析URL路由乏屯,解析參數(shù)并賦值到對(duì)應(yīng)目標(biāo)字段的頁(yè)面中。
優(yōu)勢(shì)二:支持多模塊項(xiàng)目瘦赫,因?yàn)楝F(xiàn)在很少有APP是單模塊的項(xiàng)目辰晕,一般都是多模塊單工程的,由不同的團(tuán)隊(duì)負(fù)責(zé)不同的模塊開(kāi)發(fā)确虱,這時(shí)候支持多模塊項(xiàng)目開(kāi)發(fā)就顯得尤為重要含友。
優(yōu)勢(shì)三:支持InstantRun,目前很多路由框架并不支持InstantRun校辩,而InstantRun是Google在AndroidStudio2.0阿爾法版本中提供的新功能窘问,其類(lèi)似于代碼的日更新,其只不過(guò)面向的是開(kāi)發(fā)過(guò)程宜咒,這樣做可以在開(kāi)發(fā)的過(guò)程中減少開(kāi)發(fā)和編譯的次數(shù)惠赫,可以簡(jiǎn)單地將代碼修改即時(shí)地同步到APK中,從而可以大規(guī)模降低開(kāi)發(fā)復(fù)雜度故黑。
優(yōu)勢(shì)四:允許自定義攔截器儿咱,ARouter是支持?jǐn)r截器的,而攔截器其實(shí)就是AOP的實(shí)現(xiàn)场晶,可以自定義多個(gè)攔截器解決一些面向行為編程上出現(xiàn)的問(wèn)題混埠。
優(yōu)勢(shì)五:ARouter可以提供IoC容器,IoC其實(shí)就是控制反轉(zhuǎn)诗轻,這一部分做過(guò)服務(wù)端開(kāi)發(fā)的朋友可能比較了解钳宪,因?yàn)榉?wù)端開(kāi)發(fā)經(jīng)常用到的Spring框架能夠提供的一個(gè)非常重要的能力就是控制反轉(zhuǎn)。
優(yōu)勢(shì)六:映射關(guān)系自動(dòng)注冊(cè),在頁(yè)面不是很多的小型APP上面吏颖,自動(dòng)注冊(cè)并不會(huì)體現(xiàn)出太大優(yōu)勢(shì)搔体,但是對(duì)于大型APP而言,可能頁(yè)面數(shù)量已經(jīng)達(dá)到的幾十個(gè)或者數(shù)百個(gè)侦高,在這樣的情況下嫉柴,自動(dòng)注冊(cè)就顯得非常重要了,因?yàn)椴豢赡軐⒚恳粋€(gè)頁(yè)面都通過(guò)代碼的方式進(jìn)行注冊(cè)奉呛。
優(yōu)勢(shì)七:靈活的降級(jí)策略计螺,ARouter可以提供很多種降級(jí)策略供用戶(hù)自行選擇,而原生的路由方案存在無(wú)法靈活降級(jí)的問(wèn)題瞧壮,StartActivity()一旦失敗將會(huì)拋出運(yùn)營(yíng)級(jí)異常登馒。

6、應(yīng)用場(chǎng)景:
  • 從外部URL映射到內(nèi)部頁(yè)面咆槽,以及參數(shù)傳遞與解析
  • 跨模塊頁(yè)面跳轉(zhuǎn)陈轿,模塊間解耦
  • 攔截跳轉(zhuǎn)過(guò)程,處理登陸秦忿、埋點(diǎn)等邏輯
  • 跨模塊API調(diào)用麦射,通過(guò)控制反轉(zhuǎn)來(lái)做組件解耦
    GitHub:https://github.com/alibaba/ARouter

二、ARouter的基本使用步驟:

1灯谣、添加依賴(lài)和配置
android {
    defaultConfig {
    ...
    javaCompileOptions {
        annotationProcessorOptions {
        arguments = [ moduleName : project.getName() ]
        }
    }
    }
}

dependencies {
    // 替換成最新版本, 需要注意的是api
    // 要與compiler匹配使用潜秋,均使用最新版可以保證兼容
    compile 'com.alibaba:arouter-api:x.x.x'
    annotationProcessor 'com.alibaba:arouter-compiler:x.x.x'
    ...
}
// 替換成最新版本, 需要注意的是api
// 要與compiler匹配使用,均使用最新版可以保證兼容
compile 'com.alibaba:arouter-api:x.x.x'
annotationProcessor 'com.alibaba:arouter-compiler:x.x.x'
  • 這里替換相應(yīng)的Api和compiler


2胎许、添加注解及初始化
  • ARouter初始化
if (isDebug()) {           // 這兩行必須寫(xiě)在init之前峻呛,否則這些配置在init過(guò)程中將無(wú)效
    ARouter.openLog();     // 打印日志
    ARouter.openDebug();   // 開(kāi)啟調(diào)試模式(如果在InstantRun模式下運(yùn)行,必須開(kāi)啟調(diào)試模式辜窑!線上版本需要關(guān)閉,否則有安全風(fēng)險(xiǎn))
}
ARouter.init(mApplication); // 盡可能早钩述,推薦在Application中初始化
  • 在需要跳轉(zhuǎn)的Activity上進(jìn)行注解配置
// 在支持路由的頁(yè)面上添加注解(必選)
// 這里的路徑需要注意的是至少需要有兩級(jí),/xx/xx
@Route(path = "/com/ARouter2Activity")
public class ARouter2Activity extends AppCompatActivity {
      super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_arouter2);
    //....
}
  • 應(yīng)用中的簡(jiǎn)單跳轉(zhuǎn)
 ARouter.getInstance().build("/com/ARouter2Activity").navigation();
  • 應(yīng)用中攜帶參數(shù)的跳轉(zhuǎn)
ARouter.getInstance().build("/com/ARouter2Activity")
                        .withString("name","onex")
                        .withInt("age",22)
                        .navigation();
  • 在目標(biāo)Activity中接受相關(guān)的參數(shù)
    為每一個(gè)參數(shù)聲明一個(gè)字段穆碎,并使用 @Autowired 標(biāo)注
    URL中不能傳遞Parcelable類(lèi)型數(shù)據(jù)牙勘,通過(guò)ARouter api可以傳遞
Parcelable對(duì)象
@Route(path = "/com/ARouter2Activity")
public class ARouter2Activityextends Activity {
    @Autowired
    public String name;
    @Autowired
    int age;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    ARouter.getInstance().inject(this);

    // ARouter會(huì)自動(dòng)對(duì)字段進(jìn)行賦值,無(wú)需主動(dòng)獲取
    Log.d("param", name + age + boy);
    }
}

這里需要注意的是

 ARouter.getInstance().inject(this); 

三所禀、進(jìn)階使用

1方面、Activity之間傳遞自定義對(duì)象
  • 如果需要傳遞自定義對(duì)象,需要實(shí)現(xiàn) SerializationService,并使用@Route注解標(biāo)注(方便用戶(hù)自行選擇序列化方式)
@Route(path = "/service/json")
public class JsonServiceImpl implements SerializationService {
    @Override
    public void init(Context context) {

    }

    @Override
    public <T> T json2Object(String text, Class<T> clazz) {
        return JSON.parseObject(text, clazz);
    }

    @Override
    public String object2Json(Object instance) {
        return JSON.toJSONString(instance);
    }
}
  • 以下是ARouter支持的傳遞的數(shù)據(jù)類(lèi)型
                TestParcelable testParcelable = new TestParcelable("jack", 666);
                TestObj testObj = new TestObj("Rose", 777);
                List<TestObj> objList = new ArrayList<>();
                objList.add(testObj);

                Map<String, List<TestObj>> map = new HashMap<>();
                map.put("testMap", objList);

                ARouter.getInstance().build("/test/activity1")
                        .withString("name", "老王")
                        .withInt("age", 18)
                        .withBoolean("boy", true)
                        .withLong("high", 180)
                        .withString("url", "https://a.b.c")
                        .withParcelable("pac", testParcelable)
                        .withObject("obj", testObj)
                        .withObject("objList", objList)
                        .withObject("map", map)
                        .navigation();

需要注意的是:我們?cè)趥鬟f的時(shí)候使用的是什么樣的KEY,在目標(biāo)Activity的地方使用相同的KEY,進(jìn)行聲明變量例如:

Man man = new Man("OneX","男");
ARouter.getInstance().build("/com/ARouter2Activity")
       .withObject("obj",man)
       .navigation();

目標(biāo)頁(yè)面Code

    @Autowired
    Man obj;
2北秽、通過(guò)Url進(jìn)行跳轉(zhuǎn)
  • 新建一個(gè)Activity用于監(jiān)聽(tīng)Schame事件,之后直接把url傳遞給ARouter即可(類(lèi)似于轉(zhuǎn)發(fā)路由的Activity)
public class SchameFilterActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    Uri uri = getIntent().getData();
    ARouter.getInstance().build(uri).navigation();
    finish();
    }
}

在AndroidManifest.xml中進(jìn)行如下配置

<activity android:name=".activity.SchameFilterActivity">
    <!-- Schame -->
    <intent-filter>
        <data
        android:host="m.aliyun.com"
        android:scheme="arouter"/>

        <action android:name="android.intent.action.VIEW"/>

        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
    </intent-filter>
</activity>
3、設(shè)置攔截器
  • 比較經(jīng)典的應(yīng)用就是在跳轉(zhuǎn)過(guò)程中處理登陸事件最筒,這樣就不需要在目標(biāo)頁(yè)重復(fù)做登陸檢攔截器會(huì)在跳轉(zhuǎn)之間執(zhí)行
  • 多個(gè)攔截器會(huì)按優(yōu)先級(jí)順序依次執(zhí)行
@Interceptor(priority = 8, name = "測(cè)試用攔截器")
public class TestInterceptor implements IInterceptor {
    @Override
    public void process(Postcard postcard, InterceptorCallback callback) {
    ...
    callback.onContinue(postcard);  // 處理完成贺氓,交還控制權(quán)
    // callback.onInterrupt(new RuntimeException("我覺(jué)得有點(diǎn)異常"));      // 覺(jué)得有問(wèn)題,中斷路由流程

    // 以上兩種至少需要調(diào)用其中一種,否則不會(huì)繼續(xù)路由
    }

    @Override
    public void init(Context context) {
    // 攔截器的初始化辙培,會(huì)在sdk初始化的時(shí)候調(diào)用該方法蔑水,僅會(huì)調(diào)用一次
    }
}
4、監(jiān)聽(tīng)路由跳轉(zhuǎn)結(jié)果
// 使用兩個(gè)參數(shù)的navigation方法扬蕊,可以獲取單次跳轉(zhuǎn)的結(jié)果
ARouter.getInstance().build("/test/1").navigation(this, new NavigationCallback() {
    @Override
    public void onFound(Postcard postcard) {
      ...
    }

    @Override
    public void onLost(Postcard postcard) {
    ...
    }
});
5搀别、獲取Fragment的對(duì)象
// 獲取Fragment
Fragment fragment = (Fragment) ARouter.getInstance().build("/test/fragment").navigation();
6、通過(guò)依賴(lài)注入解耦:服務(wù)管理尾抑,暴露服務(wù)
// 聲明接口,其他組件通過(guò)接口來(lái)調(diào)用服務(wù)
public interface HelloService extends IProvider {
    String sayHello(String name);
}

// 實(shí)現(xiàn)接口
@Route(path = "/service/hello", name = "測(cè)試服務(wù)")
public class HelloServiceImpl implements HelloService {

    @Override
    public String sayHello(String name) {
    return "hello, " + name;
    }

    @Override
    public void init(Context context) {

    }
}

在Class中的相關(guān)使用

public class Test {
    @Autowired
    HelloService helloService;

    @Autowired(name = "/service/hello")
    HelloService helloService2;

    HelloService helloService3;

    HelloService helloService4;

    public Test() {
    ARouter.getInstance().inject(this);
    }

    public void testService() {
     // 1. (推薦)使用依賴(lài)注入的方式發(fā)現(xiàn)服務(wù),通過(guò)注解標(biāo)注字段,即可使用歇父,無(wú)需主動(dòng)獲取
     // Autowired注解中標(biāo)注name之后,將會(huì)使用byName的方式注入對(duì)應(yīng)的字段再愈,不設(shè)置name屬性榜苫,會(huì)默認(rèn)使用byType的方式發(fā)現(xiàn)服務(wù)(當(dāng)同一接口有多個(gè)實(shí)現(xiàn)的時(shí)候,必須使用byName的方式發(fā)現(xiàn)服務(wù))
    helloService.sayHello("Vergil");
    helloService2.sayHello("Vergil");

    // 2. 使用依賴(lài)查找的方式發(fā)現(xiàn)服務(wù)翎冲,主動(dòng)去發(fā)現(xiàn)服務(wù)并使用垂睬,下面兩種方式分別是byName和byType
    helloService3 = ARouter.getInstance().navigation(HelloService.class);
    helloService4 = (HelloService) ARouter.getInstance().build("/service/hello").navigation();
    helloService3.sayHello("Vergil");
    helloService4.sayHello("Vergil");
    }
}

四、注意事項(xiàng)及混淆配置

1抗悍、初始化中的其他配置
ARouter.openLog(); // 開(kāi)啟日志
ARouter.openDebug(); // 使用InstantRun的時(shí)候驹饺,需要打開(kāi)該開(kāi)關(guān),上線之后關(guān)閉缴渊,否則有安全風(fēng)險(xiǎn)
ARouter.printStackTrace(); // 打印日志的時(shí)候打印線程堆棧
2赏壹、詳細(xì)API:
// 構(gòu)建標(biāo)準(zhǔn)的路由請(qǐng)求
ARouter.getInstance().build("/home/main").navigation();

// 構(gòu)建標(biāo)準(zhǔn)的路由請(qǐng)求,并指定分組
ARouter.getInstance().build("/home/main", "ap").navigation();

// 構(gòu)建標(biāo)準(zhǔn)的路由請(qǐng)求疟暖,通過(guò)Uri直接解析
Uri uri;
ARouter.getInstance().build(uri).navigation();

// 構(gòu)建標(biāo)準(zhǔn)的路由請(qǐng)求卡儒,startActivityForResult
// navigation的第一個(gè)參數(shù)必須是Activity,第二個(gè)參數(shù)則是RequestCode
ARouter.getInstance().build("/home/main", "ap").navigation(this, 5);

// 直接傳遞Bundle
Bundle params = new Bundle();
ARouter.getInstance()
    .build("/home/main")
    .with(params)
    .navigation();

// 指定Flag
ARouter.getInstance()
    .build("/home/main")
    .withFlags();
    .navigation();

// 獲取Fragment
Fragment fragment = (Fragment) ARouter.getInstance().build("/test/fragment").navigation();
                    
// 對(duì)象傳遞
ARouter.getInstance()
    .withObject("key", new TestObj("Jack", "Rose"))
    .navigation();

// 覺(jué)得接口不夠多俐巴,可以直接拿出Bundle賦值
ARouter.getInstance()
        .build("/home/main")
        .getExtra();

// 轉(zhuǎn)場(chǎng)動(dòng)畫(huà)(常規(guī)方式)
ARouter.getInstance()
    .build("/test/activity2")
    .withTransition(R.anim.slide_in_bottom, R.anim.slide_out_bottom)
    .navigation(this);

// 轉(zhuǎn)場(chǎng)動(dòng)畫(huà)(API16+)
ActivityOptionsCompat compat = ActivityOptionsCompat.
    makeScaleUpAnimation(v, v.getWidth() / 2, v.getHeight() / 2, 0, 0);

// ps. makeSceneTransitionAnimation 使用共享元素的時(shí)候骨望,需要在navigation方法中傳入當(dāng)前Activity

ARouter.getInstance()
    .build("/test/activity2")
    .withOptionsCompat(compat)
    .navigation();
        
// 使用綠色通道(跳過(guò)所有的攔截器)
ARouter.getInstance().build("/home/main").greenChannel().navigation();

// 使用自己的日志工具打印日志
ARouter.setLogger();
3、路由中的分組概念
  • SDK中針對(duì)所有的路徑(/test/1 /test/2)進(jìn)行分組欣舵,分組只有在分組中的某一個(gè)路徑第一次被訪問(wèn)的時(shí)候擎鸠,該分組才會(huì)被初始化
  • 通過(guò) @Route 注解主動(dòng)指定分組,否則使用路徑中第一段字符串(/*/)作為分組
  • 注意:一旦主動(dòng)指定分組之后缘圈,應(yīng)用內(nèi)路由需要使用 ARouter.getInstance().build(path, group) 進(jìn)行跳轉(zhuǎn)劣光,手動(dòng)指定分組,否則無(wú)法找到
@Route(path = "/test/1", group = "app")
4糟把、添加混淆規(guī)則(如果使用了Proguard)
-keep public class com.alibaba.android.arouter.routes.**{*;}
-keep class * implements com.alibaba.android.arouter.facade.template.ISyringe{*;}

# 如果使用了 byType 的方式獲取 Service绢涡,需添加下面規(guī)則,保護(hù)接口
-keep interface * implements com.alibaba.android.arouter.facade.template.IProvider

# 如果使用了 單類(lèi)注入遣疯,即不定義接口實(shí)現(xiàn) IProvider雄可,需添加下面規(guī)則,保護(hù)實(shí)現(xiàn)
-keep class * implements com.alibaba.android.arouter.facade.template.IProvider

本文以上部分內(nèi)容參考:https://yq.aliyun.com/articles/71687?spm=5176.100240.searchblog.7.5qkuq2

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市数苫,隨后出現(xiàn)的幾起案子聪舒,更是在濱河造成了極大的恐慌,老刑警劉巖虐急,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件箱残,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡止吁,警方通過(guò)查閱死者的電腦和手機(jī)被辑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)赏殃,“玉大人敷待,你說(shuō)我怎么就攤上這事∪嗜龋” “怎么了榜揖?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)抗蠢。 經(jīng)常有香客問(wèn)我举哟,道長(zhǎng),這世上最難降的妖魔是什么迅矛? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任妨猩,我火速辦了婚禮,結(jié)果婚禮上秽褒,老公的妹妹穿的比我還像新娘壶硅。我一直安慰自己,他們只是感情好销斟,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布庐椒。 她就那樣靜靜地躺著,像睡著了一般蚂踊。 火紅的嫁衣襯著肌膚如雪约谈。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,698評(píng)論 1 305
  • 那天犁钟,我揣著相機(jī)與錄音棱诱,去河邊找鬼。 笑死涝动,一個(gè)胖子當(dāng)著我的面吹牛迈勋,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播醋粟,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼靡菇,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼担败!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起镰官,我...
    開(kāi)封第一講書(shū)人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎吗货,沒(méi)想到半個(gè)月后泳唠,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡宙搬,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年笨腥,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片勇垛。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡脖母,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出闲孤,到底是詐尸還是另有隱情谆级,我是刑警寧澤,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布讼积,位于F島的核電站肥照,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏勤众。R本人自食惡果不足惜舆绎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望们颜。 院中可真熱鬧吕朵,春花似錦、人聲如沸窥突。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)波岛。三九已至茅坛,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間则拷,已是汗流浹背贡蓖。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留煌茬,地道東北人斥铺。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像坛善,于是被迫代替她去往敵國(guó)和親晾蜘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子邻眷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355

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

  • 組件化 模塊化、組件化與插件化 在項(xiàng)目發(fā)展到一定程度剔交,隨著人員的增多肆饶,代碼越來(lái)越臃腫,這時(shí)候就必須進(jìn)行模塊化的拆分...
    silentleaf閱讀 4,953評(píng)論 2 12
  • 開(kāi)發(fā)一款A(yù)pp岖常,總會(huì)遇到各種各樣的需求和業(yè)務(wù)驯镊,這時(shí)候選擇一個(gè)簡(jiǎn)單好用的輪子,就可以事半功倍 前言 上面一段代碼竭鞍,在...
    WangDeFa閱讀 65,767評(píng)論 44 198
  • 我曾經(jīng)遇見(jiàn)過(guò)一個(gè)薄荷味少年板惑,他的名字叫木木。他有著干凈的眉眼偎快,說(shuō)起話的時(shí)候眼睛里有閃爍的光茫冯乘。 木木總是穿...
    流星度微閱讀 838評(píng)論 2 0
  • 今天早上,下起了小雨晒夹,9點(diǎn)多出去時(shí)裆馒,地面上還是濕漉漉的,令人有些陰郁丐怯,加班這么久领追,終于可以出去散散心,感受下城市氣...
    c25866b24745閱讀 758評(píng)論 7 4
  • 當(dāng)產(chǎn)品經(jīng)理的前幾天我想通過(guò)這個(gè)發(fā)一些我看到的文章的總結(jié)和我的一些自己的响逢,僅出于的自己的體會(huì)绒窑,越分享,越進(jìn)步舔亭!
    閑晃靈人閱讀 149評(píng)論 0 1