手把手帶你造輪子-自己動(dòng)手實(shí)現(xiàn)一款EventBus框架

一、前言:

EventBus是一款事件發(fā)布與訂閱的框架兼贡,主要用來(lái)替代Intent攻冷、Handler、BroadCast來(lái)實(shí)現(xiàn)組件通信遍希,線(xiàn)程間通信等曼。優(yōu)點(diǎn)是:開(kāi)銷(xiāo)小,代碼優(yōu)雅,以及將發(fā)送者與接收者解耦禁谦,使用非常簡(jiǎn)便胁黑。分析EventBus的博客很多,但是很少有帶大家去實(shí)現(xiàn)一款EventBus框架的州泊。沒(méi)錯(cuò)丧蘸,這里我將帶你實(shí)現(xiàn)一款自己的EventBus框架。不管你之前是否接觸過(guò)EventBus遥皂,都可以通過(guò)學(xué)習(xí)而本篇文章力喷,來(lái)學(xué)習(xí)EventBus。

二演训、準(zhǔn)備

在看這篇博客之前需要對(duì)反射冗懦、注解有一定的認(rèn)識(shí),否則你是不容易看懂的仇祭。

三披蕉、流程

整個(gè)EventBus發(fā)布訂閱的流程可以形象為以下過(guò)程,包括后面的部分都是以這個(gè)流程來(lái)分析的

1乌奇、訂閱過(guò)程:

假設(shè)某公司要招聘Android没讲、IOS、前端礁苗、Java...程序員爬凑,它會(huì)先在招聘中介網(wǎng)站上(比如“前程無(wú)憂(yōu)”)提交這些信息。而“前程無(wú)憂(yōu)”需要記下這些信息试伙,它會(huì)將該公司招聘的所有崗位存入一個(gè)List<招聘崗位>集合中嘁信,因?yàn)檎腥说墓究隙ú恢惯@一家,所以然后"前程無(wú)憂(yōu)"會(huì)以公司為鍵疏叨,招聘崗位List為值存入一個(gè)Map<公司,List<招聘崗位>>中潘靖。這就是一個(gè)訂閱過(guò)程、招聘的公司就是訂閱者蚤蔓、“前程無(wú)憂(yōu)”就是一個(gè)中介卦溢。

2、發(fā)布過(guò)程:

求職者為了找工作秀又,也會(huì)去“前程無(wú)憂(yōu)”上面發(fā)布找工作的消息单寂,假設(shè)我們找的是Android的工作,“前程無(wú)憂(yōu)”就會(huì)去它的Map<公司名,List<招聘崗位>>中找吐辙,看有哪個(gè)公司是招聘Android的宣决,找到之后就會(huì)把Android求職推薦給該公司。

3昏苏、注銷(xiāo)過(guò)程:

假設(shè)公司不需要再招人尊沸,那么怎么辦呢?那就注銷(xiāo)唄威沫,此時(shí)“前程無(wú)憂(yōu)”就會(huì)在它的Map<公司名,List<招聘崗位>>中,將該公司移除掉站刑。

上面的過(guò)程大概可以用下面這張圖來(lái)表示:

IMG20170527163016.jpg

理清思路之后我們就可以來(lái)擼碼了瓤湘。

四、正式擼碼

1默责、先看下我們所寫(xiě)代碼的整體結(jié)構(gòu):

