【RN】ReactNative與原生交互之Android篇


最近在因?yàn)轫?xiàng)目需求需要模闲,需要在原本的Android工程中集成RN,用RN來開發(fā)需求經(jīng)常變更的、變更周期短的業(yè)務(wù)存璃。寫下這篇文章用來記述集成過程中的細(xì)節(jié)注意點(diǎn)以及一些學(xué)習(xí)經(jīng)驗(yàn)叉存。本文主要介紹RNAndroid原生之間的一些交互操作,以及原生中間件的封裝流程昙衅。涉及如何調(diào)用原生接口扬霜、傳參、獲取回調(diào)值而涉、獲取常量值著瓶、調(diào)用原生UI、監(jiān)聽原生發(fā)送的事件啼县、線程操作等材原。

一、自定義原生模塊

  • 創(chuàng)建自定義模塊
  • 注冊自定義模塊
  • 在RN中使用自定義模塊
  • 獲取原生模塊預(yù)設(shè)常量值
  • 導(dǎo)出帶參函數(shù)方法
  • 導(dǎo)出帶參函數(shù)方法季眷,并使用Callback回調(diào)函數(shù)返回結(jié)果信息
  • 導(dǎo)出帶參函數(shù)方法余蟹,并使用Promises返回結(jié)果信息

1、創(chuàng)建自定義模塊

ReactNative在設(shè)計(jì)之初就考慮能夠在其基礎(chǔ)上通過原生代碼封裝來間接達(dá)到編寫原生代碼的能力子刮。比如當(dāng)我們需求在RN中調(diào)用原生的某個(gè)模塊功能時(shí)威酒,我們可以通過將原生代碼封裝成可以提供給RN調(diào)用的中間件形式,提供相應(yīng)的功能挺峡。通常這樣的原生模塊需要繼承ReactContextBaseJavaModule的Java類葵孤。

  • Android項(xiàng)目中創(chuàng)建CustomModule.java,并繼承自ReactContextBaseJavaModule
  • 實(shí)現(xiàn)初始化函數(shù):
    public CustomModule(ReactApplicationContext reactContext) { super(reactContext) }
  • 實(shí)現(xiàn)getName方法橱赠,該方法返回自定義模塊名稱尤仍,在RN中我們將通過NativateModules.自定義模塊名稱的形式訪問該模塊
public class CustomModule extends ReactContextBaseJavaModule {

    public CustomModule(ReactApplicationContext reactContext) {
        super(reactContext);
    }

    @Override
    // 設(shè)置模塊名稱,需要與RN中調(diào)用時(shí)的模塊名稱保持一致
    public String getName() {
        return "CustomModule";
    }
}

完成上述步驟我們就簡單創(chuàng)建了一個(gè)提供RN使用的原生功能組件狭姨,但是現(xiàn)在RN中還不能夠直接調(diào)用該模塊吓著。我們還需要向RN注冊該模塊,將模塊的功能代碼注入到JavaScript中送挑,最終才能在RN中才能夠使用绑莺。接下來我們?nèi)プ阅K...

2、注冊自定義模塊

我們通過ReactPackage類的createNativeModules方法中添加自定義模塊實(shí)例惕耕,實(shí)現(xiàn)自定義模塊向RN的注冊纺裁。為了方便后期項(xiàng)目中統(tǒng)一管理自定義模塊的注冊,我們創(chuàng)建一個(gè)AndroidReactPackage管理類,并實(shí)現(xiàn)ReactPackage類的構(gòu)造方法欺缘。

public class AndroidReactPackage implements ReactPackage {
    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        
        List<NativeModule> modules = new ArrayList<>();
        modules.add(new CustomModule(reactContext));
        return modules;
    }

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }
}

完成模塊注冊的最后一步栋豫,就是將自定義的AndroidReactPackage添加到ReactPkage中。具體方法就是在MainApplication.java文件中的getPackages方法中添加AndroidReactPackage的實(shí)例谚殊。

