• ndk之C组件调用java方法和属性


         在ndk中,使用JNI_OnLoad方法进行java本地方法与C语言组件方法进行一一映射,然后使用C组件方法调用java的静态方法与非静态方法,静态属性与非静态属性。

    1.在eclipse新建androidNdkC的android工程,修改MainActivity.java代码如下

     

    package com.undergrowth.androidndkc;
    
    import com.undergrowth.android.R;
    
    import android.os.Bundle;
    import android.app.Activity;
    import android.util.Log;
    
    public class MainActivity extends Activity {
    
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_main);
    		 Manager manager=new Manager(MainActivity.this, 10, 20);
    	        manager.managerDisplay();
    	        Log.d("msg", MainActivity.class.getName());
    	}
    
    
    }
    


    含有本地方法的类 Manager.java

    package com.undergrowth.androidndkc;
    
    import android.content.Context;
    import android.util.Log;
    /*
     * 用于提供静态方法和非静态方法
     * 用于提供静态成员与非静态成员
     * 提供本地方法
     */
    public class Manager {
    	private Context context;//用于接受创建对象的上下文
    	public int numNot;
    	public static int num;
    	
    	public Manager(Context context,int num,int numNot)
    	{
    		this.context=context;
    		this.num=num;
    		this.numNot=numNot;
    		Log.d("msg", Manager.class.getName()+" is created!");
    		managerInit();
    	}
    	
    	//提供静态方法与非静态方法
    	public static void managerStaticMethod(int value)
    	{
    		Log.d("msg", "managerStaticMethod is called,value from c,value is "+value);
    	}
    	
    	public  void managerNotStaticMethod(int value)
    	{
    		Log.d("msg", "managerNotStaticMethod is called,value from c,value is "+value);
    	}
    	
    	public native void managerInit(); //本地方法用于初始化
        public native void managerDisplay(); //本地方法 用于显示 即在c语言中调用java代码
        
        //加载共享库 
        static{
        	try {
        		System.loadLibrary("manager");
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
        }
    }
    


    2.然后在项目androidNdkC中新建jni文件夹 新建android.mk文件

    LOCAL_PATH    :=$(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_LDLIBS    :=-llog
    LOCAL_MODULE    :=manager
    LOCAL_SRC_FILES    :=manager.c
    include $(BUILD_SHARED_LIBRARY) 
    


    这里说一下LOCAL_LDLIBS   :=-llog  表示需要在链接时用到调试的liblog.so文件

      在jni中新建manager.c文件  内容如下

    #include <jni.h>
    #include <android/log.h>
    #include <stdio.h>
    jclass cla;
    jmethodID aMethodId1,aMethodId2;
    jfieldID aFieldId1,aFieldId2;
    
    
    static void init(JNIEnv *env,jobject thiz)
    {
        jclass clazz=(*env)->GetObjectClass(env,thiz); //get class byte code: object.getClass()
        cla=(jclass)(*env)->NewGlobalRef(env,clazz);
        aMethodId1=(*env)->GetStaticMethodID(env,clazz,"managerStaticMethod","(I)V");//get static method
        aMethodId2=(*env)->GetMethodID(env,clazz,"managerNotStaticMethod","(I)V");//get non-static method
        aFieldId1=(*env)->GetStaticFieldID(env,clazz,"num","I"); //get static field
            aFieldId2=(*env)->GetFieldID(env,clazz,"numNot","I");  //get non-static field
    }
    
    static void display(JNIEnv *env,jobject thiz)
    {
        int num=(int)(*env)->GetStaticObjectField(env,cla,aFieldId1);
        int numNot=(int)(*env)->GetObjectField(env,thiz,aFieldId2);
        (*env)->CallStaticVoidMethod(env,cla,aMethodId1,(num+numNot));
        (*env)->CallVoidMethod(env,thiz,aMethodId2,(num-numNot));
    }
    
    
    
    static JNINativeMethod methods[]=
    {
        {"managerInit","()V",(void *)init },
        {"managerDisplay","()V",(void *)display},    
    };
    
    
    jint register_native_method(JNIEnv *env)
    {
        static char *className="com/undergrowth/androidndkc/Manager";
        jclass clazz;
        clazz=(*env)->FindClass(env,className);//similar to java reflect: Class.forName()
        if(clazz==NULL)
        {
            __android_log_print(ANDROID_LOG_DEBUG,"msg","can't find %s class.",className);
            return -1;
        }
        if((*env)->RegisterNatives(env,clazz,methods,sizeof(methods)/sizeof(methods[0]))!=JNI_OK)
        {
            __android_log_print(ANDROID_LOG_DEBUG,"msg","can not register native.");
            return -1;
        }
        return 0;
    
    }
    
    
    //in order to use JNI_VERSION_1_4 ,you must JNIEXPORT JNI_OnLoad and return JNI_VERSION_1_4
     jint JNI_OnLoad(JavaVM *vm,void *reserved) //when the native library load,the function willbe called by java vm
    {
        int result=-1; //-1 presentative unknown error
        JNIEnv *env=NULL;  //current thread jni function interface
        if((*vm)->GetEnv(vm,(void **)&env,JNI_VERSION_1_4)!=JNI_OK)
        {
            __android_log_print(ANDROID_LOG_DEBUG,"msg","JNI_OnLoad init error!!");
            return result;
        }
        if(register_native_method(env)!=0)
        {
            __android_log_print(ANDROID_LOG_DEBUG,"msg","register native failed!!");
            return result;
        }
        result=JNI_VERSION_1_4;
        return result;
    }
    


    然后在androidNdkC的目录中使用ndk-build工具 编译androidNdkC  显示信息如下:

     

    u1@u1:~/java/workspace/androidNdkC$ ndk-build
    Compile thumb  : manager <= manager.c
    SharedLibrary  : libmanager.so
    Install        : libmanager.so => libs/armeabi/libmanager.so
    

      
    3.运行 在LogCat中显示如下信息

     

    4.上面即是成功的效果 嗯 在整个过程中出了一些错误 如下

    08-28 15:12:37.916: W/dalvikvm(6885): JNI WARNING: jclass arg has wrong type
     (expected Ljava/lang/Class;, got Lcom/undergrowth/androidndkc/Manager;)
    08-28 15:12:37.944: W/dalvikvm(6885):   
               in Lcom/undergrowth/androidndkc/Manager;.managerDisplay:()V (GetStaticObjectField)
    

    嗯 出现如上错误 是因为 (*env)->GetStaticObjectField(env,cla,aFieldId1); 写成了 (*env)->GetStaticObjectField(env,thiz,aFieldId1);

       在获取静态成员或者静态方法的时候需要使用类的字节码才能获取

    08-28 15:21:18.015: W/dalvikvm(7235): JNI WARNING: 
    GetStaticObjectField for field 'num' of expected type L, got I
    08-28 15:21:18.025: W/dalvikvm(7235):          
        in Lcom/undergrowth/androidndkc/Manager;.managerDisplay:()V (GetStaticObjectField)
    

    出现这个错误 是因为版本问题 我试过 相同的代码 用2.2 2.3.3 4.0.3只有在2.2上是没有问题的 同时我也把数据类型换为其他的,也是相同的问题,所以想要上面的代码成功执行,必须要使用android2.2版本

    JNI的函数查询: http://game.ceeger.com/Script/AndroidJNI/AndroidJNI.GetStaticFieldID.html

  • 相关阅读:
    Java并发编程:并发容器之ConcurrentHashMap(转载)
    Java ConcurrentModificationException异常原因和解决方法
    Java并发编程:同步容器
    Java并发编程:深入剖析ThreadLocal
    错误:The POM for org.codehaus.plexus:plexus-compiler-api:jar:2.2 is invalid, transitive dependencies (if any) will not be available, enable debug logging for more details的解决方法
    maven工程中引入oracle驱动报错Missing artifact com.oracle:ojdbc14:jar:10.2.0.4.0
    部署时发出警告: [SetContextPropertiesRule]{Context} Setting property 'source' to 'org.eclipse.jst.jee.server:jx-web' did not find a matching property.的解决方法
    [WARNING] The POM for com.tao:jx-service:jar:0.0.1-SNAPSHOT is missing, no dependency information available
    maven工程中警告[WARNING] Using platform encoding (GBK actually) to copy filtered resources, i.e. build is platform dependent!
    Eclipse中Errors occurred during the build最简单的解决方法
  • 原文地址:https://www.cnblogs.com/liangxinzhi/p/4275607.html
Copyright © 2020-2023  润新知