ReactNative集成網(wǎng)易云信IM Demo(Android版)

版本

本文已 ReactNative 集成 NIM_iOS_Demo_v3.6.0 為例叫胁。Android Studio版本為2.2.3
本人是在已有的ReactNative(以下簡稱RN)工程下集成云信IM(其他各版本集成方式大同小異)

1. 下載云信 IM demo 源碼

前往 網(wǎng)易云信 下載Android版 云信IM demo
下載完成后解壓縮,使用 Android Stuido導(dǎo)入項(xiàng)目森篷,然后運(yùn)行起來疾宏,確保下載下來是可以正常運(yùn)行的。

2. 拷貝 IM 源碼到 RN 項(xiàng)目目錄下

  1. 將下載下來的源碼解壓縮岩馍,拷貝源碼中的nim_demo/uikit目錄到RN工程的android目錄下。
  2. 將 nim_demo/demo 目錄下的源碼和自己項(xiàng)目下的 android/app下合并疫铜。

下載下來的 demo 和 rn 項(xiàng)目目錄結(jié)構(gòu)有點(diǎn)不一致,我這里已 rn 項(xiàng)目目錄結(jié)構(gòu)為主顽馋。
按照 Demo 代碼照貓畫虎的把所有代碼搬過去就行竟稳。
此處省略一萬字...

3. RN 界面和原生界面跳轉(zhuǎn)問題

創(chuàng)建類 RN2NativeModule 他爸,內(nèi)容如下

package com.yuexing.mymodule;

import android.app.Activity;
import android.content.Intent;
import android.widget.Toast;

import com.alibaba.fastjson.JSONObject;
import com.drew.lang.annotations.Nullable;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.netease.nim.uikit.cache.DataCacheManager;
import com.netease.nimlib.sdk.NIMClient;
import com.netease.nimlib.sdk.Observer;
import com.netease.nimlib.sdk.RequestCallback;
import com.netease.nimlib.sdk.StatusBarNotificationConfig;
import com.netease.nimlib.sdk.auth.AuthService;
import com.netease.nimlib.sdk.auth.LoginInfo;
import com.netease.nimlib.sdk.msg.MessageBuilder;
import com.netease.nimlib.sdk.msg.MsgService;
import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum;
import com.netease.nimlib.sdk.msg.model.IMMessage;
import com.yuexing.DemoCache;
import com.yuexing.MainActivity;
import com.yuexing.R;
import com.yuexing.config.preference.Preferences;
import com.yuexing.config.preference.UserPreferences;
import com.yuexing.login.LogoutHelper;
import com.yuexing.session.SessionHelper;

import java.util.List;

/**
 * Created by andy on 2017/5/9.
 */

public class RN2NativeModule extends ReactContextBaseJavaModule {

    private static final String MODULE_NAME = "RN2Native";

    private static final String MAIN_ACTIVITY_CLASSNAME = "com.yuexing.main.activity.MainActivity";

    public RN2NativeModule(ReactApplicationContext reactContext) {
        super(reactContext);

        // 注冊(cè)消息監(jiān)聽事件
        this.registerReceiveMessage(reactContext, true);
    }

    @Override
    public String getName() {
        return MODULE_NAME;
    }

    /**
     * 注冊(cè)/注銷 觀察者事件
     * @param reactContext React 上下文對(duì)象
     * @param isRegister true 為注冊(cè),false 為注銷
     */
    private void registerReceiveMessage(final ReactApplicationContext reactContext, boolean isRegister) {
        // 創(chuàng)建觀察中
        Observer<List<RecentContact>> messageObserver = new Observer<List<RecentContact>>() {
            @Override
            public void onEvent(List<RecentContact> recentContactList) {
                WritableMap params = Arguments.createMap();
                int count = NIMClient.getService(MsgService.class).getTotalUnreadCount();
                params.putInt("unreadCount", count);
                sendEvent(reactContext, "receiveMessage", params);
            }
        };
        NIMClient.getService(MsgServiceObserve.class).observeRecentContact(messageObserver, isRegister);
    }