@Override
protected List<ReactPackage> getPackages() {
   return Arrays.<ReactPackage>asList(
       new MainReactPackage(),
       new AndroidReactPackage()
   );
}

3丧鸯、在RN中使用自定義原生模塊

在原生項(xiàng)目中實(shí)現(xiàn)向RN中注冊自定義模塊之后,我們可以在JavaScript中通過NativeModules獲取對應(yīng)的模塊嫩絮。通常我們將原生模塊封裝成一個(gè)JavaScript模塊丛肢,省去直接從NativeModules中獲取對應(yīng)模塊的步驟。

// CustomModule.js
/**
 * This exposes the native CustomModule module as a JS module. This has a
 * function 'sendRequest' which takes the following parameters:
 *
 * 1. String parmas: A string with the parmas
 */
import { NativeModules } from "react-native";

module.exports = NativeModules.CustomModule;

注意:這兒NativeModules.后面的名稱是原生模塊中getName方法返回的字符串剿干,必須要保持一致蜂怎。

JavaScript中引用封裝的JS模塊:

import CustomModule from '../NativeModules/CustomModule'

4、獲取模塊預(yù)設(shè)常量值

自定義模塊的時(shí)候置尔,通常我們的模塊中會有一些預(yù)設(shè)的參數(shù)值杠步。在RN中想要獲取這些數(shù)值時(shí),需要在原生的模塊代碼中實(shí)現(xiàn)getConstants方法榜轿,該方法返回一個(gè)Map<String, Object>幽歼。HashMap的Key值為RN中對應(yīng)的屬性名稱,Value值為RN中對應(yīng)的屬性的值谬盐。

    private static final String CUSTOM_CONST_KEY = "TEXT";

    @Nullable
    @Override
    // 獲取模塊預(yù)定義的常量值
    public Map<String, Object> getConstants() {

        final Map<String, Object> constants = new HashMap<>();
        constants.put(CUSTOM_CONST_KEY, "這是模塊預(yù)設(shè)常量值");
        return constants;
    }

RN視圖中顯示自定義模塊預(yù)設(shè)常量值:

<Text>{ CustomModule.TEXT }</Text>

5试躏、導(dǎo)出帶參函數(shù)方法

使用@ReactMethod注解可以導(dǎo)出函數(shù)方法供JavaScript調(diào)用:

    // 導(dǎo)出帶參函數(shù)方法
    @ReactMethod
    public void sendRequest(String parmas) {
        // To Do Something
        Toast.makeText(getReactApplicationContext(), parmas, Toast.LENGTH_SHORT).show();
    }

JavaScript中調(diào)用函數(shù)方法,并傳遞參數(shù):

import CustomModule from '../NativeModules/CustomModule'

CustomModule.sendRequest("This is a string of parma");

6设褐、導(dǎo)出帶參函數(shù)颠蕴,并使用Callback返回結(jié)果

如果函數(shù)方法需要返回結(jié)果,那么可以使用Callback回調(diào)函數(shù)助析,將返回值傳回給JavaScript

    // 導(dǎo)出帶參函數(shù)方法犀被,并使用Callback回調(diào)函數(shù)返回回調(diào)結(jié)果
    @ReactMethod
    public void sendRequest(String message, Callback success, Callback failture) {

        try {
            String parma1 = message;
            String parma2 = "收到回調(diào)信息";
            // 回調(diào)成功,返回結(jié)果信息
            success.invoke(parma1, parma2);
        }catch (IllegalViewOperationException e) {
            // 回調(diào)失敗外冀,返回錯(cuò)誤信息
            failture.invoke(e.getMessage());
        }
    }

JavaScript中調(diào)用帶Callbak回調(diào)函數(shù)的方法寡键,并返回結(jié)果信息:

CustomModule.sendRequest(
    "這是帶Callback回調(diào)的函數(shù)方法",
     (parma1, parma2) => {
        var result = parma1 + parma2;
        console.log(result);
    },
    errMsg => {
        console.log(errMsg);
    }
);

