Android studio中NDK开发—回调更新 UI 方法

Android studio中NDK开发—回调更新 UI 方法

Demo下载

https://github.com/linweimao/NDK-C-Java-

运行报错: CCallJava\ccalljava0

运行不会报错: CCallJava\app

ccalljava0:日志打印了,Toast奔了
在这里插入图片描述
在这里插入图片描述
日志打印了就说明(showToast)这个方法确实被调用了

报的错误是空指针异常(NullPointerException)

为什么会出错呢?

启动一个 Activity 是通过 startActivity 进行启动,通过 startActivity 启动的Activity 就有Activity 的生命周期,如果通过new的方式去new 一个 Activity ,那么Activity 没有生命周期,就是一个普通类。

那么因为反射的方式去把 MainActivity 这个类 new 出来,那么它就没有 Activity 的生命周期,那么同时就没有Activity的上下文,那么这里实例化的这个类(MainActivity.this)就不是上下文了

Toast.makeText(MainActivity.this, "showToast------", Toast.LENGTH_SHORT).show();

MainActivity 是一个 Activity 同时也是一个类,启动 startActivity,同时也可以new它(MainActivity ),new一个Activity (MainActivity)相当于把它当成普通类了。

原因就是在CCallJava中的反射实例化,把它 new 出来,new出来就不是上下文了 ,所以 Toast.makeText 去得到它的资源文件的时候就会空指针,因为它根本就不是一个上下文了

jclass jclazz = (*env)->FindClass(env, "com/lwm/ccalljava/MainActivity");

解决步骤:

  1. 将 JNITest 类中的 callBackShowToast() 方法剪切至 MainActivity 中

    /*
     * 当执行这个方法的时候,让 C 代码调用 MainActivity 里面的
     * public void showToast()方法
     *
     */
    public native void callBackShowToast();
    
  2. 调用该方法时相当于

    public void CallBackShowtoast() {
        //当我们调用 callbackAdd 方法,那么 callbackAdd 方法会通过C代码回调add方法
        //jniTest.callBackShowToast();//不用这个了,而直接用下面的
        MainActivity.this.callBackShowToast();
    }
    
  3. 重新创建 callBackShowToast() 方法的头文件在 CCallJava 中

    JNIEXPORT void JNICALL
    Java_com_lwm_ccalljava_MainActivity_callBackShowToast(JNIEnv *env, jobject instance)
    
  4. 复制上面的4个步骤至 Java_com_lwm_ccalljava_MainActivity_callBackShowToast 下,并且不用第三步的实例化**(此时的 instance 的实例是 MainActivity.this )**

    /*
     *
     * instance:谁调用了当前 Java_com_lwm_ccalljava_JNITest_callBackShowToast对应的Java接口,
     * 就是谁的实例:当前是 JNI.this(因为需要在 MainActivity中使用 jniTest.callBackShowToast()进行调用,此时为 jniTest 去调用,因此当前是 JNI.this)
     * 而现在的实例是 MainActivity.this
     *
     * (就相当于谁调用 JNITest 类中的callBackShowToast()方法,因为调用 callBackShowToast()方法才触发 Java_com_lwm_ccalljava_JNITest_callBackShowToast)
     */
    //在 MainActivity 下不用实例化了,直接使用传过来的 instance
    void Java_com_lwm_ccalljava_MainActivity_callBackShowToast(JNIEnv *env, jobject instance) {
        //让 C 代码调用 MainActivity 里面的 public void showToast()方法
        //1、得到字节码(字节码是用于实例化这个类)
        jclass jclazz = (*env)->FindClass(env, "com/lwm/ccalljava/MainActivity");
    
        //2、得到方法
        //GetMethodID()中最后一个参数是方法签名(这里需要MainActivity类的签名,调谁就用谁的签名,调用那个方法就用哪个方法中的类)
        //jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
        jmethodID jmethodIDs = (*env)->GetMethodID(env, jclazz, "showToast", "()V");
    
        //3、实例化该类
        //jobject     (*AllocObject)(JNIEnv*, jclass);
        //jobject jobject1 = (*env)->AllocObject(env,jclazz);
    
        //4.调用方法
        //void        (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
        (*env)->CallVoidMethod(env,instance,jmethodIDs);
        //成功调用了 public void showToast()方法
    }
    
发布了113 篇原创文章 · 获赞 8 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_42814000/article/details/105440561