现将native函数贴出来。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#define LOG_TAG "SCANER"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
#define ARRAY_LENGTH 1024
static int i = 0;
static JavaVM *gvm;
static jobject giface;
static const char *classPathName = "com/coder80/scaner/MainActivity";
static JNINativeMethod methods[] = {
{ "scanDir", "(Ljava/lang/String;)V", (void *)Java_com_coder80_scaner_MainActivity_scanDir},
{ "getPathArray", "(Ljava/lang/String;)[Ljava/lang/String;", (void *)Java_com_coder80_scaner_MainActivity_getPathArray},
{ "getTracksArray", "(Ljava/lang/String;)[Lcom/coder80/scaner/Track_Info;", (void *)Java_com_coder80_scaner_MainActivity_getTracksArray}
};
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
jclass clazz = NULL;
JNIEnv* env = NULL;
jmethodID constr = NULL;
jobject obj = NULL;
LOGE("JNI_OnLoad");
gvm = vm;
if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_4) != JNI_OK) {
LOGE("GetEnv FAILED");
return -1;
}
clazz = (*env)->FindClass(env,classPathName);
if (!clazz) {
LOGE("Registration unable to find class '%s'", classPathName);
return -1;
}
constr = (*env)->GetMethodID(env, clazz, "", "()V");
if (!constr) {
LOGE("Failed to get constructor");
return -1;
}
obj = (*env)->NewObject(env, clazz, constr);
if (!obj) {
LOGE("Failed to create an interface object");
return -1;
}
giface = (*env)->NewGlobalRef(env, obj);
if ((*env)->RegisterNatives(env, clazz, methods,
sizeof(methods) / sizeof(methods[0])) < 0) {
LOGE("Registration failed for '%s'", classPathName);
return -1;
}
return JNI_VERSION_1_4;
}
jobjectArray Java_com_coder80_scaner_MainActivity_getPathArray(JNIEnv *env, jobject obj, jstring jdirPath)
{
const char *dirPath = (*env)->GetStringUTFChars(env, jdirPath, NULL);
jclass objClass = (*env)->FindClass(env, "java/lang/String");
jobjectArray textsArray = (*env)->NewObjectArray(env,(jsize)ARRAY_LENGTH,objClass,0);
i = 0;
scan_dir2(env,dirPath,textsArray);
return textsArray;
}
void scan_dir2(JNIEnv *env,const char *directory,jobjectArray array)
{
DIR *dp;
struct dirent *entry;
struct stat statbuf;
if((dp = opendir(directory)) == NULL)
{
perror("opendir");
return;
}
chdir(directory);
jstring jstr;
while ((entry = readdir(dp)) != NULL)
{
stat(entry->d_name, &statbuf);
if (S_ISDIR(statbuf.st_mode))
{
if ((strcmp(entry->d_name, ".") != 0) &&
(strcmp(entry->d_name, "..") != 0) &&
(entry->d_name[0] != '.'))
{
scan_dir2(env,entry->d_name,array);
}
}
else
{
int size = strlen(entry->d_name);
if (entry->d_name[0] != '.' //隐藏文件
&& (statbuf.st_size/1024) > 300 //大于300k,表示肯能有mp3文件(忽略 <300k的mp3)
&& strcmp( ( entry->d_name + (size - 4) ) , ".mp3") == 0)
{
char* parentPath = (char*)malloc(1024);
char* absolutePath = (char*)malloc(1024);
//首先获取工作路径
getcwd(parentPath,1024);
//LOGE("parentPath = %s \n", parentPath);
strcpy(absolutePath,parentPath);
char *p = "/";
absolutePath = strcat(absolutePath,p);
absolutePath = strcat(absolutePath,entry->d_name);
//statbuf.st_size,
// LOGE("scan_dir(),file absolutePath = %s \n", absolutePath);
jstr = (*env)->NewStringUTF(env,absolutePath);
(*env)->SetObjectArrayElement(env,array,i,jstr);//必须放入jstring
i++;
// (*env)->ReleaseStringUTFChars(env,js, s);
// LOGE("scan_dir2(),i = %d,file absolutePath = %s \n\n",i, absolutePath);
free(parentPath);
parentPath = NULL;
free(absolutePath);
absolutePath = NULL;
}
}
}
chdir("..");
closedir(dp);
}
void Java_com_coder80_scaner_MainActivity_scanDir(JNIEnv *env, jobject obj, jstring jdirPath)
{
const char *path = (*env)->GetStringUTFChars(env,jdirPath,NULL);
LOGE("begin to call scan_dir() in the JNI,and path = %s \n",path);
scan_dir(path);
}
void scan_dir(const char *directory)
{
DIR *dp;
struct dirent *entry;
struct stat statbuf;
if((dp = opendir(directory)) == NULL)
{
perror("opendir");
return;
}
chdir(directory);
//LOGE("pyb chdir directory = %s\n",directory);
while ((entry = readdir(dp)) != NULL) {
stat(entry->d_name, &statbuf);
if (S_ISDIR(statbuf.st_mode)) {
//printf("name = %s, size = %d\n", entry->d_name, (int)statbuf.st_size);
if ((strcmp(entry->d_name, ".") != 0)
&& (strcmp(entry->d_name, "..") != 0)
&& (entry->d_name[0] != '.')) {
scan_dir(entry->d_name);
}
} else {
int size = strlen(entry->d_name);
if (entry->d_name[0] != '.'
&& (statbuf.st_size/1024) > 300 //大于300k,表示肯能有mp3文件(忽略 <300k的mp3)
&& strcmp(entry->d_name + (size - 4), ".mp3") == 0){
//LOGE("scan_dir(),file st_size = %d \n\n",(statbuf.st_size/1024));
char* parentPath = (char*)malloc(1024);
char* absolutePath = (char*)malloc(1024);
//首先获取工作路径
getcwd(parentPath,1024);
//LOGE("parentPath = %s \n", parentPath);
strcpy(absolutePath,parentPath);
char *p = "/";
absolutePath = strcat(absolutePath,p);
absolutePath = strcat(absolutePath,entry->d_name);
//statbuf.st_size,
LOGE("scan_dir(),file absolutePath = %s \n", absolutePath);
free(parentPath);
parentPath = NULL;
free(absolutePath);
absolutePath = NULL;
}
}
}
chdir("..");
closedir(dp);
}
////displayName
//jfieldID disName;
////size
//jfieldID trackSize;
////ext
//jfieldID extName;
////filePath
//jfieldID path;
////parentPath
//jfieldID parent;
//
//jobject obj_main;
JNIEXPORT jobjectArray JNICALL Java_com_coder80_scaner_MainActivity_getTracksArray(JNIEnv *env, jobject obj, jstring jdirPath){
const char *dirPath = (*env)->GetStringUTFChars(env,jdirPath,NULL);
jclass objectClass = (*env)->FindClass(env, "com/coder80/scaner/Track_Info");
jobjectArray jobj_arr= (*env)->NewObjectArray(env,(jsize)ARRAY_LENGTH,objectClass, 0);
obj_main = obj;
LOGE("in JNI getTracksArray(),dirPath = %s \n", dirPath);
//获取Java对象
/*
* 或者 同样可以获取Java对象
* jclass objectClass = env->GetObjectClass(jobject);
* */
//displayName
// disName = (*env)->GetFieldID(env,objectClass,"displayName","Ljava/lang/String;");
//// //size
//// trackSize = (*env)->GetFieldID(env,objectClass,"size"," L");
// //ext
// extName = (*env)->GetFieldID(env,objectClass,"ext","Ljava/lang/String;");
// //filePath
// path = (*env)->GetFieldID(env,objectClass,"filePath","Ljava/lang/String;");
// //parentPath
// parent = (*env)->GetFieldID(env,objectClass,"parentPath","Ljava/lang/String;");
i = 0;
scan_dir3(env,dirPath,jobj_arr);
return jobj_arr;
}
jmethodID JavaMid = NULL;
JNIEnv * jniEnvPlaying = NULL;
/*
* para obj: Track_Info object
* */
//void scan_dir3(JNIEnv *env,jobject obj,const char *directory,jobjectArray list)
void scan_dir3(JNIEnv *env,const char *directory,jobjectArray list)
{
DIR *dp;
struct dirent *entry;
struct stat statbuf;
if((dp = opendir(directory)) == NULL)
{
perror("opendir");
return;
}
chdir(directory);
jstring jstr;
while ((entry = readdir(dp)) != NULL)
{
stat(entry->d_name, &statbuf);
if (S_ISDIR(statbuf.st_mode))
{
if ((strcmp(entry->d_name, ".") != 0) &&
(strcmp(entry->d_name, "..") != 0) &&
(entry->d_name[0] != '.'))
{
scan_dir3(env,entry->d_name,list);
}
}
else
{
int size = strlen(entry->d_name);
if (entry->d_name[0] != '.' //隐藏文件
&& (statbuf.st_size/1024) > 300 //大于300k,表示肯能有mp3文件(忽略 <300k的mp3)
&& strcmp((entry->d_name + (size - 4)) , ".mp3") == 0)
{
char* parentPath = (char*)malloc(1024);
char* absolutePath = (char*)malloc(1024);
//首先获取工作路径
getcwd(parentPath,1024);
//LOGE("parentPath = %s \n", parentPath);
strcpy(absolutePath,parentPath);
char *p = "/";
absolutePath = strcat(absolutePath,p);
absolutePath = strcat(absolutePath,entry->d_name);
// jstring jstrDis = (*env)->NewStringUTF(env, entry->d_name);
// (*env)->SetObjectField(env, obj, disName, jstrDis);
//
//// (*env)->SetLongField(env, obj, trackSize, statbuf.st_size/1024);
//
// jstring jstrExt = (*env)->NewStringUTF(env,"mp3");
// (*env)->SetObjectField(env, obj, extName, jstrExt);
//
// jstring jstrPath = (*env)->NewStringUTF(env,absolutePath);
// (*env)->SetObjectField(env, obj, path, jstrPath);
//
// jstring jstrParentPath = (*env)->NewStringUTF(env,absolutePath);
// (*env)->SetObjectField(env, obj, parent, jstrParentPath);
jclass classTrackInfo = (*env)->FindClass(env,"com/coder80/scaner/Track_Info");
// 获取Track_Info类的构造函数ID
jmethodID midInit = (*env)->GetMethodID(env,classTrackInfo,"", "()V");
//构造Track_Info对象
jobject objTrackInfo = (*env)->NewObject(env,classTrackInfo,midInit);
/*查找java中的setDisplayName方法的ID,
* @para:obj Track_Info类的对象
* @para:setDisplayName为Java中的函数名称
* @(Ljava/lang/String;)V 表示String类型的参数。返回值V代表void
* */
JavaMid = (*env)->GetMethodID(env,classTrackInfo,"setDisplayName","(Ljava/lang/String;)V");
if (JavaMid == NULL) {
LOGE("pyb setDisplayName() fun not found!");
return;
}
jstring jstrDis = (*env)->NewStringUTF(env,entry->d_name);
//执行setDisplayName方法 jstrDis --> displayName
(*env)->CallVoidMethod(env,objTrackInfo,JavaMid,jstrDis);
JavaMid = NULL;
//************************************************
//查找java中的setSize方法的ID,J -----> long
JavaMid = (*env)->GetMethodID(env,classTrackInfo,"setSize","(J)V");
if (JavaMid == NULL) {
LOGE("pyb setSize() fun not found!");
return;
}
// jstring jstrDis = (*env)->NewStringUTF(env,entry->d_name);
// //执行setSize方法 statbuf.st_size --> size
(*env)->CallVoidMethod(env,objTrackInfo,JavaMid,statbuf.st_size);
JavaMid = NULL;
//end
//查找java中的setExt方法的ID,
JavaMid = (*env)->GetMethodID(env,classTrackInfo,"setExt", "(Ljava/lang/String;)V");
if (JavaMid == NULL) {
LOGE("pyb setExt() fun not found!");
return;
}
jstring jstrExt = (*env)->NewStringUTF(env,"mp3");
//执行setExt方法 jstrExt --> ext
(*env)->CallVoidMethod(env,objTrackInfo,JavaMid,jstrExt);
JavaMid = NULL;
//查找java中的setFilePath方法的ID,
JavaMid = (*env)->GetMethodID(env,classTrackInfo, "setFilePath","(Ljava/lang/String;)V");
if (JavaMid == NULL) {
LOGE("setFilePath() fun not found!");
return;
}
jstring jstrPath = (*env)->NewStringUTF(env,absolutePath);
//执行setFilePath方法 jstrPath --> filePath
(*env)->CallVoidMethod(env,objTrackInfo,JavaMid,jstrPath);
JavaMid = NULL;
//查找java中的setParentPath方法的ID,
JavaMid = (*env)->GetMethodID(env,classTrackInfo, "setParentPath","(Ljava/lang/String;)V");
if (JavaMid == NULL) {
LOGE("setParentPath() fun not found!");
return;
}
jstring jstrParentPath = (*env)->NewStringUTF(env,parentPath);
//执行setParentPath方法 jstrParentPath --> parentPath
(*env)->CallVoidMethod(env,objTrackInfo,JavaMid,jstrParentPath);
JavaMid = NULL;
(*env)->SetObjectArrayElement(env,list,i,objTrackInfo);
// LOGE("scan_dir3(),i = %d,file absolutePath = %s \n\n",i, absolutePath);
i++;
free(parentPath);
parentPath = NULL;
free(absolutePath);
absolutePath = NULL;
}
}
}
chdir("..");
closedir(dp);
}
在C中调用Java方法,首先需要构建一个Java中类的实例。
//查找Track_Info类
jclass classTrackInfo = (*env)->FindClass(env,"com/coder80/scaner/Track_Info");
// 获取Track_Info类的构造函数ID
jmethodID midInit = (*env)->GetMethodID(env,classTrackInfo,"", "()V");
//构造Track_Info对象
jobject objTrackInfo = (*env)->NewObject(env,classTrackInfo,midInit);
GetMethodID函数中参数值" JavaMid = (*env)->GetMethodID(env,classTrackInfo,"setDisplayName","(Ljava/lang/String;)V");
if (JavaMid == NULL) {
LOGE("pyb setDisplayName() fun not found!");
return;
}
jstring jstrDis = (*env)->NewStringUTF(env,entry->d_name);
//执行setDisplayName方法 jstrDis --> displayName
(*env)->CallVoidMethod(env,objTrackInfo,JavaMid,jstrDis);
JavaMid = NULL;
代码段中
GetMethodID(env,classTrackInfo,"setDisplayName","(Ljava/lang/String;)V");
1."setDisplayName"表示java中的
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
2."(Ljava/lang/String;)V"中
Ljava/lang/String;表示参数类型:String。V 表示 返回值类型
调用Java中的setSize函数。
//查找java中的setSize方法的ID,J -----> long
JavaMid = (*env)->GetMethodID(env,classTrackInfo,"setSize","(J)V");
if (JavaMid == NULL) {
LOGE("pyb setSize() fun not found!");
return;
}
// jstring jstrDis = (*env)->NewStringUTF(env,entry->d_name);
// //执行setSize方法 statbuf.st_size --> size
(*env)->CallVoidMethod(env,objTrackInfo,JavaMid,statbuf.st_size);
JavaMid = NULL;
代码段中:(*env)->GetMethodID(env,classTrackInfo,"setSize","(J)V"); 参数值"(J)V" J表示 java中的long类型数据。
public void setSize(long size) {
// Log.e("Track_Info.java", "setSize() called in JNI, size = " + size);
this.size = size;
}
jmethodID GetMethodID(JNIEnv *env, jclass clazz,const char *name, const char *sig);
例如,在本例中,需要调用 public native Track_Info[] getTracksArray(String dirPath);在JNI_OnLoad函数中可以看到
其signature就是 (Ljava/lang/String;)[Lcom/coder80/scaner/Track_Info;
Ljava/lang/String;表示参数类型
[Lcom/coder80/scaner/Track_Info;表示函数getTracksArray的返回值为对象数组。
另外千万别忘记L fully-qualified-class ; 这个格式后面的那个;号。
主要类代码如下:
package com.coder80.scaner;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
private Button mbtn;
private Button mbtnJava;
private long mTime;
private TextView mTextView;
private File mSdcardFile;
private String mFlagJava = "java";
private String mFlagC = "native";
private boolean mIsClick; //防止多次点击
private Track_Info mTrack;
private List mTrackList = new ArrayList();
private Track_Info[] mTracks;// = new Track_Info[100];
// char[] a = new char[100];
private boolean mIsExit;//sdcard是否存在
private void log_msg(String msg) {
if(true){
Log.e(getClass().getSimpleName(), msg);
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mIsClick = false;
mIsExit = true;
mTrack = new Track_Info();
mSdcardFile = Environment.getExternalStorageDirectory();
Log.e("pyb", " mSdcardFile = " + mSdcardFile.toString());
if (android.os.Environment.MEDIA_MOUNTED.equals(android.os.Environment
.getExternalStorageState())) {
mIsExit = true;
} else {
mIsExit = false;
Toast.makeText(MainActivity.this, "SDCard不存在,请安装!",Toast.LENGTH_LONG).show();
}
mbtn = (Button) findViewById(R.id.button1);
mbtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (mIsExit) {
if (!mIsClick){
mIsClick = true;
Log.e("pyb", " in the JNI scaner");
new MyAsyncTask().execute(mFlagC);
}
}else {
Toast.makeText(MainActivity.this, "SDCard不存在,请安装!",Toast.LENGTH_LONG).show();
}
}
});
mbtnJava = (Button) findViewById(R.id.btn2);
mbtnJava.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Log.e("pyb", " in the Java scaner");
new MyAsyncTask().execute(mFlagJava);
}
});
mTextView = (TextView) findViewById(R.id.TextView02);
}
public void addList(Track_Info track){
mTrackList.add(track);
}
public class MyAsyncTask extends AsyncTask {
@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
}
@Override
protected void onPostExecute(Object result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
if(mTime < 1000){
mTextView.setText("花费时间: " + Long.toString(mTime) + " 毫秒");
}else{
mTime = mTime/1000;
mTextView.setText("花费时间: " + Long.toString(mTime) + " 秒");
}
mIsClick = false;
}
@Override
protected Object doInBackground(String... params) {
// TODO Auto-generated method stub
String flag = params[0];
Log.e("pyb", " doInBackground called...flag = " + flag);
long time1 = System.currentTimeMillis();
// scanDir(mSdcardFile.toString() + "/音乐");
if(flag.equals("java")){
getFiles(mSdcardFile);
for(int i = 0;i< mTrackList.size();i++){
Log.e("pyb", "mTrackList[" +i+"] path = " + mTrackList.get(i).getFilePath());
}
}else if(flag.equals("native")){
// scanDir(mSdcardFile.toString());
// array = getPathArray(mSdcardFile.toString());
mTracks = getTracksArray(mSdcardFile.toString());
Log.e("pyb", "mTracks.length = "+ mTracks.length);
for (int i = 0; i < mTracks.length; i++) {
if (mTracks[i] != null) {
Log.e("pyb", "mTracks[" +i+"] path = " + mTracks[i].getFilePath());
} else {
Log.e("pyb", "mTracks == null");
break;
}
}
}
long time2 = System.currentTimeMillis();
mTime = time2 - time1;
Log.e("pyb", "in the doInBackground(),scaner mp3 cost time = " + (time2 - time1) );
return null;
}
};
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
static {
Log.e("pyb", " System.loadLibrary() called...");
System.loadLibrary("scan");
}
/**
* 获取音乐文件列表
* @param filePath
*/
public void getFiles(File filePath) {
File[] files = filePath.listFiles();
if (files != null) {
for (int i = 0; i < files.length; i++) {
if (files[i].isDirectory() && !files[i].isHidden() && files[i].canRead()) {
getFiles(files[i]);
} else {
// Mp3support
String displayName = files[i].getName();
if (displayName.endsWith(".mp3") || displayName.endsWith(".MP3")) {
// String[] strarray = displayName.split("\\.");
// String path = files[i].getParentFile().toString();
String fileName = files[i].getName();
String[] strarray=fileName.split("\\.");
// String displayName = strarray[0];
String ext = strarray[1];
String filepath = files[i].toString();
String parentPath = files[i].getParentFile().toString() + "/";
mTrack = new Track_Info();
mTrack.setDisplayName(displayName);
mTrack.setExt(ext);
mTrack.setFilePath(filepath);
mTrack.setParentPath(parentPath);
mTrackList.add(mTrack);
}
}
}
}
}
public native void scanDir(String dirPath);
public native String[] getPathArray(String dirPath);
public native Track_Info[] getTracksArray(String dirPath);
}
通过本例,可以了解JNI使用方法,对稍微复杂的JNI编程,例如从native层调用Java层对象的讲解,是有一定的帮助的。
demo代码已经上传到博客资源中!