自制“萬(wàn)能”的基礎(chǔ)BaseActivity4.0

此項(xiàng)目已上傳GitHub:https://github.com/kongzue/BaseActivity 歡迎Fork&Star

此版本是基于上次的《自用基礎(chǔ)Activity:BaseActivity3.0》的更新:http://www.reibang.com/p/7d22397bebf1 具體的基本使用方法請(qǐng)參閱3.0

警告:
1.請(qǐng)無(wú)視本文章標(biāo)題蚊夫,因?yàn)檫@個(gè)“萬(wàn)能”是正在進(jìn)行時(shí)皮官,以后依然還會(huì)不斷完善增加功能
2.制作這個(gè)基礎(chǔ)BaseActivity的目的是讓今后的開發(fā)更容易巢株,該有的都有了不用到處在忙著找東找西
3.一聲不吭的轉(zhuǎn)載者的節(jié)操呢?

新增說(shuō)明:
1.對(duì)于魅族的smartbar高度進(jìn)行計(jì)算
2.由于本人常用的http請(qǐng)求框架是Volley,不習(xí)慣不合適的請(qǐng)刪除代碼中的如下一行,之所以默認(rèn)帶上的原因是繼承這個(gè)BaseActivity的所有Activity都可以輕松使用Volley請(qǐng)求網(wǎng)絡(luò),我就是這么懶锣夹。

public RequestQueue mQueue;            //請(qǐng)求隊(duì)列

3.另外新增了權(quán)限申請(qǐng),使用方法如下:

    //使用:
    requestPermission(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE}, 1);

    //...

    /**
    * 權(quán)限回調(diào)
    */
    @Override
    public void permissionSuccess(int requestCode) {
        super.permissionSuccess(requestCode);
        switch (requestCode) {
            case 1:
                //權(quán)限申請(qǐng)成功...
                break;
        }

    }

以下苏潜,引用部分:

import android.app.ActionBar;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.Settings;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.Window;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.Toast;


import com.android.volley.RequestQueue;    //不用Volley的刪掉這個(gè)
import com.android.volley.toolbox.Volley;    //不用Volley的刪掉這個(gè)
import 你的包名.BuildConfig;
import 你的包名.R;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

import java.util.ArrayList;
import java.util.List;

代碼部分

/**
 * Created by chao on 2016/11/5.
 * 半透明狀態(tài)欄形式的Activity
 * 以及對(duì)原生安卓银萍、MIUI、flyme的透明狀態(tài)欄顯示灰色圖標(biāo)文字的支持
 * 我只想說(shuō)太tm麻煩了
 */
public class BaseActivity extends Activity {

    public RequestQueue mQueue;            //請(qǐng)求隊(duì)列
    public Activity me = this;
    protected SystemBarTintManager mTintManager;

    private static final String KEY_MIUI_VERSION_CODE = "ro.miui.ui.version.code";
    private static final String KEY_MIUI_VERSION_NAME = "ro.miui.ui.version.name";
    private static final String KEY_MIUI_INTERNAL_STORAGE = "ro.miui.internal.storage";

    public static boolean isMIUI() {
        try {
            final BuildProperties prop = BuildProperties.newInstance();
            return prop.getProperty(KEY_MIUI_VERSION_CODE, null) != null || prop.getProperty(KEY_MIUI_VERSION_NAME, null) != null || prop.getProperty(KEY_MIUI_INTERNAL_STORAGE, null) != null;
        } catch (final IOException e) {
            return false;
        }
    }

    public static boolean isFlyme() {
        try {
            final Method method = Build.class.getMethod("hasSmartBar");

            return method != null;
        } catch (final Exception e) {
            return false;
        }
    }

    // 獲取魅族SmartBar高度
    public float getSmartBarHeight(Context context) {
        final boolean isMeiZu = Build.MANUFACTURER.equals("Meizu");

        final boolean autoHideSmartBar = Settings.System.getInt(context.getContentResolver(),
                "mz_smartbar_auto_hide", 0) == 1;

        if (isMeiZu) {
            if (autoHideSmartBar) {
                return 0;
            } else {
                try {
                    Class c = Class.forName("com.android.internal.R$dimen");
                    Object obj = c.newInstance();
                    Field field = c.getField("mz_action_button_min_height");
                    int height = Integer.parseInt(field.get(obj).toString());
                    return context.getResources().getDimensionPixelSize(height) ;
                } catch (Throwable e) { // 不自動(dòng)隱藏smartbar同時(shí)又沒有smartbar高度字段供訪問(wèn)恤左,取系統(tǒng)navigationbar的高度
                    return getNormalNavigationBarHeight(context);
                }
            }
        } else {
            return 0;
            //return getNormalNavigationBarHeight(context) / metrics.density;
        }
    }

