1、JNI简介
JNI全称为Java Native Interface(JAVA本地调用)。从Java1.1开始,JNI成为java平台的一部分,它允许Java代码和其他语言写的代码(如C&C++)进行交互。并非从Android发布才引入JNI的概念的。
2、JNI与NDK
简单来说,Android的NDK提供了一些交叉编译工具链和Android自带的库,这些Android的库可以让开发者在编写本地语言的程序时调用。而NDK提供的交叉编译工具链就对已经编写好的C&C++代码进行编译,生成库。
当然了,你也可以自己搭建交叉编译环境,而不用NDK的工具和库。然后生成库,只要规范操作,一样可以生成能让JAVA层成功调用的库文件的。
使用JNI技术,其实就是在Java程序中,调用C语言的函数库中提供的函数,来完成一些Java语言无法完成的任务。由于Java语言和C语言结构完全不相同,因此若想让它们二者交互,则需要制定一系列的规范。JNI就是这组规范,此时 Java只和JNI交互,而由JNI去和C语言交互。
JNI技术分为两部分:Java端和C语言端。且以Java端为主导。
|- 首先,Java程序员在Java端定义一些native方法,并将这些方法以C语言头文件的方式提供给C程序员。
|- 然后,C程序员使用C语言,来实现Java程序员提供的头文件中定义的函数。
|- 接着,C程序员将函数打包成一个库文件,并将库文件交给Java程序员。
在Java程序执行的时候,若在某个类中调用了native方法,则虚拟机会通过JNI来转调用库文件中的C语言代码。提示:C代码最终是在Linux进程中执行的,而不是在虚拟机中。
下面是一个Android调用JNI实现通过LAME转码器实现wav格式到MP3格式的转换.
准备:首先下载lame源码文件。
需要三个条件 :cgywin,cdt,ndk才能实现JNI的开发。
开发lame需要从http://lame.sourceforge.net/选择Using Lame 下载源代码。
新建工程
1、Android主界面布局
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <EditText android:id="@+id/editText1" android:hint="源wav文件的路径" android:text="/sdcard/118/ccc.wav" android:layout_width="match_parent" android:layout_height="wrap_content" > </EditText> <EditText android:id="@+id/editText2" android:hint="目标MP3文件的路径" android:layout_width="match_parent" android:text="/sdcard/118/ccccc.mp3" android:layout_height="wrap_content" /> <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="转化" android:onClick="convert" /> <Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="获取lame版本号" android:onClick="getversion" /></LinearLayout>
首先是建立JNI目录
1、把lameC语言源码导入jni中
2、创建Android.mk文件
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := HelloLOCAL_SRC_FILES := bitstream.c fft.c id3tag.c mpglib_interface.c presets.c quantize.c reservoir.c tables.c util.c VbrTag.c encoder.c gain_analysis.c lame.c newmdct.c psymodel.c quantize_pvt.c set_get.c takehiro.c vbrquantize.c version.c Hello.cLOCAL_LDLIBS += -lloginclude $(BUILD_SHARED_LIBRARY)
3、编写C语言文件
#include <stdio.h>#include <jni.h>#include "com_example_ndkpassdata_DataProvider.h"#include <android/log.h>#include<malloc.h>#define LOG_TAG "System.out.c"#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)char* Jstring2CStr(JNIEnv* env, jstring jstr) { char* rtn = NULL; jclass clsstring = (*env)->FindClass(env, "java/lang/String"); //String jstring strencode = (*env)->NewStringUTF(env, "GB2312"); // 得到一个java字符串 "GB2312" jmethodID mid = (*env)->GetMethodID(env, clsstring, "getBytes", "(Ljava/lang/String;)[B"); //[ String.getBytes("gb2312"); jbyteArray barr = (jbyteArray)(*env)->CallObjectMethod(env, jstr, mid, strencode); // String .getByte("GB2312"); jsize alen = (*env)->GetArrayLength(env, barr); // byte数组的长度 jbyte* ba = (*env)->GetByteArrayElements(env, barr, JNI_FALSE); if (alen > 0) { rtn = (char*) malloc(alen + 1); //"\0" memcpy(rtn, ba, alen); rtn[alen] = 0; } (*env)->ReleaseByteArrayElements(env, barr, ba, 0); // return rtn;}JNIEXPORT jint JNICALL Java_com_example_ndkpassdata_DataProvider_add( JNIEnv *env, jobject obj, jint x, jint y) { LOGD("x=%d", x); LOGD("y=%d", y); return x + y;}JNIEXPORT jstring JNICALL Java_com_example_ndkpassdata_DataProvider_sayHelloInc( JNIEnv *env, jobject obj, jstring jstr) { char *cstr = Jstring2CStr(env, jstr); LOGD("cstr=%s", cstr); char arr[7] = { ' ', 'h', 'e', 'l', 'l', 'o', '/0' }; strcat(cstr, arr); LOGD("newcstr=%s", cstr); return (*env)->NewStringUTF(env, cstr);}JNIEXPORT jintArray JNICALL Java_com_example_ndkpassdata_DataProvider_intMethod( JNIEnv *env, jobject obj, jintArray arr) { int len = (*env)->GetArrayLength(env, arr); LOGD("SHUZU length-=%d", len); jint *intarr = (*env)->GetIntArrayElements(env, arr, 1); int i = 0; for (; i < len; i++) { LOGD("intarr[%d]=%d", i, intarr[i]); *(intarr + i) += 10; //intarr[i] += 10; } (*env)->ReleaseIntArrayElements(env, arr, intarr, len); return arr;}JNIEXPORT jint JNICALL Java_com_example_ndkpassdata_DataProvider_sub( JNIEnv *env, jclass clazz, jint x, jint y) { LOGD("x=%d", x); LOGD("Y=%d", y); return x - y;}
4、使用cgywin工具进行ndk-build编译
成功之后
5、编写Activity文件
package cn.itcast.lame;import java.io.File;import android.app.Activity;import android.app.ProgressDialog;import android.os.Bundle;import android.view.View;import android.widget.EditText;import android.widget.Toast;public class LameActivity extends Activity { private EditText et_wav; private EditText et_mp3; private ProgressDialog pd; public native void convertmp3(String wav,String mp3); public native String getLameVersion(); public native void stop(); static{ System.loadLibrary("Hello"); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); et_wav = (EditText) this.findViewById(R.id.editText1); et_mp3 = (EditText) this.findViewById(R.id.editText2); pd = new ProgressDialog(this); } public void convert(View view){ final String mp3name = et_mp3.getText().toString().trim(); final String wavname = et_wav.getText().toString().trim(); File file = new File(wavname); int size = (int) file.length(); System.out.println("文件大小 "+ size); if("".equals(mp3name)||"".equals(wavname)){ Toast.makeText(this, "路径不能为空", 1).show(); return; } //convertmp3(wavname,mp3name); pd.setMessage("转换中...."); pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); pd.setMax(size); // 设置进度条的最大值 //pd.setCancelable(false); pd.show(); new Thread(){ @Override public void run() { convertmp3(wavname,mp3name); pd.dismiss(); } }.start(); } public void setConvertProgress(int progress){ pd.setProgress(progress); } public void getversion(View view){ String version = getLameVersion(); Toast.makeText(this, version, 0).show(); }}
6、运行程序
源码地址:
http://download.csdn.net/detail/kai46385076/8999373
版权声明:本文为博主原创文章,未经博主允许不得转载。