7、導(dǎo)出帶參函數(shù)雪隧,并使用Promises返回結(jié)果

除了設(shè)置Callback回調(diào)函數(shù)的方法外西轩,RN還提供了設(shè)置橋接方法的最后一個(gè)參數(shù)為一個(gè)Promise,并搭配 ES2016(ES7)標(biāo)準(zhǔn)的async/await語法的方式來返回調(diào)用結(jié)果的方式脑沿。

    private static final String E_FUNCTION_ERROR = "E_FUNCTION_ERROR";

    // 導(dǎo)出帶參函數(shù)方法藕畔,并使用Promise簡化回調(diào)結(jié)果方法
    @ReactMethod
    public void sendRequest(String message, Promise promise) {

        try {
            String result = message + ",收到回調(diào)信息";

            WritableMap map = Arguments.createMap();
            map.putString("content", result);

            // 回調(diào)成功庄拇,返回結(jié)果信息
            promise.resolve(map);
        }catch (IllegalViewOperationException e) {
            // 回調(diào)失敗注服,返回錯(cuò)誤信息
            promise.reject(E_FUNCTION_ERROR, e);
        }
    }

JavaScript端調(diào)用上面方法后會返回一個(gè)promise對象韭邓。在一個(gè)聲明了async的異步函數(shù)內(nèi)使用await關(guān)鍵字來調(diào)用,并等待結(jié)果的返回溶弟。

async function testSendRequest() {
    
    try {
        var { content } = await CustomModule.sendRequest(
            "這是使用Promise回調(diào)的函數(shù)方法",
        );
        console.log(content);
    }catch (e) {
        console.error(e);
    }
}

testSendRequest();

二女淑、自定義視圖組件

ReactNative除了可以封裝原生模塊之外,還可以將原生UI視圖封裝成組件后供RN使用辜御。接下來我們來說說如何封裝一個(gè)原生的UI視圖組件及其屬性值設(shè)置鸭你、事件通知,視圖跳轉(zhuǎn)等擒权。

  • 創(chuàng)建自定義視圖組件
  • 注冊自定義視圖組件
  • 封裝對應(yīng)的JavaScript組件代碼
  • 導(dǎo)出自定義視圖組件屬性設(shè)置器
  • 處理自定義原生視圖組件的事件通知
  • 跳轉(zhuǎn)Activity視圖

1袱巨、創(chuàng)建自定義視圖組件

在自定義原生模塊的時(shí)候,我們知道第一步就是創(chuàng)建一個(gè)繼承ReactContextBaseJavaModule類的子類菜拓。同樣的瓣窄,創(chuàng)建自定義原生UI視圖需要被一個(gè)ViewMangager或者SimpleViewManager的派生類創(chuàng)建和管理笛厦。一個(gè)SimpleViewManager的子類包含許多公共屬性纳鼎,包括背景色、透明度裳凸、Flexbox布局等贱鄙。每一個(gè)子類都是一個(gè)單例類。它們被NativeViewHierarchyManager所管理姨谷,在合適的時(shí)候NativeViewHierarchyManager會委托原生UI視圖組件去更新相應(yīng)的視圖屬性逗宁。 ViewMangager還會代理原生視圖的所有委托,在適當(dāng)?shù)臅r(shí)候向RN發(fā)送對應(yīng)的事件通知梦湘。
簡單創(chuàng)建自定義按鈕視圖組件的具體步驟如下:

  • Android項(xiàng)目中創(chuàng)建SimpleViewManager的子類瞎颗。<Button>指定RCTCustomButton這個(gè)視圖管理類所管理的對象類型是原生組件Button類型。
  • 實(shí)現(xiàn)getName方法捌议,該方法返回自定義視圖組件的名稱
  • 實(shí)現(xiàn)createViewInstance方法哼拔,創(chuàng)建原生Button實(shí)例并返回。
package com.rnproject;

import android.widget.Button;

import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;

public class RCTCustomButton extends SimpleViewManager<Button> {

