Android NDK JNI C++ <7> eg

刚开始一直没有找到该系列的第五篇博客,郁闷的要死,本打算重写的,看来没必要了.那这一篇就相当于小结第五篇和第六篇使用的样例.

所有的NDK都是在Linux系统下开发的,jni C或者CPP文件这一篇开始是在windosws7 VC6.0中开发的.所以下面的新建Android项目之类的都是在我的Ubuntu12.04中进行的.

<1> : 首先新建一个Android工程androidjnicppdemo1,包名package com.org.androidjnicppdemo1;

<2> : 在工程下新建一个jnipack的包,在这个包下新建一个JniClass.java的文件,build后(一定要先生成class文件),在工程根目录下新建一个jni,让后让终端进入jni文件目录下执行:

javah -classpath ../bin/classes jnipack.JniClass

把生成的jnipack_JniClass.h名改为JniClass.h,不要包名.

<3> : 上面的操作和以前的没什么区别.让后启动VC6.0,VC6.0耗内存非常少,所以这个很快捷.新建一个console工程就可以了,然后新建一个JniClass.h的头文件和JniClass.cpp文件,将上面生成的JniClass.h文件内容拷贝VC同名下的文件中,然后具体实现在JniClass.cpp文件中实现.
截图如下:

JniClass.c代码如下:

#include "JniClass.h"

jclass mClass;
jobject mObject;
jmethodID mMethodID;
jmethodID mMethodAddID;
jfieldID mFieldID;

JNIEXPORT void JNICALL Java_jnipack_JniClass_nativeinit
(JNIEnv *env, jobject thiz){

    jclass cls=(*env)->GetObjectClass(env,thiz);
    mClass=(jclass)(*env)->NewGlobalRef(env,cls);
//    mClass=(jclass)(*env)->FindClass(env,"jnipack.JniClass");
    mObject=(jobject)(*env)->NewGlobalRef(env,thiz);

    mFieldID=(*env)->GetFieldID(env,mClass,"native_para","I");
    mMethodID=(*env)->GetMethodID(env,mClass,"SubJava","(II)I");

    mMethodAddID=(*env)->GetMethodID(env,mClass,"AddJava","(II)I");

}

JNIEXPORT jint JNICALL Java_jnipack_JniClass_Add
(JNIEnv *env, jobject thiz, jint a, jint b){

    jint res=0;

    jint para=0;
    para=(jint)(*env)->GetIntField(env,mObject,mFieldID);

    res=(*env)->CallIntMethod(env,mObject,mMethodAddID,a,(b+para));

    return res;

}

JNIEXPORT jstring JNICALL Java_jnipack_JniClass_getLibVersion
(JNIEnv *env, jobject thiz){
    
    return (*env)->NewStringUTF(env,"jnilibs : 1.0");
    
}

 补充上面的内容,传递数组的方法j*array,*代表int等数据类型:

java代码增加:

public native int AddArray(int[] arr);

Jni实现代码中:

JNIEXPORT jint JNICALL Java_jnipack_JniClass_AddArray(JNIEnv *env, jobject thiz,
        jintArray arr) {

    jint len = 5;
    jint i = 0;
    jint res = 0;
    jint *arri;
    arri = (*env)->GetIntArrayElements(env, arr, 0);

    for (i = 0; i < 5; i++) {
        res = res + arri[i];
    }

    return res;

}

调用:

 

<4> : 现在在上面的工程中继续添加一个CPP的程序:

plus.h:

#ifndef PLUS_HEADER_H__
#define PLUS_HEADER_H__

class cale{

public:
    cale(){};//不要添加virtual修饰符
    virtual ~cale(){};

    virtual int addplus(int a,int b);
    virtual char* showmsg();

};

#endif

plus.cpp:

#include "plus.h"

char* cale::showmsg(){
    return "cpp program !";
};

int cale::addplus(int a,int b){
    return a+b;
};


swig.i:

%module swig
%{
#include "plus.h"
%}
%include "plus.h"

swig.sh:

#!/bin/bash

swig -c++ -java -package orgcpp -outdir ../src/orgcpp -o plusplus.cpp swig.i


Android.mk:这个文件里面即有cpp又有c的文件,混合起来都可以build的,NB啊.

LOCAL_PATH :=$(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := jnilibs
LOCAL_SRC_FILES := JniClass.c plusplus.cpp plus.cpp
#LOCAL_CFLAGS    :=-frtti

include $(BUILD_SHARED_LIBRARY)


<5>应该没有了,运行脚本然后build后,调用如下:

package com.org.androidjnicppdemo1;

import orgcpp.cale;

import jnipack.JniClass;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends Activity implements OnClickListener{

    private Button mGetVerBtn;
    private Button mCallNativeAddBtn;
    private Button mCppBtn;
    
    private JniClass jClass=new JniClass();
    
//    private cale ce=new cale();
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        mGetVerBtn=(Button)findViewById(R.id.getver);
        mGetVerBtn.setOnClickListener(this);
        
        mCallNativeAddBtn=(Button)findViewById(R.id.callnativeadd);
        mCallNativeAddBtn.setOnClickListener(this);
        
        mCppBtn=(Button)findViewById(R.id.cpp);
        mCppBtn.setOnClickListener(this);
        
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public void onClick(View arg0) {
        // TODO Auto-generated method stub
        int id;
        id=arg0.getId();
        
        switch(id){
        case R.id.getver:
            Toast.makeText(this, "lib : "+jClass.getLibVersion(), Toast.LENGTH_SHORT).show();
            break;
        case R.id.callnativeadd:
            Toast.makeText(this, "native call : "+jClass.Add(16, 12), Toast.LENGTH_LONG).show();
            break;
        case R.id.cpp:
//            Toast.makeText(this, "cpp : "+ce.showmsg(), Toast.LENGTH_LONG).show();
            break;
        }
        
    }

}

 

综合上面:

<1> : jni回调java代码;

<2> : java调用jni的c代码;

<3> : java调用jni的c++代码;

<4> : 增加常量native_para传递和使用;


其他图片:

 

 

 

 

下一节开始jni多线程操作.

 

 

 

 

 

 

 

 

posted @ 2014-05-18 02:17  MMLoveMeMM  阅读(289)  评论(0)    收藏  举报