学习NDK开发,一方面是掌握Java和C/C++互相调用,另一方面是掌握C/C++语言本身的基础;因此我觉得入门的最好方式就是使用C/C++构建数据结构,然后存储数据;这样既可以掌握一些C++语言本身的基础知识,又可以掌握一些Java和C/C++对象的互相调用的方法。
本次项目是在Android Studio中构建的。
首先,我新建一个Java类,
public class LinkList {
static {
System.loadLibrary("native-linklist");
}
public LinkList(){
init();
}
public native void init();
public native void add(int key,String value);
public native int size();
public native Node next();
public native void prenext();
public native boolean hasnext();
public native String get(int key);
}
然后在cpp文件中新建和它对象的h文件
#include "jni.h"
#include "list.h"
#include <stdlib.h>
#include <string>
#ifndef JNIEXAMPLE_NATIVE_LINKLIST_H
#define JNIEXAMPLE_NATIVE_LINKLIST_H
extern "C"{
using namespace std;
Node *startNode= nullptr,*endNode= nullptr,*nextNode= nullptr;
int count=0;
JNIEXPORT void JNICALL Java_com_xuye_xy_socket_jni_LinkList_init(JNIEnv *,jobject);
JNIEXPORT void JNICALL Java_com_xuye_xy_socket_jni_LinkList_add(JNIEnv *,jobject,jint ,jstring);
JNIEXPORT jint JNICALL Java_com_xuye_xy_socket_jni_LinkList_size(JNIEnv *,jobject);
JNIEXPORT jobject JNICALL Java_com_xuye_xy_socket_jni_LinkList_next(JNIEnv *,jobject);
JNIEXPORT void JNICALL Java_com_xuye_xy_socket_jni_LinkList_prenext(JNIEnv *,jobject);
JNIEXPORT jboolean JNICALL Java_com_xuye_xy_socket_jni_LinkList_hasnext(JNIEnv *,jobject);
JNIEXPORT jstring JNICALL Java_com_xuye_xy_socket_jni_LinkList_get(JNIEnv *,jobject,jint);
jobject newNode(JNIEnv *env,int key, const char *value);
};
这个是Node类如下:
#include "jni.h"
#ifndef JNIEXAMPLE_LIST_H
#define JNIEXAMPLE_LIST_H
extern "C"{
class Node{
public:
Node *next,*pre;
Node(){
this->key=0;
this->value= nullptr;
};
Node(int key, const char* value){
this->key=key;
this->value=value;
};
~Node(){};
int getkey(){
return this->key;
}
const char* getvalue(){
return this->value;
};
void set(int key, const char* value){
this->key=key;
this->value=value;
}
private:
int key;
const char *value;
};
};
#endif //JNIEXAMPLE_LIST_H
然后是实现:
#include"native-linklist.h"
JNIEXPORT void JNICALL Java_com_xuye_xy_socket_jni_LinkList_init(JNIEnv *env,jobject thiz){
startNode=new Node();
endNode=new Node();
nextNode=new Node();
nextNode->next=startNode;
startNode->next=endNode;
startNode->pre= nullptr;
endNode->pre=startNode;
endNode->next= nullptr;
}
JNIEXPORT void JNICALL Java_com_xuye_xy_socket_jni_LinkList_add(JNIEnv *env,jobject thiz,jint jst,jstring obj){
count++;
int key=jst;
const char *value=env->GetStringUTFChars(obj,JNI_FALSE);
if(startNode->getvalue()== nullptr){
startNode->set(key,value);
}else{
Node *elem=new Node(key,value);
elem->next=endNode;
elem->pre=endNode->pre;
endNode->pre->next=elem;
endNode->pre=elem;
}
}
JNIEXPORT jint JNICALL Java_com_xuye_xy_socket_jni_LinkList_size(JNIEnv *env,jobject thiz){
return count;
}
JNIEXPORT jobject JNICALL Java_com_xuye_xy_socket_jni_LinkList_next(JNIEnv *env,jobject thiz){
if(nextNode!= nullptr&&nextNode->next!= nullptr&&nextNode->next->getvalue()!= nullptr){
const char *value=nextNode->next->getvalue();
int key=nextNode->next->getkey();
jobject nodeobj=newNode(env,key,value);
nextNode->next=nextNode->next->next;//下一个
return nodeobj;
}
return nullptr;
}
JNIEXPORT void JNICALL Java_com_xuye_xy_socket_jni_LinkList_prenext(JNIEnv *env,jobject obj){
nextNode=new Node();
nextNode->next=startNode;
}
JNIEXPORT jboolean JNICALL Java_com_xuye_xy_socket_jni_LinkList_hasnext(JNIEnv *env,jobject thiz){
if(nextNode!= nullptr&&nextNode->next!= nullptr&&nextNode->next->getvalue()!= nullptr){
return true;
}
return false;
}
JNIEXPORT jstring JNICALL Java_com_xuye_xy_socket_jni_LinkList_get(JNIEnv *env,jobject thiz,jint key){
Node *temp=new Node();
temp->next=startNode;
while (temp->next!= nullptr){
if(temp->next->getkey()==key)
return env->NewStringUTF(temp->next->getvalue());
temp=temp->next;
}
return nullptr;
}
jobject newNode(JNIEnv *env,int key, const char *value){
jclass nodeclass=env->FindClass("com/xuye/xy/socket/java/Node");//获取到Node类
jmethodID nodeinit=env->GetMethodID(nodeclass,"<init>","()V");//获取到Node实例化方法
jmethodID nodesetkey=env->GetMethodID(nodeclass,"setKey","(I)V");//获取到设置Key的方法
jmethodID nodesetvalue=env->GetMethodID(nodeclass,"setValue","(Ljava/lang/String;)V");//获取到设置value的方法
jobject nodeobj=env->NewObject(nodeclass,nodeinit);//创建一个新的Node
env->CallVoidMethod(nodeobj,nodesetkey,key);//设置key
jstring valuestr=env->NewStringUTF(value);
env->CallVoidMethod(nodeobj,nodesetvalue,valuestr);//设置value
return nodeobj;
}
MainActivity的调用:
private LinkList list;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Example of a call to a native method
TextView tv = (TextView) findViewById(R.id.sample_text);
list=new LinkList();
for(int i=0;i<1000;i++){
list.add(i,new String("第"+i+"个"));
}
list.prenext();
StringBuilder builder=new StringBuilder();
while (list.hasnext()){
Node node=list.next();
node.log();
}
tv.setText(list.get(5));
}
执行后打印结果如下:
在这里对于基础学习有2个地方需要注意:
第一个是在构建对应的.h文件时,可以利用javah命令生成和Java对应的.h文件;
第二个是在需要调用Java对象或者方法的时候,可以利用javap命令获取到签名,在C中进行调用。