JNI 常見用法

一杨何、Java 代碼 和JNI代碼通信

Java代碼通過(guò)JNI接口 調(diào)用 C/C++方法

1、首先我們需要在Java代碼中聲明Natvie方法原型

public native void helloJNI(String msg);

2阎肝、其次我們需要在C/C++代碼里聲明JNI方法的原型
如:

extern "C"
JNIEXPORT void JNICALL
Java_com_kgdwbb_jnistudy_MainActivity_helloJNI(JNIEnv* env, jobject thiz,jstring msg) {
    //do something
}
  • extern "C"渐北。JNI函數(shù)聲明聲明代碼是用C++語(yǔ)言寫的筛璧,所以需要添加extern "C"聲明;如果源代碼是C語(yǔ)言聲明骡男,則不需要添加這個(gè)聲明
  • JNIEXPORT淆游。這個(gè)關(guān)鍵字表明這個(gè)函數(shù)是一個(gè)可導(dǎo)出函數(shù)。每一個(gè)C/C++庫(kù)都有一個(gè)導(dǎo)出函數(shù)列表,只有在這個(gè)列表里面的函數(shù)才可以被外部直接調(diào)用稽犁,類似Java的public函數(shù)和private函數(shù)的區(qū)別焰望。
  • JNICALL。說(shuō)明這個(gè)函數(shù)是一個(gè)JNI函數(shù)已亥,用來(lái)和普通的C/C++函數(shù)進(jìn)行區(qū)別熊赖。
  • Void 返回值類型
  • JNI函數(shù)名原型:Java_ + JNI方法所在的完整的類名,把類名里面的”.”替換成”_” + 真實(shí)的JNI方法名虑椎,這個(gè)方法名要和Java代碼里面聲明的JNI方法名一樣震鹉。
  • env 參數(shù) 是一個(gè)執(zhí)行JNIENV函數(shù)表的指針。
  • thiz 參數(shù) 代表的是聲明這個(gè)JNI方法的Java類的引用捆姜。
  • msg 參數(shù)就是和Java聲明的JNI函數(shù)的msg參數(shù)對(duì)于的JNI函數(shù)參數(shù)

靜態(tài)JNI方法 和實(shí)例JNI方法的區(qū)別

Java代碼:

public native void showHello();
public native static void showHello2();

C++代碼:

extern "C"
JNIEXPORT void JNICALL
Java_com_kgdwbb_jnistudy_MainActivity_showHello(JNIEnv* env, jobject thiz) {
    //do something
}

extern "C"
JNIEXPORT void JNICALL
Java_com_kgdwbb_jnistudy_MainActivity_showHello2(JNIEnv* env, jclass thiz) {
    //do something
}

二传趾、java 和JNI類型對(duì)照表

Java 和JNI基本類型對(duì)照表

java的基本類型可以直接與C/C++的基本類型映射。

image

Java與JNI引用類型對(duì)照表

與Java基本類型不同泥技,引用類型對(duì)開發(fā)人員是不透明的浆兰。Java內(nèi)部數(shù)據(jù)結(jié)構(gòu)并不直接向原生代碼開放。也就是說(shuō) C/C++代碼并不能直接訪問Java代碼的字段和方法

image

三珊豹、JNI 基本操作舉例

1簸呈、JNI操作 字符串

java 類 TestNatvie.java

  /**
     * 字符串相關(guān)測(cè)試代碼
     * @param str
     */
    public native void testJstring(String str);

C++文件 natvie-lib.cpp

extern "C"
JNIEXPORT void JNICALL
Java_com_example_feifei_testjni_TestNatvie_testJstring(JNIEnv *env, jobject instance,
                                                       jstring str_) {
    
  //(1)生成JNI String
    char const * str = "hello world!";
    jstring  jstring = env->NewStringUTF(str);

    // (2) jstring 轉(zhuǎn)換成 const char * charstr
    const char *charstr = env->GetStringUTFChars(str_, 0);
    // (3) 釋放 const char *
    env->ReleaseStringUTFChars(str_, charstr);

    //(4) 獲取字符串子集
    char * subStr = new char;
    env->GetStringUTFRegion(str_,0,3,subStr);//截取字符串char*;


    env->ReleaseStringUTFChars(str_, subStr);
    
}

2、JNI操作數(shù)組