![


021IU)(QA507A[Y3K%@20KT.png](http://upload-images.jianshu.io/upload_images/4933844-54f113ac78de4734.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

沒(méi)錯(cuò)壶熏,就這四個(gè)類(lèi)就是實(shí)現(xiàn)了一款EventBus,麻雀雖小句柠,但也是五臟俱全。EventBus類(lèi)就是“前程無(wú)憂(yōu)”棒假,SubscribleMethod類(lèi)就是招聘崗位溯职,ThreadMode和Subscrible是啥先別管它。

2.EventBus類(lèi)的基本實(shí)現(xiàn)(前程無(wú)憂(yōu))

求職者要找工作帽哑,公司要招人谜酒,那么肯定得先有一個(gè)招聘的招聘的中介"前程無(wú)憂(yōu)"。那么我們現(xiàn)在就來(lái)寫(xiě)一個(gè)中介EventBus類(lèi)妻枕,至于怎么寫(xiě)了?大家在使用EventBus的時(shí)候都知道使用以下這句代碼進(jìn)行注冊(cè)(訂閱):
EventBus.getDefault().regist(this);
那么我們就依葫蘆畫(huà)瓢僻族,寫(xiě)一個(gè)getDefault()
方法,代碼如下:

/**
 * Created by Administrator on 2017/5/22.
 * 招聘中介
 */
public class EventBus {
    //招聘中介的信息表(表里面填了各大公司需要招聘的崗位)
    //Map<招聘公司,該公司招聘的崗位集合>
    private Map<Object,List<SubscribleMethod>> cacheMap;
    private static volatile EventBus instance;
    private EventBus(){
        cacheMap=new HashMap<>();
    }
    public static EventBus getDefault(){
        if(instance==null){
            synchronized (EventBus.class){
                if(instance==null){
                    instance=new EventBus();
                }
            }
        }
        return instance;
    }
}

代碼行數(shù)不多屡谐,采用了一個(gè)雙重檢查鎖式的單例模式來(lái)創(chuàng)建EventBus的實(shí)例述么。cacheMap就是用來(lái)存儲(chǔ)各公司招聘信息的。SubscribleMethod這個(gè)類(lèi)就是招聘崗位信息的封裝類(lèi)愕掏,暫時(shí)不用管它度秘,咱們后面再說(shuō)。

2饵撑、注冊(cè)方法的實(shí)現(xiàn)()

有了EventBus的實(shí)例剑梳,那么我們就來(lái)實(shí)現(xiàn)regist方法,代碼如下:

 /**
     * 注冊(cè)
     * @param obj 公司
     */
    public void regist(Object obj){ 
        List<SubscribleMethod> list = cacheMap.get(obj);
        //還沒(méi)有注冊(cè)過(guò),那么就將崗位集合put進(jìn)中介的map中,
        //如果已經(jīng)注冊(cè)過(guò)了滑潘,那么久不用再次注冊(cè)垢乙,那么什么都不做
        if(list==null){
            //找到公司obj招的所有崗位的集合
            List<SubscribleMethod> methods = findSubscribleMethod(obj); 
            cacheMap.put(obj,methods);
        }else {
            throw new RuntimeException("你就已經(jīng)注冊(cè)(訂閱)過(guò)了,不需要再次注冊(cè)(訂閱)");
        }
    }

上面這個(gè)注冊(cè)方法,參數(shù)就是要注冊(cè)的公司對(duì)象众羡。首先會(huì)去“前程無(wú)憂(yōu)”的Map集合里面找一下侨赡,看是否這個(gè)公司已經(jīng)注冊(cè)(訂閱)過(guò)了,如果已經(jīng)注冊(cè)(訂閱)過(guò)了粱侣,那就拋一個(gè)異常告訴它不需要再注冊(cè)了,如果沒(méi)有注冊(cè)(訂閱)蓖宦,才讓他注冊(cè)(訂閱)齐婴,注冊(cè)的公司obj需要招人,那么就得知道obj這個(gè)公司到底招聘那些崗位,findSubscribleMethod(obj)這個(gè)方法就是找到公司obj的所有招聘崗位(具體實(shí)現(xiàn)咱們后面再說(shuō)稠茂,你現(xiàn)在只要知道它是干啥的就行)柠偶,找到公司obj所有崗位的集合后情妖,后面的自然是將公司招聘信息存入“前程無(wú)憂(yōu)”的招聘信息表Map里面去了, 也就是這句代碼cacheMap.put(obj,methods)。

2诱担、Subscrible是個(gè)啥?

上面的代碼結(jié)構(gòu)圖中出現(xiàn)Subscrible毡证,那它是個(gè)啥呢?我們現(xiàn)在就來(lái)說(shuō)一說(shuō)蔫仙,代碼如下:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Subscrible {
    ThreadMode value() default ThreadMode.PostThread;
}

沒(méi)錯(cuò)料睛,它就這幾行代碼,灰常簡(jiǎn)單摇邦,可以看出它就是一個(gè)注解恤煞, 簡(jiǎn)單的來(lái)說(shuō),招聘的公司招人它得有個(gè)招聘的方法呀施籍,招聘的公司肯定也得干其他的事居扒,肯定也有非招聘的方法,那么怎么知道它的哪些方法是招聘的方法呢丑慎?那么就給它的招聘方法上面加個(gè)Subscrible注解我們就知道了喜喂,里面的value()先不管它,下面先給個(gè)示例:

 /**
     *公司招人的方法
     * @param content
     */
    @Subscrible(ThreadMode.PostThread)
    public void receive(AndroidProgrammer content){
        Log.i("zkx","Thread  "+Thread.currentThread().getName());
        //Toast彈不出來(lái),不知道為啥
        //Toast.makeText(this,Thread.currentThread().getName(),Toast.LENGTH_SHORT);
    }

@Subscrible(ThreadMode.MainThread)這句代碼就表示了這個(gè)方法是一個(gè)招聘方法竿裂,()里面的代碼表示這個(gè)方法是在主線(xiàn)程里面執(zhí)行的玉吁。該方法的參數(shù)類(lèi)型就表明了招的是什么職位,我這里是招聘AndroidProgrammer铛绰,至于ThreadMode請(qǐng)看下面诈茧。

3、ThreadMode是個(gè)啥?

ThreadMode聽(tīng)名字就知道是線(xiàn)程模式的意思捂掰,具體的請(qǐng)看代碼:

public enum ThreadMode {
    PostThread,//發(fā)送線(xiàn)程執(zhí)行
    MainThread,//主線(xiàn)程執(zhí)行
    BackgroundThread,//后臺(tái)線(xiàn)程執(zhí)行
    Async

這段其實(shí)就是直接復(fù)制EventBus源碼里面的敢会,英文注釋太長(zhǎng)了,我給去掉了这嚣∨富瑁可以看出他就是一個(gè)枚舉,請(qǐng)看我給出的注釋。再回到
注解Subscrible的代碼中姐帚,我們就可以知道它里面的value()值就是說(shuō)加上這個(gè)注解的在哪個(gè)線(xiàn)程執(zhí)行了吏垮,我的代碼中默認(rèn)指定的是PostThread。

4罐旗、SubscribleMethod是個(gè)啥?

從名字是可以看出它是訂閱方法的意思膳汪,實(shí)際是上它是封裝了招聘崗位信息(公司招聘的方法、招聘崗位的類(lèi)型九秀、招聘方法在哪個(gè)線(xiàn)程執(zhí)行)的一個(gè)JavaBean遗嗽。具體代碼如下:

**
 * Created by Administrator on 2017/5/22.
 * 招聘崗位信息類(lèi)
 */
public class SubscribleMethod {
    //招聘這個(gè)崗位的方法
    private Method method;
    //招聘這個(gè)崗位的方法在哪個(gè)線(xiàn)程里面執(zhí)行
    private ThreadMode threadMode;
    //招聘的崗位的類(lèi)型
    private Class<?> eventType;

    public SubscribleMethod(Method method, ThreadMode threadMode, Class<?> eventType) {
        this.method = method;
        this.threadMode = threadMode;
        this.eventType = eventType;
    }

    public Method getMethod() {
        return method;
    }

    public void setMethod(Method method) {
        this.method = method;
    }

    public ThreadMode getThreadMode() {
        return threadMode;
    }

    public void setThreadMode(ThreadMode threadMode) {
        this.threadMode = threadMode;
    }

    public Class<?> getEventType() {
        return eventType;
    }

    public void setEventType(Class<?> eventType) {
        this.eventType = eventType;
    }
}

5、深入細(xì)節(jié)

到這里EventBus的各個(gè)類(lèi)的意思已經(jīng)說(shuō)完了鼓蜒,我們來(lái)看一些細(xì)節(jié)的東西痹换。上面“2征字、注冊(cè)方法的實(shí)現(xiàn)”這段,我們說(shuō)到findSubscribleMethod(obj)這個(gè)方法就是找到公司obj的所有招聘崗位娇豫,那么我們就來(lái)看看它是怎么找的匙姜,代碼如下:

 /**
     * 尋找該公司的招聘崗位
     * @param activity 該公司
     * @return
     */
    private List<SubscribleMethod> findSubscribleMethod(Object activity) {
        List<SubscribleMethod> list  = new CopyOnWriteArrayList<>();
        Class<?> clazz = activity.getClass();
        Method[] methods = clazz.getDeclaredMethods();
        //循環(huán)查找父類(lèi) 接收方法
        while(clazz!=null){//如果該公司又隸屬于某個(gè)更大的公司,那么它也要為這個(gè)更大的公司招人
            String name = clazz.getName();
            //系統(tǒng)方法直接break
            if(name.startsWith("java.")||name.startsWith("javax.")||name.startsWith("android.")){
                break;
            }
            //遍歷所有類(lèi)的方法(其中有Subscrible注解的為招人的崗位(方法))
            //每找到一個(gè)招聘崗位就將其放到集合中冯痢,最終返回的集合list就是該公司所有招聘崗位的集合
            for (Method method:methods){
                //持有Subscrible注解的才是個(gè)接收方法氮昧,才是個(gè)崗位
                //發(fā)生線(xiàn)程
                Subscrible subscrible = method.getAnnotation(Subscrible.class);
                if (subscrible==null){
                    continue;
                }
                //拿到方法的參數(shù)類(lèi)型的數(shù)組
                Class<?>[] parameters = method.getParameterTypes();
                if(parameters.length!=1){//只能接收一個(gè)參數(shù)
                    throw new RuntimeException("eventbus must be one parameter");
                }
                //獲得參數(shù)類(lèi)型數(shù)組的第一個(gè)元素(也只有一個(gè)元素)
                Class<?> paramClass  = parameters[0];
                //拿到發(fā)生的線(xiàn)程(默認(rèn)發(fā)生在PostThread)
                ThreadMode threadMode = subscrible.value();
                //new一個(gè)招聘崗位
                SubscribleMethod subscribleMethod = new SubscribleMethod(method,threadMode,paramClass);
                //招聘中介(前程無(wú)憂(yōu)) 把該公司所有崗位緩存到集合
                list.add(subscribleMethod);
            }
            clazz=clazz.getSuperclass();
        }
        return list;
    }

從代碼總可以看出,我們其實(shí)就是通過(guò)反射拿到該招聘公司的所有方法系羞,遍歷這些方法郭计,判斷這些方法是不是招聘的方法,具體的就是看這些方法有沒(méi)有加Subscrible 注解椒振,加了注解的肯定就是招聘方法昭伸,繼而拿到,每一個(gè)招聘方法的參數(shù)類(lèi)型澎迎,也就是招聘的崗位庐杨,然后將所有的崗位存入List集合中。還有一點(diǎn)要注意的是如果公司類(lèi)是繼承自某個(gè)類(lèi)夹供,也就是說(shuō)該公司它是某個(gè)更大的公司的一個(gè)子公司灵份,那么它在招人的同時(shí)也得給它的父公司招人。所以有了我們的最外層的while循環(huán)哮洽,不斷遍歷它的父類(lèi)填渠,直到系統(tǒng)類(lèi)為止。

6鸟辅、發(fā)布的方法

到這里氛什,中介有了,公司也注冊(cè)(訂閱)了匪凉,那么就到我們求職者出場(chǎng)了枪眉,假設(shè)我們要找Android程序員的工作,那么就只需要調(diào)用下面這句代碼就行:

EventBus.getDefault().post(new AndroidProgrammer("zkx","123456"));

其實(shí)就是調(diào)用了EventBus的post方法再层,具體實(shí)現(xiàn)如下:

 /**
     * 安卓程序員 來(lái)找工作
     * @param object 求職的崗位類(lèi)型
     */
    public void post(final Object object) {
        //拿到集合cacheMap里所有的公司
        Set<Object> set = cacheMap.keySet();
        Iterator iterator = set.iterator();
        while(iterator.hasNext()){
            //拿到具體的每一個(gè)公司
            final Object activity = iterator.next();
            //拿出該公司招聘的崗位集合
            List<SubscribleMethod> list = cacheMap.get(activity);
            //遍歷該公司招聘崗位的集合贸铜,看有沒(méi)有招聘安卓的
            for (final SubscribleMethod method:list) {
                //如果是屬于同樣的類(lèi)型(如果有崗位匹配)
                if(method.getEventType().isAssignableFrom(object.getClass())){
                    //判斷當(dāng)前接收方法是在哪個(gè)線(xiàn)程
                    switch (method.getThreadMode()){
                        //發(fā)送方法的線(xiàn)程和接收的線(xiàn)程在同一個(gè)線(xiàn)程,直接invoke就完事了
                        case PostThread:
                            //activity:公司,method:崗位,object:求職者
                            //崗位匹配,把這個(gè)人招進(jìn)來(lái)
                            invoke(activity,method,object);
                            break;
                        case MainThread:
                            //判斷發(fā)送線(xiàn)程是在哪個(gè)線(xiàn)程,
                            //如果發(fā)送線(xiàn)程就是主線(xiàn)程就不用切換線(xiàn)程
                            if(Looper.myLooper()==Looper.getMainLooper()){
                                //直接調(diào)用
                                invoke(activity,method,object);
                            }else {//發(fā)送是在子線(xiàn)程
                                handler.post(new Runnable() {
                                    @Override
                                    public void run() {
                                        invoke(activity,method,object);
                                    }
                                });
                            }
                            break;
                        //指定接收方法發(fā)生在子線(xiàn)程
                        case BackgroundThread:
                            //如果當(dāng)前發(fā)送線(xiàn)程就是子線(xiàn)程就不用切換線(xiàn)程
                            if(Looper.myLooper()!=Looper.getMainLooper()){
                                //發(fā)生在子線(xiàn)程
                                invoke(activity,method,object);
                            }else {
                                executorService.execute(new Runnable() {
                                    @Override
                                    public void run() {
                                        invoke(activity,method,object);
                                    }
                                });
                            }
                            break;
                    }
                }
            }
        }
    }

代碼有些長(zhǎng)聂受,但是基本上每行代碼都給出了注釋蒿秦。理解起來(lái)應(yīng)該不難。大體的流程就是在”前程無(wú)憂(yōu)”的信息表里面拿到所有的公司蛋济,然后遍歷這些公司渤早,看這些公司的招聘崗位里面有木有Android的崗位(是否匹配),如果有的話(huà)瘫俊,那就利用反射去調(diào)用有招聘Android崗位的公司的招聘方法來(lái)招聘這個(gè)求職者鹊杖。還有需要注意的就是,我們會(huì)根據(jù)發(fā)布方法(求職者發(fā)布求職的方法)和接收方法(公司招人的方法)所在線(xiàn)程的不同扛芽,采取不同的策略骂蓖。具體請(qǐng)看代碼,有詳細(xì)的注釋川尖。反射調(diào)用公司的招聘方法代碼如下:


    /**
     * @param activity 公司
     * @param method   崗位信息封裝類(lèi)
     * @param object   求職者
     */
    private void invoke(Object activity, SubscribleMethod method, Object object) {
        try {
            //調(diào)用公司activity的崗位method的招人方法method.getMethod()方法,
            //傳參object,代表招Object類(lèi)型崗位的人
            method.getMethod().invoke(activity,object);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

7注銷(xiāo)方法的實(shí)現(xiàn)(取消訂閱)

公司不招人了登下,那么就得注銷(xiāo)(取消訂閱),代碼很簡(jiǎn)單叮喳,就是將該公司的信息從EventBus的map中移除就行了

 public void unregist(Object object){
        //在中介的map中將該公司object移除
        cacheMap.remove(object);
 }

五被芳、最后

到這里我們所有的代碼就寫(xiě)完了,現(xiàn)在就可以使用我們寫(xiě)的這款框架來(lái)進(jìn)行組件間、線(xiàn)程間通信了馍悟,寫(xiě)的不好的或者錯(cuò)誤的畔濒,歡迎批評(píng)指正。
全部代碼下載地址:
https://github.com/zkxok/MyEventBus

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末锣咒,一起剝皮案震驚了整個(gè)濱河市侵状,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌毅整,老刑警劉巖趣兄,帶你破解...
    沈念sama閱讀 216,651評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異悼嫉,居然都是意外死亡艇潭,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)戏蔑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蹋凝,“玉大人,你說(shuō)我怎么就攤上這事辛臊∠闪唬” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,931評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵彻舰,是天一觀(guān)的道長(zhǎng)伐割。 經(jīng)常有香客問(wèn)我,道長(zhǎng)刃唤,這世上最難降的妖魔是什么隔心? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,218評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮尚胞,結(jié)果婚禮上硬霍,老公的妹妹穿的比我還像新娘。我一直安慰自己笼裳,他們只是感情好唯卖,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布粱玲。 她就那樣靜靜地躺著,像睡著了一般拜轨。 火紅的嫁衣襯著肌膚如雪抽减。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,198評(píng)論 1 299
  • 那天橄碾,我揣著相機(jī)與錄音卵沉,去河邊找鬼。 笑死法牲,一個(gè)胖子當(dāng)著我的面吹牛史汗,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播拒垃,決...
    沈念sama閱讀 40,084評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼停撞,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了恶复?” 一聲冷哼從身側(cè)響起怜森,我...
    開(kāi)封第一講書(shū)人閱讀 38,926評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎谤牡,沒(méi)想到半個(gè)月后副硅,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,341評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡翅萤,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評(píng)論 2 333
  • 正文 我和宋清朗相戀三年恐疲,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片套么。...
    茶點(diǎn)故事閱讀 39,731評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡培己,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出胚泌,到底是詐尸還是另有隱情省咨,我是刑警寧澤,帶...
    沈念sama閱讀 35,430評(píng)論 5 343
  • 正文 年R本政府宣布玷室,位于F島的核電站零蓉,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏穷缤。R本人自食惡果不足惜敌蜂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望津肛。 院中可真熱鬧章喉,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,676評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至撞反,卻和暖如春妥色,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背遏片。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,829評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留撮竿,地道東北人吮便。 一個(gè)月前我還...
    沈念sama閱讀 47,743評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像幢踏,于是被迫代替她去往敵國(guó)和親髓需。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評(píng)論 2 354

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,079評(píng)論 25 707
  • EventBus源碼分析(一) EventBus官方介紹為一個(gè)為Android系統(tǒng)優(yōu)化的事件訂閱總線(xiàn)房蝉,它不僅可以很...
    蕉下孤客閱讀 3,998評(píng)論 4 42
  • 感恩今天和好姐妹一起慶祝僚匆,慶祝我的第一份兼職收入資金到位,用勞動(dòng)和學(xué)習(xí)來(lái)的成果換取的勞務(wù)費(fèi)搭幻,值得慶祝下咧擂。也要感謝我...
    念秀閱讀 96評(píng)論 0 1
  • 各位親: 因朋友擁有一個(gè)車(chē)類(lèi)域名,可能是職業(yè)的原因檀蹋,一直以來(lái)從事松申,網(wǎng)絡(luò)運(yùn)營(yíng)工作,十來(lái)年俯逾,也已經(jīng)做到公司高層贸桶,這次應(yīng)...
    tyuguang閱讀 1,129評(píng)論 1 50
  • 大河向東流皇筛,天上的星星參北斗.....大家是唱下來(lái)這句話(huà)的請(qǐng)點(diǎn)贊了。 這首好漢歌來(lái)大家都很熟悉坠七,水滸傳主題曲水醋。水滸...
    小學(xué)生老韓閱讀 755評(píng)論 0 0