    private ThemedReactContext mReactContext;

    @Override
    public String getName() {
        return "RCTCustomButton";
    }

    @Override
    protected Button createViewInstance(ThemedReactContext reactContext) {

        this.mReactContext = reactContext;
        Button button = new Button(reactContext);
        return button;
    }
}

2瓣颅、注冊自定義視圖組件

我們通過ReactPackage類的createViewManagers方法中添加自定義視圖組件實(shí)例倦逐,實(shí)現(xiàn)自定義視圖組件向RN的注冊。之前我們創(chuàng)建一個(gè)AndroidReactPackage管理類宫补,并實(shí)現(xiàn)了ReactPackage類的構(gòu)造方法檬姥。我們可以在這個(gè)Package中注冊自定義的視圖組件。

public class AndroidReactPackage implements ReactPackage {
    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {

        List<NativeModule> modules = new ArrayList<>();
        modules.add(new CustomModule(reactContext));
        return modules;
    }

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {

        List<ViewManager> managers = new ArrayList<>();
        managers.add(new RCTCustomButton());
        return managers;
    }
}

3粉怕、封裝對應(yīng)的JavaScript組件代碼

JavaScript中健民,我們通過requireNativeComponent引入自定義視圖組件,requireNativeComponent接受的參數(shù)為視圖組件的名稱贫贝,與原生組件中getName方法返回的字符串保持一致荞雏。

// RCTCustomButton.js

import { requireNativeComponent } from "react-native";
/**
 * Composes `Button`.
 */
module.exports = requireNativeComponent("RCTCustomButton");

RN布局中使用自定義視圖組件:

import RCTCustomButton from '../RCTCustomButton'

<RCTCustomButton style = {{width:160,height:50}}/>

4、導(dǎo)出視圖的屬性設(shè)置器

使用 @ReactProp或者@ReactPropGroup注解可以將視圖屬性設(shè)置器的導(dǎo)出,提供RN設(shè)置原生視圖控件屬性的方法凤优。
比如設(shè)置ButtonText屬性:

    // 導(dǎo)出視圖屬性設(shè)置器
    @ReactProp(name = "text")
    public void setText(Button button, String text) {
        button.setText(text);
    }

RN布局代碼中設(shè)置自動(dòng)定義按鈕組件的標(biāo)題:

<RCTCustomButton text="原生自定義按鈕組件" style = {{width:160,height:50}}/>

5悦陋、處理自定義原生視圖組件的事件通知

我們知道原生按鈕是有點(diǎn)擊事件的,那么我們?nèi)绾螌粹o的點(diǎn)擊事情傳遞給JavaScript端呢筑辨?RN如何來處理原生的事件通知呢俺驶?在原生我們封裝的JavaScript組件代碼中沒有任何的處理事件通知的方法,那么接下來我們就去處理原生組件的事件通知棍辕。

  • 首先我們需要將封裝的JavaScript端的組件代碼(RCTCustomButton.js)進(jìn)行改動(dòng)暮现,將其封裝成React組件
  • Android原生視圖組件代碼(RCTCustomButton.java文件)中重寫addEventEmitters方法,添加按鈕點(diǎn)擊事件監(jiān)聽通知
  • 在點(diǎn)擊事件的實(shí)現(xiàn)方法中調(diào)用getJSModule(RCTEventEmitter.class).receiveEvent方法楚昭,傳遞事件通知栖袋。
    receiveEvent方法參數(shù)說明:
    第一個(gè)參數(shù)通過getId()方法將原生組件和React組件關(guān)聯(lián)在一起
    第二個(gè)參數(shù)是事件映射到JavaScript中的Key
    第三個(gè)參數(shù)是事件傳遞到JavaScript端的數(shù)據(jù)
  • 在Android原生視圖組件代碼(RCTCustomButton.java文件)中覆寫getExportedCustomBubblingEventTypeConstants方法將事件通知映射到JavaScript
  • JavaScript端的組件代碼(RCTCustomButton.js)中實(shí)現(xiàn)映射的事件通知方法
  1. 在RN中重新封裝RCTCustomButton.js代碼,將其封裝成React組件
