ARouter源碼分析

ARouter源碼解讀

以前看優(yōu)秀的開(kāi)源項(xiàng)目绕德,看到了頁(yè)面路由框架ARouter,心想頁(yè)面路由是個(gè)啥東東凡蚜,于是乎網(wǎng)上搜索查看人断,是阿里出品開(kāi)源的,主要是關(guān)于頁(yè)面跳轉(zhuǎn)的解耦框架朝蜘。一直想看看具體是怎么實(shí)現(xiàn)的恶迈,今有時(shí)間便來(lái)一探究竟。

傳統(tǒng)的頁(yè)面跳轉(zhuǎn)就是調(diào)用系統(tǒng)的startActivity谱醇,里面的參數(shù)Intent攜帶了要跳轉(zhuǎn)的信息暇仲,可以傳入要跳轉(zhuǎn)的activity信息或者action。如果是action則要在清單文件里面配置副渴。但是ARouter的實(shí)現(xiàn)頁(yè)面跳轉(zhuǎn)則另辟蹊徑,傳入一個(gè)path路徑奈附,官方示例代碼如下

ARouter.getInstance().build("/test/activity2") .navigation();

初看到這樣的代碼你會(huì)想,這是要跳轉(zhuǎn)到哪里去呢?既然只有一個(gè)路徑佳晶,那么某個(gè)activity必然會(huì)和這個(gè)路徑有關(guān)系.果然在示例代碼的Test2Activity上面有個(gè)注解,里面就有個(gè)這個(gè)參數(shù)桅狠。


基于以前注解的知識(shí)讼载,作猜想,只要獲取Activity上面的注解參數(shù)轿秧,再把該參數(shù)和該Activity綁定起來(lái),全局緩存咨堤,只要匹配跳轉(zhuǎn)路徑是該Activity上注解參數(shù)菇篡,就讓它跳轉(zhuǎn)到該Activity.大概應(yīng)該是這樣。有了這個(gè)猜想一喘,再去查看源碼驱还,看看是否符合猜想。下面開(kāi)始探索源碼之旅凸克。

首先調(diào)用其初始化方法

ARouter.init(getApplication());

點(diǎn)到這個(gè)ARouter類init方法里面议蟆,發(fā)現(xiàn)里面調(diào)用的是一個(gè)_ARouter的初始化方法,再初看其他方法萎战,發(fā)現(xiàn)所有方法其實(shí)都是調(diào)用的_ARouter類的方法咐容。

看_ARouter類的初始化方法

protected static synchronized boolean init(Application application) {????

mContext = application;???

LogisticsCenter.init(mContext, executor);//LogisticsCenter類的初始化????

logger.info(Consts.TAG, "ARouter init success!");//日志初始化???

?hasInit = true;//根據(jù)該變量判斷是否初始化了,若使用前未調(diào)用初始化方法蚂维,則拋出未初始化異常信息 ????// It's not a good idea.????//

if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH) {????// ????application.registerActivityLifecycleCallbacks(new AutowiredLifecycleCallback());????

// }???

?return true;

}

其主要是LogisticsCenter類的初始化戳粒。

LogisticsCenter類的初始化主要都做了什么事情呢路狮?

繼續(xù)往下看


public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {???...前面省略無(wú)關(guān)代碼

Set routerMap;????????// It will rebuild router map every times when debuggable.????????

if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {????????????logger.info(TAG, "Run with debug mode or new install, rebuild router map.");????????????// These class was generate by arouter-compiler.//獲取Arouter自動(dòng)生成的類的信息???????????

?routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);???????????

?if (!routerMap.isEmpty()) {????????????????context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).edit().putStringSet(AROUTER_SP_KEY_MAP, routerMap).apply();????????????}????????????

PackageUtils.updateVersion(context); ???// Save new version name when router map update finish.???????

?} else {????????????logger.info(TAG, "Load router map from cache.");????????????

routerMap = new HashSet<>(context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).getStringSet(AROUTER_SP_KEY_MAP, new HashSet()));????????}????????

logger.info(TAG, "Find router map finished, map size = " + routerMap.size() + ", cost " + (System.currentTimeMillis() - startInit) + " ms.");????????startInit = System.currentTimeMillis();

//將路徑按分類加入緩存???????