    protected static float getNormalNavigationBarHeight(final Context ctx) {
        try {
            final Resources res = ctx.getResources();
            int rid = res.getIdentifier("config_showNavigationBar", "bool", "android");
            if (rid > 0) {
                boolean flag = res.getBoolean(rid);
                if (flag) {
                    int resourceId = res.getIdentifier("navigation_bar_height", "dimen", "android");
                    if (resourceId > 0) {
                        return res.getDimensionPixelSize(resourceId);
                    }
                }
            }
        } catch (Throwable e) {
            return 0;
        }
        return 0;
    }


    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mTintManager = new SystemBarTintManager(this);
        mQueue = Volley.newRequestQueue(this);         //創(chuàng)建請(qǐng)求隊(duì)列
    }

    protected void setTranslucentStatus(boolean on, boolean darkmode) {
        Log.i("SDK_INT", Build.VERSION.SDK_INT + "");
        if (isMIUI()) setStatusBarDarkMode(darkmode, this);
        if (isFlyme()) setStatusBarDarkIcon(getWindow(), darkmode);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            Window window = getWindow();
            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
                    | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
            window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
            window.setStatusBarColor(Color.TRANSPARENT);
            window.setNavigationBarColor(Color.BLACK);

            if (darkmode)
                getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
            getWindow().setStatusBarColor(Color.TRANSPARENT);
            return;
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            Window win = getWindow();
            WindowManager.LayoutParams winParams = win.getAttributes();
            final int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
            if (on) {
                winParams.flags |= bits;
            } else {
                winParams.flags &= ~bits;
            }
            win.setAttributes(winParams);
            return;
        }
    }

    public void setStatusBarDarkMode(boolean darkmode, Activity activity) {
        Class<? extends Window> clazz = activity.getWindow().getClass();
        try {
            int darkModeFlag = 0;
            Class<?> layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
            Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
            darkModeFlag = field.getInt(layoutParams);
            Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
            extraFlagField.invoke(activity.getWindow(), darkmode ? darkModeFlag : 0, darkModeFlag);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static boolean setStatusBarDarkIcon(Window window, boolean dark) {
        boolean result = false;
        if (window != null) {
            try {
                WindowManager.LayoutParams lp = window.getAttributes();
                Field darkFlag = WindowManager.LayoutParams.class.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
                Field meizuFlags = WindowManager.LayoutParams.class.getDeclaredField("meizuFlags");
                darkFlag.setAccessible(true);
                meizuFlags.setAccessible(true);
                int bit = darkFlag.getInt(null);
                int value = meizuFlags.getInt(lp);
                if (dark) {
                    value |= bit;
                } else {
                    value &= ~bit;
                }
                meizuFlags.setInt(lp, value);
                window.setAttributes(lp);
                result = true;
            } catch (Exception e) {
                Log.e("MeiZu", "setStatusBarDarkIcon: failed");
            }
        }
        return result;
    }

    //獲取是否存在NavigationBar
    public boolean checkDeviceHasNavigationBar() {
        if (getWindowManager().getDefaultDisplay().getHeight() < (getWindowManager().getDefaultDisplay().getWidth() * 16 / 9) - 20) {
            return true;
        } else {
            return false;
        }
    }


    public static class BuildProperties {

        private final Properties properties;

        private BuildProperties() throws IOException {
            properties = new Properties();
            properties.load(new FileInputStream(new File(Environment.getRootDirectory(), "build.prop")));
        }

        public boolean containsKey(final Object key) {
            return properties.containsKey(key);
        }

        public boolean containsValue(final Object value) {
            return properties.containsValue(value);
        }

        public Set<Map.Entry<Object, Object>> entrySet() {
            return properties.entrySet();
        }

        public String getProperty(final String name) {
            return properties.getProperty(name);
        }

        public String getProperty(final String name, final String defaultValue) {
            return properties.getProperty(name, defaultValue);
        }

        public boolean isEmpty() {
            return properties.isEmpty();
        }

        public Enumeration<Object> keys() {
            return properties.keys();
        }

        public Set<Object> keySet() {
            return properties.keySet();
        }

        public int size() {
            return properties.size();
        }

        public Collection<Object> values() {
            return properties.values();
        }

        public static BuildProperties newInstance() throws IOException {
            return new BuildProperties();
        }

    }


    /**
     * 設(shè)置占位符布局
     */
    public void setStatusBarHeight() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            LinearLayout linear_bar = (LinearLayout) findViewById(R.id.sys_statusBar);
            linear_bar.setVisibility(View.VISIBLE);
            int statusHeight = getStatusBarHeight();
            android.widget.RelativeLayout.LayoutParams params = (android.widget.RelativeLayout.LayoutParams) linear_bar.getLayoutParams();
            params.height = statusHeight;
            linear_bar.setLayoutParams(params);
        }
    }


    public void setStatusBarHeightByLayout(LinearLayout linearLayout) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            LinearLayout linear_bar = linearLayout;
            linear_bar.setVisibility(View.VISIBLE);
            int statusHeight = getStatusBarHeight();
            android.widget.RelativeLayout.LayoutParams params = (android.widget.RelativeLayout.LayoutParams) linear_bar.getLayoutParams();
            params.height = statusHeight;
            linear_bar.setLayoutParams(params);
        }
    }//end setStatusBarHeight()


    /**
     * 獲取狀態(tài)欄的高度
     *
     * @return
     */
    private int getStatusBarHeight() {
        try {
            Class<?> c = Class.forName("com.android.internal.R$dimen");
            Object obj = c.newInstance();
            Field field = c.getField("status_bar_height");
            int x = Integer.parseInt(field.get(obj).toString());
            return getResources().getDimensionPixelSize(x);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    protected final static String NULL = "";
    private Toast toast;

    protected void runOnMain(Runnable runnable) {
        runOnUiThread(runnable);
    }

    //簡(jiǎn)易吐司
    public void toast(final Object obj) {
        try {
            runOnMain(new Runnable() {

                @Override
                public void run() {
                    if (toast == null)
                        toast = Toast.makeText(BaseActivity.this, NULL, Toast.LENGTH_SHORT);
                    toast.setText(obj.toString());
                    toast.show();
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //簡(jiǎn)易Log
    public void log(final Object obj) {
        try {
            runOnMain(new Runnable() {

                @Override
                public void run() {
                    if (BuildConfig.DEBUG) {
                        Log.i("log", obj.toString());
                    }
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //軟鍵盤打開與收起
    public void setIMMStatus(boolean show, EditText editText) {
        if (show) {
            editText.requestFocus();
            editText.setFocusableInTouchMode(true);
            InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.showSoftInput(editText, InputMethodManager.SHOW_FORCED);
        } else {
            InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
        }
    }

    public static String StartFindWords = "";

    //用于進(jìn)行dip和px轉(zhuǎn)換
    public static int dip2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    //用于進(jìn)行px和dip轉(zhuǎn)換
    public static int px2dip(Context context, float pxValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }


    //權(quán)限相關(guān)

    private final String TAG = "PermissionsUtil";
    private int REQUEST_CODE_PERMISSION = 0x00099;

    /**
     * 請(qǐng)求權(quán)限
     *
     * @param permissions 請(qǐng)求的權(quán)限
     * @param requestCode 請(qǐng)求權(quán)限的請(qǐng)求碼
     */
    public void requestPermission(String[] permissions, int requestCode) {
        this.REQUEST_CODE_PERMISSION = requestCode;
        if (checkPermissions(permissions)) {
            permissionSuccess(REQUEST_CODE_PERMISSION);
        } else {
            List<String> needPermissions = getDeniedPermissions(permissions);
            ActivityCompat.requestPermissions(this, needPermissions.toArray(new String[needPermissions.size()]), REQUEST_CODE_PERMISSION);
        }
    }

    /**
     * 檢測(cè)所有的權(quán)限是否都已授權(quán)
     *
     * @param permissions
     * @return
     */
    private boolean checkPermissions(String[] permissions) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            return true;
        }

        for (String permission : permissions) {
            if (ContextCompat.checkSelfPermission(this, permission) !=
                    PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }

    /**
     * 獲取權(quán)限集中需要申請(qǐng)權(quán)限的列表
     *
     * @param permissions
     * @return
     */
    private List<String> getDeniedPermissions(String[] permissions) {
        List<String> needRequestPermissionList = new ArrayList<>();
        for (String permission : permissions) {
            if (ContextCompat.checkSelfPermission(this, permission) !=
                    PackageManager.PERMISSION_GRANTED ||
                    ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) {
                needRequestPermissionList.add(permission);
            }
        }
        return needRequestPermissionList;
    }


    /**
     * 系統(tǒng)請(qǐng)求權(quán)限回調(diào)
     *
     * @param requestCode
     * @param permissions
     * @param grantResults
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_CODE_PERMISSION) {
            if (verifyPermissions(grantResults)) {
                permissionSuccess(REQUEST_CODE_PERMISSION);
            } else {
                permissionFail(REQUEST_CODE_PERMISSION);
                showTipsDialog();
            }
        }
    }

    /**
     * 確認(rèn)所有的權(quán)限是否都已授權(quán)
     *
     * @param grantResults
     * @return
     */
    private boolean verifyPermissions(int[] grantResults) {
        for (int grantResult : grantResults) {
            if (grantResult != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }

    /**
     * 顯示提示對(duì)話框
     */
    private void showTipsDialog() {
        new android.support.v7.app.AlertDialog.Builder(this)
                .setTitle("警告")
                .setMessage("需要必要的權(quán)限才可以正常使用該功能砖顷,您已拒絕獲得該權(quán)限。\n如果需要重新授權(quán)赃梧,您可以點(diǎn)擊“允許”按鈕進(jìn)入系統(tǒng)設(shè)置進(jìn)行授權(quán)")
                .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                    }
                })
                .setPositiveButton("確定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        startAppSettings();
                    }
                }).show();
    }

    /**
     * 啟動(dòng)當(dāng)前應(yīng)用設(shè)置頁(yè)面
     */
    private void startAppSettings() {
        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        intent.setData(Uri.parse("package:" + getPackageName()));
        startActivity(intent);
    }

    /**
     * 獲取權(quán)限成功
     *
     * @param requestCode
     */
    public void permissionSuccess(int requestCode) {
        Log.d(TAG, "獲取權(quán)限成功=" + requestCode);

    }

    /**
     * 權(quán)限獲取失敗
     *
     * @param requestCode
     */
    public void permissionFail(int requestCode) {
        Log.d(TAG, "獲取權(quán)限失敗=" + requestCode);
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末滤蝠,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子授嘀,更是在濱河造成了極大的恐慌物咳,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蹄皱,死亡現(xiàn)場(chǎng)離奇詭異览闰,居然都是意外死亡芯肤,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門压鉴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)崖咨,“玉大人,你說(shuō)我怎么就攤上這事油吭〈疲” “怎么了嘲碧?”我有些...
    開封第一講書人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我分瘦,道長(zhǎng)襟沮,這世上最難降的妖魔是什么身辨? 我笑而不...
    開封第一講書人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任障簿,我火速辦了婚禮,結(jié)果婚禮上蟹腾,老公的妹妹穿的比我還像新娘痕惋。我一直安慰自己,他們只是感情好娃殖,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開白布血巍。 她就那樣靜靜地躺著,像睡著了一般珊随。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上柿隙,一...
    開封第一講書人閱讀 52,158評(píng)論 1 308
  • 那天叶洞,我揣著相機(jī)與錄音,去河邊找鬼禀崖。 笑死衩辟,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的波附。 我是一名探鬼主播艺晴,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼掸屡!你這毒婦竟也來(lái)了封寞?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤仅财,失蹤者是張志新(化名)和其女友劉穎狈究,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體盏求,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡抖锥,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年亿眠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片磅废。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡纳像,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出拯勉,到底是詐尸還是另有隱情竟趾,我是刑警寧澤,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布谜喊,位于F島的核電站潭兽,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏斗遏。R本人自食惡果不足惜山卦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望诵次。 院中可真熱鬧账蓉,春花似錦、人聲如沸逾一。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)遵堵。三九已至箱玷,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間陌宿,已是汗流浹背锡足。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留壳坪,地道東北人舶得。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像爽蝴,于是被迫代替她去往敵國(guó)和親沐批。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359

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