java 類 TestNatvie.java

 /**
     * 整形數(shù)組相關(guān)代碼
     * @param array
     */
    public native void testIntArray(int []array);

    /**
     *
     * Object Array 相關(guān)測(cè)試 代碼
     * @param strArr
     */
    public native void testObjectArray(String[]strArr);

C++文件 natvie-lib.cpp

extern "C"
JNIEXPORT void JNICALL
Java_com_example_feifei_testjni_TestNatvie_testIntArray(JNIEnv *env, jobject instance,
                                                     jintArray array_) {

    //----獲取數(shù)組元素
    //(1)獲取數(shù)組中元素
    jint * intArray = env->GetIntArrayElements(array_,NULL);

    int len = env->GetArrayLength(array_);//(2)獲取數(shù)組長(zhǎng)度

    LOGD("feifei len:%d",len);

    for(int i = 0; i < len;i++){
        jint item = intArray[i];
        LOGD("feifei item[%d]:%d",i,item);
    }

    env->ReleaseIntArrayElements(array_, intArray, 0);

    //----- 獲取子數(shù)組
    jint *subArray = new jint;
    env->GetIntArrayRegion(array_,0,3,subArray);
    for(int i = 0;i<3;i++){
        subArray[i]= subArray[i]+5;
        LOGD("feifei subArray:[%d]:",subArray[i]);
    }

    //用子數(shù)組修改原數(shù)組元素
    env->SetIntArrayRegion(array_,0,3,subArray);

    env->ReleaseIntArrayElements(array_,subArray,0);//釋放子數(shù)組元素


}
extern "C"
JNIEXPORT void JNICALL
Java_com_example_feifei_testjni_TestNatvie_testObjectArray(JNIEnv *env, jobject instance,

                                                           jobjectArray strArr) {
    //獲取數(shù)組長(zhǎng)度
    int len = env->GetArrayLength(strArr);
    for(int i = 0;i< len;i++){
        //獲取Object數(shù)組元素
        jstring item = (jstring)env->GetObjectArrayElement(strArr,i);

        const char * charStr = env->GetStringUTFChars(item, false);
        LOGD("feifei strArray item:%s",charStr);

        jstring jresult = env->NewStringUTF("HaHa");
        //設(shè)置Object數(shù)組元素
        env->SetObjectArrayElement(strArr,i,jresult);
        env->ReleaseStringUTFChars(item,charStr);
    }

}

3店茶、JNI 訪問Java類的方法和字段

JNI 中訪問java類的方法和字段都是 通過(guò)反射來(lái)實(shí)現(xiàn)的蜕便。

JNI獲取Java類的方法ID和字段ID,都需要一個(gè)很重要的參數(shù),就是Java類的方法和字段的簽名

image

JNI 中訪問Java對(duì)象的屬性 和方法:

java 類 TestNatvie.java

public class TestNatvie {
    static {
        System.loadLibrary("native-lib");
    }
    
     /**
     * Jni調(diào)用 java 對(duì)象方法
     */
    public native void testCallJavaMethod();
      /**
     * Jni 調(diào)用 java static 方法
     */
    public native void testCallStaticJavaMethod();
     /**
     * JNI 訪問 java 的對(duì)象屬性和類屬性
     * @param student
     */
    public native void getJavaObjectField(Student student);
    
     public void helloworld(String msg){
        Log.d("feifei","hello world:"+msg);
    }

    public static void helloworldStatic(String msg){
        Log.d("feifei","hello world:"+msg);
    }

}

C++ 類 natvie-lib.cpp

extern "C"
JNIEXPORT void JNICALL
Java_com_example_feifei_testjni_TestNatvie_testCallJavaMethod(JNIEnv *env, jobject instance) {


    //獲取類名
    jclass  clazz = env->GetObjectClass(instance);
    if(clazz == NULL) return;

    jmethodID  javaMethod = env->GetMethodID(clazz,"helloworld","(Ljava/lang/String;)V");
    if(javaMethod == NULL)return;
    const char * msg = "nancy";
    jstring  jmsg = env->NewStringUTF(msg);
    env->CallVoidMethod(instance,javaMethod,jmsg);

}