// RCTCustomButton.js

import React, { Component } from 'react';
import { requireNativeComponent } from "react-native";

export default class RCTCustomButton extends Component {

    render() {
        return <CustomButton {...this.props}/>;
    }
}
var CustomButton = requireNativeComponent("RCTCustomButton");
  1. Android原生視圖組件RCTCustomButton.java中添加事件監(jiān)聽抚太,關(guān)聯(lián)視圖組件并傳遞事件通知及其數(shù)據(jù)
    private static final String EVENT_NATIVE_ONCLICK_NAME = "onNativeClick";

    // 重寫addEventEmitters方法塘幅,傳遞點(diǎn)擊事件
    @Override
    protected void addEventEmitters(final ThemedReactContext reactContext, final Button button) {
        super.addEventEmitters(reactContext, button);

        // 添加按鈕點(diǎn)擊事件監(jiān)聽
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                // 返回?cái)?shù)據(jù)
                WritableMap dataMap = Arguments.createMap();
                dataMap.putString("msg", "這是原生按鈕點(diǎn)擊事件");
                // 傳遞事件及其數(shù)據(jù)
                reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(
                        view.getId(),
                        EVENT_NATIVE_ONCLICK_NAME,
                        dataMap
                );
            }
        });
    }

注意:如果不重寫addEventEmitters方法,在createViewInstance方法在添加事件監(jiān)聽也是可以的尿贫。但是優(yōu)先級低于addEventEmitters方法电媳。

  1. 在Android原生視圖組件代碼(RCTCustomButton.java文件)中覆寫getExportedCustomBubblingEventTypeConstants方法將事件通知映射到JavaScript
    // 覆寫getExportedCustomBubblingEventTypeConstants方法,將事件映射到JavaScript端
    @Nullable
    @Override
    public Map<String, Object> getExportedCustomBubblingEventTypeConstants() {
        return MapBuilder.<String, Object>builder().put(
                EVENT_NATIVE_ONCLICK_NAME,
                MapBuilder.of(
                        "phasedRegistrationNames",
                        MapBuilder.of(
                                "bubbled",
                                EVENT_JS_ONCLICK_NAME
                        )
                )
        ).build();
    }

踩坑啦庆亡,踩坑啦:這兒只需要更改EVENT_NATIVE_ONCLICK_NAME對應(yīng)原生組件事件Key值匾乓,EVENT_JS_ONCLICK_NAME對應(yīng)JS端事件的Key值,其他的直接復(fù)制粘貼又谋,尤其是字符串“phasedRegistrationNames”“bubbled”不要更改拼缝,不然會導(dǎo)致映射失敗,點(diǎn)擊按鈕發(fā)現(xiàn)沒有反應(yīng)彰亥。

  1. JavaScript端的組件代碼(RCTCustomButton.js)中實(shí)現(xiàn)映射的事件通知方法咧七,綁定到封裝的組件的方法上。
// RCTCustomButton.js

import React, { Component } from 'react';
import { requireNativeComponent } from "react-native";

export default class RCTCustomButton extends Component {

    constructor(props){
        super(props)
        this._onJSClickEvent = this._onJSClickEvent.bind(this);
    }

    _onJSClickEvent(event: Event) {

        if (!this.props.onClick) {
            return;
        }

        // 獲取原生事件傳遞的數(shù)據(jù)
        this.props.onClick(event.nativeEvent.msg);
    }

    render() {
        return <CustomButton {...this.props} onJSClick={ this._onJSClickEvent }/>;
    }
}

var CustomButton = requireNativeComponent("RCTCustomButton");

完成上述步驟后剩愧,我們就可以通過onClick屬性方法回調(diào)原生組件的點(diǎn)擊事件了O(∩_∩)O~)

在JS中調(diào)用我們自定義的原生組件:

import RCTCustomButton from '../RCTCustomButton'

<RCTCustomButton
    text="原生自定義按鈕組件"
    style = {{width:160,height:50}}
    onClick={(msg) => {
       Alert.alert(msg);
    }}
 />
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末猪叙,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子仁卷,更是在濱河造成了極大的恐慌穴翩,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,561評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锦积,死亡現(xiàn)場離奇詭異芒帕,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)丰介,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評論 3 385
  • 文/潘曉璐 我一進(jìn)店門背蟆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鉴分,“玉大人,你說我怎么就攤上這事带膀≈菊洌” “怎么了?”我有些...
    開封第一講書人閱讀 157,162評論 0 348
  • 文/不壞的土叔 我叫張陵垛叨,是天一觀的道長爆土。 經(jīng)常有香客問我坤检,道長,這世上最難降的妖魔是什么棉姐? 我笑而不...
    開封第一講書人閱讀 56,470評論 1 283
  • 正文 為了忘掉前任妄均,我火速辦了婚禮荐类,結(jié)果婚禮上境肾,老公的妹妹穿的比我還像新娘蚂夕。我一直安慰自己,他們只是感情好佩谷,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,550評論 6 385
  • 文/花漫 我一把揭開白布旁壮。 她就那樣靜靜地躺著,像睡著了一般琳要。 火紅的嫁衣襯著肌膚如雪寡具。 梳的紋絲不亂的頭發(fā)上秤茅,一...
    開封第一講書人閱讀 49,806評論 1 290
  • 那天稚补,我揣著相機(jī)與錄音,去河邊找鬼框喳。 笑死课幕,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的五垮。 我是一名探鬼主播乍惊,決...
    沈念sama閱讀 38,951評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼放仗!你這毒婦竟也來了润绎?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,712評論 0 266
  • 序言:老撾萬榮一對情侶失蹤诞挨,失蹤者是張志新(化名)和其女友劉穎莉撇,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體惶傻,經(jīng)...
    沈念sama閱讀 44,166評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡棍郎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,510評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了银室。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片涂佃。...
    茶點(diǎn)故事閱讀 38,643評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡励翼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出辜荠,到底是詐尸還是另有隱情汽抚,我是刑警寧澤,帶...
    沈念sama閱讀 34,306評論 4 330
  • 正文 年R本政府宣布伯病,位于F島的核電站殊橙,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏狱从。R本人自食惡果不足惜膨蛮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,930評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望季研。 院中可真熱鬧敞葛,春花似錦、人聲如沸与涡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽驼卖。三九已至氨肌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間酌畜,已是汗流浹背怎囚。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留桥胞,地道東北人恳守。 一個(gè)月前我還...
    沈念sama閱讀 46,351評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像贩虾,于是被迫代替她去往敵國和親催烘。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,509評論 2 348

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,769評論 25 707
  • 用兩張圖告訴你缎罢,為什么你的 App 會卡頓? - Android - 掘金 Cover 有什么料伊群? 從這篇文章中你...
    hw1212閱讀 12,699評論 2 59
  • 那只是一方小小的窗臺。 那時(shí)的我必須爬上板凳策精,才能夠找外面的世界舰始。樓房并不高,但足以俯瞰并眺望遠(yuǎn)方蛮寂。...
    Letsstart閱讀 145評論 0 0
  • 兒子小時(shí)候真是多災(zāi)多難蔽午,總是碰到驚險(xiǎn)的事。那時(shí)候我一個(gè)人帶孩子酬蹋,平時(shí)其本每天有男孩子來幫忙帶的及老。有的歲數(shù)小點(diǎn)抽莱,有的...
    A寒秋閱讀 498評論 12 13
  • 沒有一個(gè)女人不美——一位色鬼朋友 在哈市,老房子是韶華已逝的美人馬迭爾眼尾紋里有寧靜風(fēng)暴允許你進(jìn)入她身體或者內(nèi)心索...
    阿劍啊閱讀 299評論 5 13