    /**
     * 發(fā)送事件給 js 端
     * @param reactContext
     * @param eventName
     * @param params
     */
    private void sendEvent(ReactApplicationContext reactContext, String eventName, @Nullable WritableMap params) {
        if (reactContext != null) {
            reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName, params);
        }
    }

    /**
     * IM 登錄
     * @param account 登錄賬號(hào)
     * @param password 登錄密碼
     * @param promise 登錄的回調(diào)函數(shù)
     */
    @ReactMethod
    public void login(final String account, final String password, final Promise promise) {
        LoginInfo loginInfo = new LoginInfo(account, password);
        RequestCallback<LoginInfo> callback = new RequestCallback<LoginInfo>() {
            @Override
            public void onSuccess(LoginInfo loginInfo) {
                // 緩存賬號(hào)
                DemoCache.setAccount(account);
                Preferences.saveUserAccount(account);
                Preferences.saveUserToken(password);

                // 初始化消息提醒配置
                initNotificationConfig();

                // 初始化消息提醒
                NIMClient.toggleNotification(UserPreferences.getNoticeContentToggle());

                // 構(gòu)建緩存
                // DataCacheManager.buildDataCacheAsync();

                JSONObject json = new JSONObject();
                try {
                    int unreadCount = NIMClient.getService(MsgService.class).getTotalUnreadCount();
                    json.put("code", 200);
                    json.put("unreadCount", unreadCount);
                } catch (Exception e) {
                    promise.reject(e);
                }
                promise.resolve(json.toJSONString());
            }

            @Override
            public void onFailed(int code) {
                JSONObject json = new JSONObject();
                // { code: 302 }
                json.put("code", code);
                if (code == 302 || code == 404) {
                    json.put("message", R.string.login_failed);
                }
                promise.resolve(json.toJSONString());
            }

            @Override
            public void onException(Throwable throwable) {
                promise.reject(throwable);
            }
        };
        NIMClient.getService(AuthService.class).login(loginInfo).setCallback(callback);
    }

    /**
     * 初始化消息提醒
     */
    private void initNotificationConfig() {
        NIMClient.toggleNotification(UserPreferences.getNoticeContentToggle());

        // 加載狀態(tài)欄配置
        StatusBarNotificationConfig statusBarNotificationConfig = UserPreferences.getStatusConfig();

        if (statusBarNotificationConfig == null) {
            statusBarNotificationConfig = DemoCache.getNotificationConfig();
            UserPreferences.setStatusConfig(statusBarNotificationConfig);
        }

        // 更新配置
        NIMClient.updateStatusBarNotificationConfig(statusBarNotificationConfig);
    }

    /**
     * IM 登出
     */
    @ReactMethod
    public void logout() {
        System.out.println("java后臺(tái)    IM 注銷");
        Preferences.saveUserToken("");
        NIMClient.getService(AuthService.class).logout();
        // 清理緩存&注銷監(jiān)聽
        LogoutHelper.logout();
    }

    /**
     * 跳轉(zhuǎn)到IM頁
     */
    @ReactMethod
    public void toYunXinIM() {
        try {
            Activity currentActivity = getCurrentActivity();

            if (null != currentActivity) {
                currentActivity.startActivity(new Intent(currentActivity, Class.forName(MAIN_ACTIVITY_CLASSNAME)));
            }
        } catch (Exception e) {
            Toast.makeText(new MainActivity(), "跳轉(zhuǎn)失敗: " + e.getMessage(), Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * 咨詢客服
     * @param userId 用戶id
     * @param textMsg 提醒內(nèi)容
     */
    @ReactMethod
    public void chatWithCS(String userId, String textMsg) {
        IMMessage message = MessageBuilder.createTextMessage(userId, SessionTypeEnum.P2P, textMsg);
        // 第二個(gè)參數(shù)表示發(fā)送失敗后重發(fā),false為不重發(fā)
        NIMClient.getService(MsgService.class).sendMessage(message, true);
    }


    /**
     * 發(fā)送tip給指定用戶
     * @param userId 用戶id
     * @param textMsg 提醒內(nèi)容
     */
    @ReactMethod
    public void p2pTipMsg(String userId, String textMsg) {
        IMMessage message = MessageBuilder.createTipMessage(userId, SessionTypeEnum.P2P);
        message.setContent(textMsg);
        // 第二個(gè)參數(shù)表示發(fā)送失敗后重發(fā)混聊,false為不重發(fā)
        NIMClient.getService(MsgService.class).sendMessage(message, false);
    }


    /**
     * 發(fā)起p2p聊天窗
     * @param userId 對(duì)方id
     */
    @ReactMethod
    public void toP2PChat(String userId) {
        try {
            SessionHelper.startP2PSession(getCurrentActivity(), userId);
        } catch (Exception e) {
            System.out.println("發(fā)起p2p聊天失敗: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 跳轉(zhuǎn)到指定頁
     * @param activityClassName
     */
    @ReactMethod
    public void toActivity(String activityClassName) {
        try {
            Activity currentActivity = getCurrentActivity();

            if (null != currentActivity) {
                Class clazz = Class.forName(activityClassName);
                Intent intent = new Intent(currentActivity, clazz);
                currentActivity.startActivity(intent);
            }
        } catch (Exception e) {
            Toast.makeText(new MainActivity(), "跳轉(zhuǎn)失敗: " + e.getMessage(), Toast.LENGTH_SHORT).show();
        }
    }

}


創(chuàng)建對(duì)應(yīng)的 package 類 RN2NativePackage, 內(nèi)容如下

package com.yuexing.mymodule;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * Created by andy on 2017/5/9.
 */

public class RN2NativePackage implements ReactPackage {

    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        return Arrays.<NativeModule>asList(new RN2NativeModule(reactContext));
    }

    @Override
    public List<Class<? extends JavaScriptModule>> createJSModules() {
        return Collections.emptyList();
    }

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

MainApplication 中的 getPackages 添加如下代碼

@Override
protected List<ReactPackage> getPackages() {
    return Arrays.<ReactPackage>asList(
        new MainReactPackage(),
        // 添加如下代碼
        new RN2NativePackage()
    );
}

當(dāng) RN 界面 調(diào)用 NativeModules.RN2Native.toYunXinIM 跳轉(zhuǎn)到原生im界面時(shí)咳胃,如下所示销睁。

無法返回到原來的 rn 頁面

此時(shí)如果想回到跳轉(zhuǎn)前的頁面冻记,我們發(fā)現(xiàn)沒有返回按鈕冗栗。因此接下來要做的就是添加返回按鈕隅居,返回到原來的 rn 頁面葛虐。

  1. 修改 app/src/main/res/layout/main.xml挡闰,先復(fù)制<android.support.design.widget.AppBarLayout> 節(jié)點(diǎn)(將要粘貼到另一個(gè)文件里)摄悯,然后注釋或刪除申钩,此步操作完后瘪阁,xml配置如下

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:app="http://schemas.android.com/apk/res-auto"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@drawable/skin_global_bg">
<!--
    <android.support.design.widget.AppBarLayout
        android:id="@+id/app_bar_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay"
        app:elevation="0dp">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:titleTextAppearance="@style/Toolbar.TitleText"/>
    </android.support.design.widget.AppBarLayout>
    -->

    <com.yuexing.common.ui.viewpager.PagerSlidingTabStrip
        android:id="@+id/tabs"
        android:layout_width="match_parent"
        android:layout_height="@dimen/pager_sliding_tab_strip_height"
        android:layout_below="@id/app_bar_layout"
        android:background="@drawable/skin_global_bg"/>

    <android.support.v4.view.ViewPager
        android:id="@+id/main_tab_pager"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/tabs"/>

    <com.netease.nim.uikit.common.ui.drop.DropCover
        android:id="@+id/unread_cover"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="invisible"
        />

</RelativeLayout>

  1. 打開文件 app/src/main/res/layout/activity_main_tab.xml,你會(huì)發(fā)現(xiàn)這個(gè)配置文件里除了 LinearLayout 根元素之外廉涕,沒有其他子節(jié)點(diǎn)狐蜕。我們把上一步操作復(fù)制的代碼粘貼到里面层释,完成后結(jié)果如下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/welcome_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    
    <android.support.design.widget.AppBarLayout
        android:id="@+id/app_bar_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay"
        app:elevation="0dp">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:titleTextAppearance="@style/Toolbar.TitleText" />
    </android.support.design.widget.AppBarLayout>
    
</LinearLayout>
  1. 打開文件 app/src/main/java/com/yuexing/main/activity/MainActivity.java 廉白,在 onCreate 函數(shù)中添加三行代碼蒙秒,另外注釋掉 onBackPressed 函數(shù)。完成后如下代碼所示马澈。
    //...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_tab);

        // 添加如下三行代碼
        ToolBarOptions toolBarOptions = new ToolBarOptions();
        toolBarOptions.titleId = R.string.app_name;
        setToolBar(R.id.toolbar, toolBarOptions);

        requestBasicPermission();

        onParseIntent();

        //...
    }

    // ... 

//    @Override
//    public void onBackPressed() {
//        if (mainFragment != null) {
//            if (mainFragment.onBackPressed()) {
//                return;
//            } else {
//                moveTaskToBack(true);
//            }
//        } else {
//            super.onBackPressed();
//        }
//    }

完成上述操作后痊班,再次在使用 Android Studio 運(yùn)行涤伐,然后跳轉(zhuǎn)到云信節(jié)目凝果,跳轉(zhuǎn)后如下圖器净,多了個(gè)返回按鈕,點(diǎn)擊返回則返回到 原來的 RN 頁面浪慌。

完后上述操作后权纤,返回到 RN 界面的按鈕就出來了

4. 去除無用功能和替換logo圖片操作

  • 替換 app/src/main/res/drawable-hdpi 目錄下的 about.logo.pngactionbar_dark_logo_icon.png欧宜,actionbar_white_logo_icon.png冗茸,ic_logo.png夏漱,ic_multiport_detail.png挂绰,ic_stat_notify_msg.png葵蒂,logo.png。刪除 login_bg.png秦士,welcome_bg.pngroom_cover_*.png隧土,刪除圖片后,代碼或配置文件里有引用到圖片的可以選擇刪除或注釋相關(guān)代碼塊卖毁。

  • 替換 app/src/main/res/drawable-mdpi 目錄下的 ic_logo.png落萎,ic_stat_notify_msg.png

  • 替換 app/src/main/res/drawable-xdpi 目錄下的 about_logo.png亥啦,actionbar_dark_logo_icon.pngactionbar_white_logo_icon.png练链,ic_logo.png翔脱,ic_multiport_detail.pngic_stat_notify_msg.png媒鼓,logo.png届吁,welcome_bg.png

  • 替換 app/src/main/res/drawable-xxhdpi 目錄下的 ic_logo.pngic_stat_notify_msg.png

  • 替換 uikit/res/drawable-hdpi 目錄下的 nim_actionbar_dark_logo_icon绿鸣。

  • 替換 uikit/res/drawable-xhdpi 目錄下的 nim_actionbar_dark_logo_icon疚沐。

  • 注釋掉 app/src/main/java/com/yuexing/main/activity/SettingsActivity.java 中的以下行

// ...

//        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
//            items.add(new SettingTemplate(TAG_NRTC_SETTINGS, getString(R.string.nrtc_settings)));
//            items.add(SettingTemplate.addLine());
//            items.add(new SettingTemplate(TAG_NRTC_NET_DETECT, "音視頻通話網(wǎng)絡(luò)探測(cè)"));
//            items.add(SettingTemplate.makeSeperator());
//        }

// ...

//items.add(SettingTemplate.addLine());
//items.add(new SettingTemplate(TAG_JS_BRIDGE, getString(R.string.js_bridge_demonstration)));

// ...
  • 注釋掉 app/src/main/java/com/yuexing/main/activity/SettingsActivity.java 下的
// ...
//Toast.makeText(SettingsActivity.this, "收到multiport push config:" + aBoolean, Toast.LENGTH_SHORT).show();
// ...

    private void initUI() {
        initItems();
        listView = (ListView) findViewById(R.id.settings_listview);
//        View footer = LayoutInflater.from(this).inflate(R.layout.settings_logout_footer, null);
//        listView.addFooterView(footer);

        initAdapter();
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                SettingTemplate item = items.get(position);
                onListItemClick(item);
            }
        });
//        View logoutBtn = footer.findViewById(R.id.settings_button_logout);
//        logoutBtn.setOnClickListener(new View.OnClickListener() {
//            @Override
//            public void onClick(View v) {
//                logout();
//            }
//        });
    }

// ...
  • 修改 uikit/src/com/netease/nim/uikit/common/ui/drop/DropManager.java 中的 destroy 究流,修改如下
    public void destroy() {
        this.isTouchable = false;
        this.statusBarHeight = 0;
        // 判斷 this.dropCover 是否為空
        if (this.dropCover != null) {
            this.dropCover.removeAllDropCompletedListeners();
            this.dropCover = null;
        }
        this.currentId = null;
        this.textPaint = null;
        this.textYOffset = 0;
        this.circlePaint = null;
        this.enable = false;
        LogUtil.i(TAG, "destroy DropManager");
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末哩簿,一起剝皮案震驚了整個(gè)濱河市形入,隨后出現(xiàn)的幾起案子蛇数,更是在濱河造成了極大的恐慌浦徊,老刑警劉巖冕香,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異鸵赖,居然都是意外死亡茫打,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門汉柒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來正塌,“玉大人问裕,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵周偎,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮抬闷,結(jié)果婚禮上纵诞,老公的妹妹穿的比我還像新娘茁裙。我一直安慰自己壕翩,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開白布宅倒。 她就那樣靜靜地躺著,像睡著了一般持痰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上丙挽,一...
    開封第一講書人閱讀 49,730評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音敲董,去河邊找鬼撒桨。 笑死,一個(gè)胖子當(dāng)著我的面吹牛键兜,可吹牛的內(nèi)容都是我干的凤类。 我是一名探鬼主播,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼普气,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼谜疤!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤夷磕,失蹤者是張志新(化名)和其女友劉穎履肃,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體坐桩,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡尺棋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了绵跷。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片膘螟。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖碾局,靈堂內(nèi)的尸體忽然破棺而出荆残,到底是詐尸還是另有隱情,我是刑警寧澤擦俐,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布脊阴,位于F島的核電站,受9級(jí)特大地震影響蚯瞧,放射性物質(zhì)發(fā)生泄漏嘿期。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一埋合、第九天 我趴在偏房一處隱蔽的房頂上張望备徐。 院中可真熱鬧,春花似錦甚颂、人聲如沸蜜猾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蹭睡。三九已至,卻和暖如春赶么,著一層夾襖步出監(jiān)牢的瞬間肩豁,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來泰國打工辫呻, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留清钥,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓放闺,卻偏偏與公主長得像祟昭,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子怖侦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,727評(píng)論 25 707
  • 本文會(huì)不定期更新篡悟,推薦watch下項(xiàng)目谜叹。如果喜歡請(qǐng)star,如果覺得有紕漏請(qǐng)?zhí)峤籭ssue恰力,如果你有更好的點(diǎn)子可以...
    天之界線2010閱讀 18,195評(píng)論 19 153
  • ¥開啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個(gè)線程叉谜,因...
    小菜c閱讀 6,362評(píng)論 0 17
  • 2016年5月我迎來了最糟糕的日子 !畢業(yè)踩萎!對(duì)于如今的大學(xué)生來說 停局、畢業(yè)真的就是一場(chǎng)噩夢(mèng)!成千上萬的人過獨(dú)木橋香府。還...
    陣雨嘩嘩下閱讀 183評(píng)論 0 0
  • 第二百五十七天 最近一直很抑郁董栽,心態(tài)并不是很好。想的問題很多企孩,越想越陷入惡性循環(huán)锭碳。不知道活著的意義,生命的價(jià)值在哪...
    95f8f0c20b38閱讀 301評(píng)論 1 1