extern "C"
JNIEXPORT void JNICALL
Java_com_example_feifei_testjni_TestNatvie_testCallStaticJavaMethod(JNIEnv *env, jobject instance) {

    //獲取java類型
    jclass clazz = env->GetObjectClass(instance);
    if(clazz == NULL) return;
    jmethodID staticMethod = env->GetStaticMethodID(clazz,"helloworldStatic","(Ljava/lang/String;)V");
    if(staticMethod == NULL) return;

    jstring jmsg = env->NewStringUTF("wangfeng");
    env->CallStaticVoidMethod(clazz,staticMethod,jmsg);

}

extern "C"
JNIEXPORT void JNICALL
Java_com_example_feifei_testjni_TestNatvie_getJavaObjectField(JNIEnv *env, jobject instance,
                                                              jobject student) {

    jclass  clazz = env->GetObjectClass(student);
    if(clazz == NULL )return;

    // 獲取Object 實(shí)例屬性
    jfieldID  nameId = env->GetFieldID(clazz,"name","Ljava/lang/String;");
    jstring jname = (jstring)env->GetObjectField(student,nameId);

    jfieldID  ageId = env->GetFieldID(clazz,"age","I");
    jint jage = env->GetIntField(student,ageId);

    const char * name = env->GetStringUTFChars(jname,false);
    env->ReleaseStringUTFChars(jname,name);


    //獲取java 類屬性:

    jfieldID  gradeId = env->GetStaticFieldID(clazz,"grade","I");
    jint  jgrade = env->GetStaticIntField(clazz,gradeId);

    jfieldID  nickeNameID = env->GetStaticFieldID(clazz,"nickname","Ljava/lang/String;");
    jstring  jnickname = (jstring)env->GetStaticObjectField(clazz,nickeNameID);

    const char * nickeName = env->GetStringUTFChars(jnickname, false);
    env->ReleaseStringUTFChars(jnickname,nickeName);

    LOGD("feifei name:%s,age:%d,grade:%d,nickname:%s",name,jage,jgrade,nickeName);

    //JNI 設(shè)置 java對(duì)象屬性
    env->SetObjectField(student,nameId,env->NewStringUTF("張三"));
    //JNI 設(shè)置 java 類屬性
    env->SetStaticObjectField(clazz,nickeNameID,env->NewStringUTF("小白"));
    jstring jnameNew = (jstring)env->GetObjectField(student,nameId);
    jstring jnickNameNew = (jstring)env->GetStaticObjectField(clazz,nickeNameID);

    const char * newName = env->GetStringUTFChars(jnameNew, false);
    const char *newNickName = env->GetStringUTFChars(jnickNameNew, false);

    env->ReleaseStringUTFChars(jnameNew,newName);
    env->ReleaseStringUTFChars(jnickNameNew,newName);
    LOGD("feifei after update name:%s,age:%d,grade:%d,nickname:%s",newName,jage,jgrade,newNickName);

}

4贩幻、JNI對(duì)象的全局引用和局部引用

Java代碼的內(nèi)存是由垃圾回收器來(lái)管理轿腺,而JNI代碼則不受Java的垃圾回收器來(lái)管理。所以JNI代碼提供了一組函數(shù)丛楚,來(lái)管理通過(guò)JNI代碼生成的JNI對(duì)象族壳,比如jobject,jclass鸯檬,jstring决侈,jarray等。

JNI對(duì)象的局部引用

在JNI接口函數(shù)中引用JNI對(duì)象的局部變量喧务,都是對(duì)JNI對(duì)象的局部引用,一旦JNI接口函數(shù)返回枉圃,所有這些JNI對(duì)象都會(huì)被自動(dòng)釋放功茴。
不過(guò)我們也可以采用JNI代碼提供的DeleteLocalRef函數(shù)來(lái)刪除一個(gè)局部JNI對(duì)象引用。

 //聲明局部變量clazz
    jclass clazz = env->GetObjectClass(instance);

    //手動(dòng)釋放 局部變量 clazz ;DeleteLocalRef 也可不用手動(dòng)調(diào)用孽亲,JNI方法返回之后坎穿,會(huì)自動(dòng)釋放局部JNI變量
    env->DeleteLocalRef(clazz);

JNI對(duì)象的全局引用

JNI對(duì)象的全局引用分為兩種,一種是強(qiáng)全局引用,這種引用會(huì)阻止Java的垃圾回收器回收J(rèn)NI代碼引用的Java對(duì)象玲昧,另一種是弱全局引用栖茉,這種全局引用則不會(huì)阻止垃圾回收器回收J(rèn)NI代碼引用的Java對(duì)象。