?for (String className : routerMap) {???????????

?if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {???????????????

// This one of root elements, load root.????????????????((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);????????????} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {???????????????

?// Load interceptorMeta????????????????((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);????????????} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {????????????????

// Load providerIndex????????????????

((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);????????????}????????}...后面省略無(wú)關(guān)代碼??????}

執(zhí)行完getFileNameByPackageName這個(gè)方法后,Set里面都有些什么呢?


緩存類


初始化完畢蔚约。

小結(jié):初始化方法只是要把緩存里面的groupsIndex和providerIndex和intercaptorsIndex三個(gè)Map集合先緩存了奄妨。groupsIndex主要是組名的路徑和對(duì)象class映射。什么是組名的路徑呢苹祟?

比如當(dāng)前示例傳入的路徑為/test/activity2,則組名就是test砸抛。providerIndex主要是用于依賴注入的path路徑和class對(duì)應(yīng)的關(guān)系。至于啥事依賴注入树枫,就是聲明一個(gè)對(duì)象,并不實(shí)例化锰悼,由框架根據(jù)你傳入的參數(shù)生成對(duì)應(yīng)的對(duì)象,說(shuō)白點(diǎn)就是通過(guò)框架實(shí)例化你所需要的對(duì)象(試想連對(duì)象都不用自己實(shí)例化了,是不是耦合性就非常低了)团赏。如果知道java web spring 框架的話箕般,那么這個(gè)就很清楚了,因?yàn)閟pring框架里面就大量應(yīng)用了依賴注入舔清。InterceptorsIndex則是保存了攔截器的path和class對(duì)應(yīng)的關(guān)系丝里,何為攔截器,攔截什么操作体谒?杯聚,繼續(xù)看下面代碼。


現(xiàn)在查看調(diào)用代碼抒痒,

ARouter.getInstance()????????.build("/test/activity2")????????.navigation();

Build方法調(diào)用_ARouter方法的build方法

public Postcard build(String path) {????return _ARouter.getInstance().build(path);}

查看_ARouter方法

/**?* Build postcard by path and default group?*/

protected Postcard build(String path) {????

if (TextUtils.isEmpty(path)) {????????t

hrow new HandlerException(Consts.TAG + "Parameter is invalid!");???

?} else {????????

PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);????????

if (null != pService) {????????????path = pService.forString(path);????????}????????

return build(path, extractGroup(path));????}}

其中extractGroup方法是根據(jù)路徑解析其路徑所在的組幌绍。

/**?* Extract the default group from path.?*/

private String extractGroup(String path) {????

if (TextUtils.isEmpty(path) || !path.startsWith("/")) {????????throw new HandlerException(Consts.TAG + "Extract the default group failed, the path must be start with '/' and contain more than 2 '/'!");????

}????try {

//如果當(dāng)前路徑是/xxx/... 則默認(rèn)其在xxx組內(nèi). ????????

String defaultGroup = path.substring(1, path.indexOf("/", 1));???????

?if (TextUtils.isEmpty(defaultGroup)) {????????????

throw new HandlerException(Consts.TAG + "Extract the default group failed! There's nothing between 2 '/'!");????????

} else {????????????return defaultGroup;????????}????

} catch (Exception e) {???????

?logger.warning(Consts.TAG, "Failed to extract default group! " + e.getMessage());????????return null;????}}


最終調(diào)用這個(gè)方法

/**?* Build postcard by path and group?*/

protected Postcard build(String path, String group) {???

if (TextUtils.isEmpty(path) || TextUtils.isEmpty(group)) {???????

throw new HandlerException(Consts.TAG + "Parameter is invalid!");???

} else {????????PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);??????

?if (null != pService) {????????????path = pService.forString(path);????????}???????

return new Postcard(path, group);????}}

這個(gè)方法后返回一個(gè)新的Postcard對(duì)象。

先查看Postcard對(duì)象的navigation方法,里面又多個(gè)重載方法故响,但最后都調(diào)用了此方法傀广。

public Object navigation(Context mContext, Postcard postcard, int requestCode, NavigationCallback callback) {????

return _ARouter.getInstance().navigation(mContext, postcard, requestCode, callback);}


還是調(diào)用_ARouter的navigation方法

查看navigation方法

/**?* Use router navigation.?

*?* @param context ????Activity or null.?

* @param postcard ???Route metas?

* @param requestCode RequestCode?

* @param callback ???cb?*/

protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {????try {????????LogisticsCenter.completion(postcard);???

?} catch (NoRouteFoundException ex) {????????logger.warning(Consts.TAG, ex.getMessage());

..//后面代碼暫時(shí)省略


/**?* Completion the postcard by route metas

?*?*@param postcard Incomplete postcard, should completion by this method.?*/

public synchronized static void completion(Postcard postcard) {????????

//從緩存中獲取path對(duì)應(yīng)的RouteMeta類型????//RouteMeta中保存了該路徑對(duì)應(yīng)的目標(biāo)的Class類型????RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());???

?//如果沒(méi)有,去加載????if (null == routeMeta) { ???

// Maybe its does't exist, or didn't load.????????//查找所在組群的類信息???????

?Class groupMeta = Warehouse.groupsIndex.get(postcard.getGroup()); ?

// Load route meta.????????

if (null == groupMeta) {????????????

throw new NoRouteFoundException(TAG + "There is no route match the path [" + postcard.getPath() + "], in group [" + postcard.getGroup() + "]");???????

?} else {????????????// Load route and cache it into memory, then delete from metas.???????????????

?IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();

//加載該群組下面的路徑和class對(duì)應(yīng)的信息????????????????

iGroupInstance.loadInto(Warehouse.routes);????????????????

Warehouse.groupsIndex.remove(postcard.getGroup());????????????????????

completion(postcard); ??// Reload????????}????}

else {????????

postcard.setDestination(routeMeta.getDestination()); ???

//設(shè)置跳轉(zhuǎn)的class信息???????

?postcard.setType(routeMeta.getType()); ?????????????//設(shè)置路由類型????????postcard.setPriority(routeMeta.getPriority()); ?????//路由優(yōu)先級(jí)????????postcard.setExtra(routeMeta.getExtra());????????

Uri rawUri = postcard.getUri();???????

?if (null != rawUri) { ??// Try to set params into bundle.????????????

Map resultMap = TextUtils.splitQueryParameters(rawUri);????????????

Map paramsType = routeMeta.getParamsType();????????????if (MapUtils.isNotEmpty(paramsType)) {????????????????// Set value by its type, just for params which annotation by @Param????????????????for (Map.Entry params : paramsType.entrySet()) {????????????????????

setValue(postcard,????????????????????????????params.getValue(),????????????????????????????params.getKey(),????????????????????????????resultMap.get(params.getKey()));????????????????}????????????????// Save params name which need auto inject.???????????????

?postcard.getExtras().putStringArray(ARouter.AUTO_INJECT, paramsType.keySet().toArray(new String[]{}));????????????}????????????// Save raw uri????????????

postcard.withString(ARouter.RAW_URI, rawUri.toString());????????}...//如果是acitivty跳轉(zhuǎn),下面代碼省略暫時(shí)不看???????}


該方法主要是設(shè)置postcard對(duì)象里面的要跳轉(zhuǎn)的信息彩届,和跳轉(zhuǎn)時(shí)如果有參數(shù)則設(shè)置參數(shù)伪冰。

那么如何使將path和對(duì)應(yīng)的class類信息加載進(jìn)來(lái)的呢?

通過(guò)調(diào)試可以發(fā)現(xiàn)是調(diào)用了ARouter$$Group$$test的loadInto方法


找到該類的該方法,loadInto方法里面有設(shè)置路徑和對(duì)應(yīng)的RoteMeta對(duì)象一一對(duì)應(yīng)樟蠕,而RoteMeta對(duì)象則是保存了相應(yīng)的屬性,比如類型,和跳轉(zhuǎn)的目標(biāo)類類型贮聂。該類沒(méi)有在src目錄下,而是在build目標(biāo)下寨辩,由此可見(jiàn)該類是自動(dòng)編譯的吓懈。


但是是如何自動(dòng)編譯的呢,這個(gè)問(wèn)題暫時(shí)放下靡狞。

繼續(xù)往下看耻警,既然已經(jīng)找到了path和要跳轉(zhuǎn)的activity class的信息了,那么接下應(yīng)該就是調(diào)用真正的跳轉(zhuǎn)方法了。繼續(xù)navigation方法往下看.


/**?* Use router navigation.

*?* @param context ????Activity or null.

* @param postcard ???Route metas

* @param requestCode RequestCode

* @param callback ???cb?*/

protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {

//省略前面代碼...

//如果設(shè)置了greenChannel為true榕栏,表示不需要攔截畔勤,為false。則跳轉(zhuǎn)前還需做一步攔截操作????????if (!postcard.isGreenChannel()) { ?

// It must be run in async thread, maybe interceptor cost too mush time made ANR.

//前面初始化分析的攔截器作用就在此???????

interceptorService.doInterceptions(postcard, new InterceptorCallback() {???????????????????????

@Override???????????

public void onContinue(Postcard postcard) {??????????????

?_navigation(context, postcard, requestCode, callback);????????????}??????????????????});??

?} else {???????

return _navigation(context, postcard, requestCode, callback);??

?}????return null;}


最后調(diào)用了_navigation方法扒磁。

private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {???

?final Context currentContext = null == context ? mContext : context;????switch (postcard.getType()) {????????

case ACTIVITY:????????????// Build intent????????????

final Intent intent = new Intent(currentContext, postcard.getDestination());????????????

intent.putExtras(postcard.getExtras());//設(shè)置要跳轉(zhuǎn)攜帶的參數(shù)????????????// Set flags.???????????

?int flags = postcard.getFlags();????????????

if (-1 != flags) {????????????????intent.setFlags(flags);????????????}

else if (!(currentContext instanceof Activity)) { ???// Non activity, need less one flag.???????????????

?intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);????????????}????????????// Navigation in main looper.????????????

new Handler(Looper.getMainLooper()).post(new Runnable() {????????????????

@Override????????????????public void run() {???????????????????

?if (requestCode > 0) { ?// Need start for result????????????????????????

ActivityCompat.startActivityForResult((Activity) currentContext, intent, requestCode, postcard.getOptionsBundle());???????????????????

?} else {

//真正的跳轉(zhuǎn)動(dòng)作????????????????????????

ActivityCompat.startActivity(currentContext, intent, postcard.getOptionsBundle());????????????????????}???????????????????????????????});????????????

break;???????//如果類型是acitivity則庆揪,后面的可以省略不看????return null;}

終于看到了startActivity方法了。

查看跳轉(zhuǎn)到Test1Activity的示例代碼時(shí)妨托,里面攜帶了要傳入Test1Activity的參數(shù)缸榛,但是Test1Activity里面沒(méi)有看到獲取參數(shù)代碼,而是每個(gè)參數(shù)上面還有@Autowited注解

@Route(path = "/test/activity1")public class Test1Activity extends AppCompatActivity {????@Autowired????String name = "jack";

還有onCreate方法里面的調(diào)用了inject方法.由此可猜測(cè)該方法應(yīng)該已經(jīng)把@Autowited下面的變量全都賦值了兰伤。

ARouter.getInstance().inject(this);


追蹤查看該方法最終調(diào)用了_ARouter里面的inject方法

static void inject(Object thiz) {????

AutowiredService autowiredService = ((AutowiredService) ARouter.getInstance().build("/arouter/service/autowired").navigation());????

if (null != autowiredService) {????????autowiredService.autowire(thiz);????}}


AutowiredService 是個(gè)接口内颗,其實(shí)現(xiàn)是AutowiredServiceImpl類

查看AutowiredServiceImpl類的autowite方法




@Overridepublic void autowire(Object instance) {????

String className = instance.getClass().getName();????

try {????????if (!blackList.contains(className)) {

//????????????ISyringe autowiredHelper = classCache.get(className);????????????

if (null == autowiredHelper) { ?// No cache.

//查找對(duì)應(yīng)的ISyringe 實(shí)現(xiàn)類,className$$ARouter$$Autowired

????????????????autowiredHelper = (ISyringe) Class.forName(instance.getClass().getName() + SUFFIX_AUTOWIRED).getConstructor().newInstance();????????????}????????????

autowiredHelper.inject(instance);????????????

classCache.put(className, autowiredHelper);????????}????}

catch (Exception ex) {????????

blackList.add(className); ???// This instance need not autowired.????}}

最終調(diào)用了className$$ARouter$$Autowired類里面的inject

方法,看到這個(gè)類的類名字敦腔,在該工程查找該類均澳,發(fā)現(xiàn)也在build目錄下


可以看到最終這里調(diào)用getIntent().getXXX獲取Intent攜帶的參數(shù)。因?yàn)閹缀跛蝎@取攜帶參數(shù)的代碼方式是一樣的符衔,因此這里直接也是用自動(dòng)編譯而成的找前。

小結(jié):梳理下跳轉(zhuǎn)界面的步驟 1 首先根據(jù)路徑生成一個(gè)路徑和組名的Postcard對(duì)象。2查看緩存里面是否有組名的class信息判族,如果沒(méi)有躺盛,根據(jù)組名獲取所有組名下面的的class信息。3 根據(jù)獲取的信息填充postcard對(duì)象形帮。4 如果需要攔截槽惫,如執(zhí)行攔截器的方法。5 如果沒(méi)有攔截辩撑,執(zhí)行跳轉(zhuǎn)動(dòng)作. 6 跳轉(zhuǎn)的那個(gè)activity執(zhí)行注入?yún)?shù)方法界斜。

總結(jié):ARouter的界面跳轉(zhuǎn)流程分析完畢。但是ARouter的用處不止界面跳轉(zhuǎn)槐臀,還有依賴注入等其他功能,根據(jù)github官網(wǎng)介紹

1. 支持直接解析標(biāo)準(zhǔn)URL進(jìn)行跳轉(zhuǎn)锄蹂,并自動(dòng)注入?yún)?shù)到目標(biāo)頁(yè)面中

2. 支持多模塊工程使用

3. 支持添加多個(gè)攔截器,自定義攔截順序

4. 支持依賴注入水慨,可單獨(dú)作為依賴注入框架使用

5. 支持InstantRun

6.支持MultiDex(Google方案)

7.映射關(guān)系按組分類、多級(jí)管理敬扛,按需初始化

8. 支持用戶指定全局降級(jí)與局部降級(jí)策略

9. 頁(yè)面晰洒、攔截器、服務(wù)等組件均自動(dòng)注冊(cè)到框架

10. 支持多種方式配置轉(zhuǎn)場(chǎng)動(dòng)畫(huà)

11. 支持獲取Fragment

12. 完全支持Kotlin以及混編(配置見(jiàn)文末 其他#5)

有興趣可以自行查看其他功能詳解


ARouter github地址https://github.com/alibaba/ARouter

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末啥箭,一起剝皮案震驚了整個(gè)濱河市谍珊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌急侥,老刑警劉巖砌滞,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件侮邀,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡贝润,警方通過(guò)查閱死者的電腦和手機(jī)绊茧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)打掘,“玉大人华畏,你說(shuō)我怎么就攤上這事∽鹨希” “怎么了亡笑?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)横朋。 經(jīng)常有香客問(wèn)我仑乌,道長(zhǎng),這世上最難降的妖魔是什么琴锭? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任绝骚,我火速辦了婚禮,結(jié)果婚禮上祠够,老公的妹妹穿的比我還像新娘压汪。我一直安慰自己,他們只是感情好古瓤,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布止剖。 她就那樣靜靜地躺著,像睡著了一般落君。 火紅的嫁衣襯著肌膚如雪穿香。 梳的紋絲不亂的頭發(fā)上袍榆,一...
    開(kāi)封第一講書(shū)人閱讀 51,631評(píng)論 1 305
  • 那天暖途,我揣著相機(jī)與錄音喊暖,去河邊找鬼马僻。 笑死言疗,一個(gè)胖子當(dāng)著我的面吹牛傲醉,可吹牛的內(nèi)容都是我干的扶镀。 我是一名探鬼主播芯侥,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼萌京,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼雁歌!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起知残,我...
    開(kāi)封第一講書(shū)人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤靠瞎,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體乏盐,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡佳窑,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了父能。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片神凑。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖法竞,靈堂內(nèi)的尸體忽然破棺而出耙厚,到底是詐尸還是另有隱情,我是刑警寧澤岔霸,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布薛躬,位于F島的核電站,受9級(jí)特大地震影響呆细,放射性物質(zhì)發(fā)生泄漏型宝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一絮爷、第九天 我趴在偏房一處隱蔽的房頂上張望趴酣。 院中可真熱鬧,春花似錦坑夯、人聲如沸岖寞。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)仗谆。三九已至,卻和暖如春淑履,著一層夾襖步出監(jiān)牢的瞬間隶垮,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工秘噪, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留狸吞,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓指煎,卻偏偏與公主長(zhǎng)得像蹋偏,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子贯要,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

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