1孵延、強(qiáng)全局引用
  • NewGlobalRef用來(lái)創(chuàng)建強(qiáng)全局引用的JNI對(duì)象
  • DeleteGlobalRef用來(lái)刪除強(qiáng)全局引用的JNI對(duì)象
2吕漂、弱全局引用
  • NewWeakGlobalRef用來(lái)創(chuàng)建弱全局引用的JNI對(duì)象
  • DeleteWeakGlobalRef用來(lái)刪除弱全局引用的JNI對(duì)象
  • IsSameObject用來(lái)判斷兩個(gè)JNI對(duì)象是否相同

Java類 TestNatvie.java

  /**
     * 測(cè)試 JNI 強(qiáng)全局引用 和弱全局引用
     */
    public native void testJNIReference(Object object);

C++ 代碼 natvie-lib.cpp


/**
 * (1)在JNI接口函數(shù)中引用JNI對(duì)象的局部變量,都是對(duì)JNI對(duì)象的局部引用尘应,一旦JNI接口函數(shù)返回惶凝,所有這些JNI對(duì)象都會(huì)被自動(dòng)釋放。不過(guò)我們也可以采用JNI代碼提供的DeleteLocalRef函數(shù)來(lái)刪除一個(gè)局部JNI對(duì)象引用
 * (2)對(duì)于JNI對(duì)象犬钢,絕對(duì)不能簡(jiǎn)單的聲明一個(gè)全局變量苍鲜,在JNI接口函數(shù)里面給這個(gè)全局變量賦值這么簡(jiǎn)單,一定要使用JNI代碼提供的管理JNI對(duì)象的函數(shù).
 *  JNI 全局引用分為兩種: 一種全局引用,這種引用會(huì)阻止Java垃圾回收器回收J(rèn)NI代碼引用的對(duì)象玷犹;
 *  另一種是弱全局引用混滔,這種全局引用不會(huì)阻止垃圾回收器回收J(rèn)NI 代碼引用的Java對(duì)象
 *  - NewGlobalRef用來(lái)創(chuàng)建強(qiáng)全局引用的JNI對(duì)象
 *  - DeleteGlobalRef用來(lái)刪除強(qiáng)全局引用的JNI對(duì)象
 *  - NewWeakGlobalRef用來(lái)創(chuàng)建弱全局引用的JNI對(duì)象
 *  - DeleteWeakGlobalRef用來(lái)刪除弱全局引用的JNI對(duì)象
 *  - IsSameObject用來(lái)判斷兩個(gè)JNI對(duì)象是否相同
 */

jobject  gThiz; //全局JNI對(duì)象引用
jobject  gWeakThiz;//全局JNI對(duì)象弱應(yīng)用
extern "C"
JNIEXPORT void JNICALL
Java_com_example_feifei_testjni_TestNatvie_testJNIReference(JNIEnv *env, jobject instance,jobject obj) {


    //聲明局部變量clazz
    jclass clazz = env->GetObjectClass(instance);

    //手動(dòng)釋放 局部變量 clazz ;DeleteLocalRef 也可不用手動(dòng)調(diào)用,JNI方法返回之后歹颓,會(huì)自動(dòng)釋放局部JNI變量
    env->DeleteLocalRef(clazz);

    //---- 強(qiáng)全局變量
    gThiz = env->NewGlobalRef(obj);//生成全局的JNI 對(duì)象引用,這樣生成的全局的JNI對(duì)象 才可以在其他函數(shù)中使用

    env->DeleteGlobalRef(gThiz);//在我們不需要gThis這個(gè)全局JNI對(duì)象應(yīng)用時(shí)坯屿,可以將其刪除。

    //---- 全局弱引用
    gWeakThiz = env->NewWeakGlobalRef(obj);//生成全局的JNI對(duì)象引用晴股,這樣生成的全局的JNI對(duì)象才可以在其它函數(shù)中使用

    if(env->IsSameObject(gWeakThiz,NULL)){
        LOGD("全局弱引用 已經(jīng)被釋放了");
    }

    //釋放 全局弱應(yīng)用對(duì)象
    env->DeleteWeakGlobalRef(gWeakThiz);

}

5愿伴、JNI 進(jìn)程間同步

JNI可以使用Java對(duì)象進(jìn)行線程同步

  • MonitorEnter函數(shù)用來(lái)鎖定Java對(duì)象
  • MonitorExit函數(shù)用來(lái)釋放Java對(duì)象鎖

Java類 TestNative.java

  /**
     * JNI 利用 java 對(duì)象進(jìn)行線程同步
     * @param lock
     */
    public native void testJNILock(Object lock);

C++ 類 native-lib.cpp

extern "C"
JNIEXPORT void JNICALL
Java_com_example_feifei_testjni_TestNatvie_testJNILock(JNIEnv *env, jobject instance,
                                                       jobject lock) {

    //加鎖
    env->MonitorEnter(lock);

    //doSomething
    LOGD("feifei, this is in lock");

    //釋放鎖
    env->MonitorExit(lock);

}

6、JNI異常相關(guān)的函數(shù)

JNI處理Java異常

當(dāng)JNI函數(shù)調(diào)用的Java方法出現(xiàn)異常的時(shí)候电湘,并不會(huì)影響JNI方法的執(zhí)行隔节,但是我們并不推薦JNI函數(shù)忽略Java方法出現(xiàn)的異常繼續(xù)執(zhí)行,這樣可能會(huì)帶來(lái)更多的問題寂呛。我們推薦的方法是怎诫,當(dāng)JNI函數(shù)調(diào)用的Java方法出現(xiàn)異常的時(shí)候,JNI函數(shù)應(yīng)該合理的停止執(zhí)行代碼贷痪。

  • ExceptionOccurred函數(shù)用來(lái)判斷JNI函數(shù)調(diào)用的Java方法是否出現(xiàn)異常
  • ExceptionClear函數(shù)用來(lái)清除JNI函數(shù)調(diào)用的Java方法出現(xiàn)的異常
/**
     *  1幻妓、env->ExceptionOccurred() 判斷JNI調(diào)用java方法 是否遇到了Exception
     *  2、env->ThrowNew() JNI 可以主動(dòng)拋出Java Exception異常
     */
    public native void testJavaException();

C++ 類 native-lib.cpp

extern "C"
JNIEXPORT void JNICALL
Java_com_example_feifei_testjni_TestNatvie_testJavaException(JNIEnv *env, jobject instance) {

    jclass  clazz = env->GetObjectClass(instance);
    if(clazz == NULL) return;

    jmethodID helloException_method  = env->GetMethodID(clazz,"helloException","()V");
    if(helloException_method == NULL )return;
    env->CallVoidMethod(instance,helloException_method);
    if(env->ExceptionOccurred() != NULL){
//        env->ExceptionDescribe();
        env->ExceptionClear();
        LOGD("feifei,調(diào)用java 方法時(shí) 遇到了Exception");
        return;

    }
    LOGD("feifei,調(diào)用helloException 方法成功了!");

    LOGD("feifei,now JNI throw java exception - beging");
    jclass  expetionClazz = env->FindClass("java/lang/Exception");
    if(expetionClazz == NULL) return;
    env->ThrowNew(expetionClazz,"this is a exception");

}

JNI拋出Java類型的異常

JNI通過(guò)ThrowNew函數(shù)拋出Java類型的異常

Java類 TestNative.java

 LOGD("feifei,now JNI throw java exception - beging");
    jclass  expetionClazz = env->FindClass("java/lang/Exception");
    if(expetionClazz == NULL) return;
    env->ThrowNew(expetionClazz,"this is a exception");

四 JNI 和 Java對(duì)象的互相持有

Java對(duì)象持久化C/C++對(duì)象實(shí)例

通常的做法是 將C++對(duì)象指針 強(qiáng)轉(zhuǎn)為jlong 類型劫拢,保存在調(diào)用者java對(duì)象的long型變量中肉津,一直持有。
當(dāng)需要使用該C++對(duì)象時(shí),從Java對(duì)象中的long變量舱沧,強(qiáng)轉(zhuǎn)化為C++對(duì)象,進(jìn)而使用妹沙。

TestNative.java

public class TestNatvie {
    static {
        System.loadLibrary("native-lib");
    }

    /**
     * 用戶保存 C++對(duì)象的引用
     */
    private long mNatvieId;
    /**
     * Java 對(duì)象持有 C++對(duì)象
     */
    public native void initSDK();

    /**
     * Java 對(duì)象釋放 C++對(duì)象
     */
    public native void releasSDK();

}

native-lib.cpp

extern "C"
JNIEXPORT void JNICALL
Java_com_example_feifei_testjni_TestNatvie_initSDK(JNIEnv *env, jobject instance) {

    Person * person = new Person();
    person->setAge(18);
    person->initSDK();

    jclass classzz = env->GetObjectClass(instance);
    jfieldID fid = env->GetFieldID(classzz,"mNatvieId","J");

    //將C++對(duì)象的地址綁定到Java變量中
    env->SetLongField(instance,fid,(jlong)person);


}
extern "C"
JNIEXPORT void JNICALL
Java_com_example_feifei_testjni_TestNatvie_releasSDK(JNIEnv *env, jobject instance) {

    jclass objectClass = env->GetObjectClass(instance);
    jfieldID fid = env->GetFieldID(objectClass,"mNatvieId","J");

    //取出java對(duì)象中保存的C++對(duì)象地址
    jlong  p = env->GetLongField(instance,fid);

    //轉(zhuǎn)換成 C++對(duì)象
    Person * person = (Person*)p;
    person->releaseSDK();
    //釋放person C++對(duì)象
    free(person);
    env->SetLongField(instance,fid,-1);
}


C/C++ 持久化Java對(duì)象

一般做法是

  • 在本地方式中,創(chuàng)建一個(gè)全局引用 保存java對(duì)象:
 env->NewGlobalRef(obj);

這樣在其他的JNI方法中就可以任意的使用該java對(duì)象了熟吏。

  • 在不需要改java對(duì)象時(shí)距糖,再將JNI全局引用刪除即可玄窝。

 env->DeleteGlobalRef(gThiz);

使用示例:

TestNative.cpp

  /**
     * 利用JNI全局引用持有java 對(duì)象
     */
    public native void testJNIReference(Object object);

natvie-lib.cpp

jobject  gThiz; //全局JNI對(duì)象引用 - 用于持有特定的java對(duì)象。
jobject  gWeakThiz;//全局JNI對(duì)象弱應(yīng)用
extern "C"
JNIEXPORT void JNICALL
Java_com_example_feifei_testjni_TestNatvie_testJNIReference(JNIEnv *env, jobject instance,jobject obj) {



    //---- 強(qiáng)全局變量
    gThiz = env->NewGlobalRef(obj);//生成全局的JNI 對(duì)象引用,這樣生成的全局的JNI對(duì)象 才可以在其他函數(shù)中使用

    env->DeleteGlobalRef(gThiz);//在我們不需要gThis這個(gè)全局JNI對(duì)象應(yīng)用時(shí)悍引,可以將其刪除恩脂。

  

}

參考文章

JNI入門教程

JNI實(shí)例

JNI 函數(shù)大全

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市趣斤,隨后出現(xiàn)的幾起案子俩块,更是在濱河造成了極大的恐慌,老刑警劉巖唬渗,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件典阵,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡镊逝,警方通過(guò)查閱死者的電腦和手機(jī)壮啊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)撑蒜,“玉大人歹啼,你說(shuō)我怎么就攤上這事∽ぃ” “怎么了狸眼?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)浴滴。 經(jīng)常有香客問我拓萌,道長(zhǎng),這世上最難降的妖魔是什么升略? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任微王,我火速辦了婚禮,結(jié)果婚禮上品嚣,老公的妹妹穿的比我還像新娘炕倘。我一直安慰自己,他們只是感情好翰撑,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布罩旋。 她就那樣靜靜地躺著,像睡著了一般眶诈。 火紅的嫁衣襯著肌膚如雪涨醋。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天逝撬,我揣著相機(jī)與錄音东帅,去河邊找鬼。 笑死球拦,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播坎炼,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼愧膀,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了谣光?” 一聲冷哼從身側(cè)響起檩淋,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎萄金,沒想到半個(gè)月后蟀悦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡氧敢,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年日戈,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片孙乖。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡浙炼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出唯袄,到底是詐尸還是另有隱情弯屈,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布恋拷,位于F島的核電站资厉,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏蔬顾。R本人自食惡果不足惜宴偿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望阎抒。 院中可真熱鬧酪我,春花似錦、人聲如沸且叁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)逞带。三九已至欺矫,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間展氓,已是汗流浹背穆趴。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留遇汞,地道東北人未妹。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓簿废,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親络它。 傳聞我的和親對(duì)象是個(gè)殘疾皇子族檬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

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