本帖最后由 tigerA15 于 2014-4-16 08:13 编辑
lazarus为free pascal 提供良好的IDE(在我看来,Delphi已死),可编译出各种平台的目标程序,而且大前提是免费的!我想这是free pacal的魅力所在。 android 正如日中天,独霸一方,lazarus也提供了编译到android目标的方法,但于作者各种尝试后感觉,其UI实现渣了点,显然还处于起步阶段。 但非UI的衔接兼容的很好,用free pascal写android NDK一点也不输C。 好了,题外话不多说,以下我提供一些最常用的数据类型转换函数,用作android调用 free pascal进行数据运算绝对没问题。
android_jni_2下有两大目录和三个pas文件:android是android project的目录,直接在ADT里面导入即可;native为 lazarus工程目录,jni_demo3.lpr是工程文件,简单几个演示function
示例如何调用这些转换函数;三个pas文件,分别是jni.pas,jniutil.pas,和log.pas,jni就是常规的jni不用多说,jniutil是我写的若干个数据类型转换函数,log是日志输出函数。
以下分别介绍jniutil的几个函数及应用:
以下两个String JString互相转换的function是来自chenyuchih的,谢谢他的奉献。
[delphi] view plaincopy 
- function JNI_JStringToString(Env: pJNIEnv; JStr: JString): string; cdecl;
- //Java String轉Pascal String副本範例
- var
- pAnsiCharTMP: pAnsiChar;
- IsCopy: JBoolean;
- pIsCopy: pJBoolean;
-
- begin
- IsCopy := JNI_TRUE;
- pIsCopy := @IsCopy;
-
- if (JStr = nil) then
- begin
- Result := '';
- Exit;
- end;
-
- pAnsiCharTMP := Env^^.GetStringUTFChars(Env, JStr, pIsCopy);
- //將輸入的Java String轉為pAnsiChar(相容C語言的零位元終止字元陣列指標),因後續有釋放資源的動作故不宜在外加掛一層StrPas()直接轉換成Pascal String。
- if (pAnsiCharTMP = nil) then
- begin
- Result := '';
- end
- else
- begin
- Result := StrPas(pAnsiCharTMP); //將pAnsiChar轉為Pascal String後作為回傳值
- Env^^.ReleaseStringUTFChars(Env, JStr, pAnsiCharTMP);
- //輸入字串相關的轉換資源用完要釋放,否則會產生記憶體洩漏問題!
- end;
- end;
-
- function JNI_StringToJString(Env: pJNIEnv; Str: string): jstring; cdecl;
- begin
- Result := Env^^.NewStringUTF(Env, @Str[1]); //依Pascal String內容建立新的Java String回傳
- end;
以下是字符串数组的互相转换:
[delphi] view plaincopy 
- function JNI_JStringArrayToStrings(Env: PJNIEnv; jStrings: jarray): TStringDynArray;cdecl;
- var
- len, i: jsize;
- w_ret: TStringDynArray;
- obj: jobject;
- begin
- len := Env^^.GetArrayLength(env, jStrings);
- SetLength(w_ret, len);
- for i := 0 to len - 1 do
- begin
- obj := env^^.GetObjectArrayElement(env, jStrings, i);
- w_ret := JNI_JStringToString(Env, jString(obj));
- end;
- Result := w_ret;
- end;
-
- function JNI_StringsToJStringArray(Env: PJNIEnv; strings: TStringDynArray): jarray;cdecl;
- var
- i, len: cardinal;
- w_ret: jarray;
- begin
- len := length(strings);
- //开始忘了在java里面String是Object,转了很大弯
- w_ret := Env^^.NewObjectArray(Env, Len,Env^^.FindClass(Env,'java/lang/String'),JNI_StringToJString(Env,''));
- for i := 0 to len - 1 do
- begin
- Env^^.SetObjectArrayElement(Env, w_ret, i, JNI_StringToJString(env, strings));
- end;
- Result := w_ret;
- end;
以下是整形数组的互相转换:
[delphi] view plaincopy 
- function JNI_JIntArrayToIntegers(Env: PJNIEnv; jarr: jintArray): TIntegerDynArray;cdecl;
- var
- w_ret: TIntegerDynArray;
- len: jint;
- begin
- len := Env^^.GetArrayLength(Env, jarr);
- SetLength(w_ret, len);
- Env^^.GetIntArrayRegion(Env, jarr, 0, len, @w_ret[0]);
- Result := w_ret;
- end;
-
- function JNI_IntegersToJIntArray(Env: PJNIEnv; arr: TIntegerDynArray): JIntArray;cdecl;
- var
- len: cardinal;
- intArray: JIntArray;
- begin
- if (arr = nil) then
- begin
- Result := nil;
- Exit;
- end;
-
- len := High(arr) + 1;
- intArray := Env^^.NewIntArray(Env, Len);
- Env^^.SetIntArrayRegion(Env, intArray, 0, len, @arr[0]);
- Result := intArray;
- end;
以下是字节数组的互相转换:
[delphi] view plaincopy 
- { Convert byte array to JByteArray }
- function JNI_BytesToJByteArray(Env: PJNIEnv; Bytes: TByteDynArray): JByteArray;cdecl;
- var
- len: cardinal;
- byteArray: JByteArray;
- begin
- if (bytes = nil) then
- begin
- Result := nil;
- Exit;
- end;
-
- len := High(Bytes) + 1;
- byteArray := Env^^.NewByteArray(Env, Len);
- Env^^.SetByteArrayRegion(Env, byteArray, 0, len, @Bytes[0]);
- Result := byteArray;
- end;
-
- function JNI_JByteArrayToBytes(Env: PJNIEnv; JBytes: jbyteArray): TByteDynArray;cdecl;
- var
- len: jsize;
- w_ret: TByteDynArray;
- begin
- len := Env^^.GetArrayLength(env, JBytes);
- SetLength(w_ret,len);
- Env^^.GetByteArrayRegion(env, JBytes, 0, len, @w_ret[0]);
- Result := w_ret;
- end;
还有一个抛出异常的函数:
[delphi] view plaincopy 
- procedure JNI_ThrowException(Env: PJNIEnv; E: Exception);cdecl;
- var
- jc: JObject;
- begin
- jc := Env^^.FindClass(Env, 'java/lang/Exception');
- Env^^.ThrowNew(Env, jc, PChar(E.Message));
- end;
===========
以下是Native代码:
[delphi] view plaincopy 
- library jni_demo3;
-
- {$mode objfpc}{$H+}
- {*******************************************************************************
- jni_demo3 by lrh (rock33@126.com)
-
- 非常感谢fpc和lazarus的各位大神无私奉献,让 pascal语言能同行各平台(包括现在
- 流行的android),谢谢猫工、delphicn的引路,也谢谢台湾的chenyuchih给启蒙。
-
- 小弟化了一天半的时间作了如下最常用的数据类型转换function,希望能帮助大家。
- free pascal虽然偏冷,但并不代表她不优秀,要发扬光大得靠大家努力^_^。
-
- main project source 只是简单带出这几个function的一些应用示例,具体如何调用还要
- 看android那边的java代码。
- *******************************************************************************}
- uses
- Classes, jniutil,types,sysutils,log,
- jni in '../jni.pas';
- function JNI_OnLoad(vm: PJavaVM; reserved: pointer): jint; cdecl;
- begin
- Result := JNI_VERSION_1_6;
- end;
-
- procedure JNI_OnUnload(vm
JavaVM;reserved:pointer); cdecl; - begin
- end;
-
- function TestAddint(env: pJniEnv; this: jObject; a, b: jInt): jInt; cdecl;
- begin
- LOGW(pchar('a='+inttostr(a)+',b='+inttostr(b)));
- result:=a+b;
- end;
- function testSubfloat(env: pJniEnv; this: jObject; a, b: jdouble): jdouble; cdecl;
- begin
- LOGW(pchar('a='+FloatToStr(a)+',b='+FloatToStr(b)));
- result:=a-b;
- end;
- function testString(env: pJniEnv; this: jObject; str:jstring): jstring; cdecl;
- begin
- result:=JNI_StringToJString(env,'hello,'+JNI_JStringToString(env,str)+'.\n你好,'+JNI_JStringToString(env,str));
- end;
- function testByteArray(env: pJniEnv; this: jObject; jbytes:jbyteArray): jbyteArray; cdecl;
- var w_vals:TByteDynArray;
- begin
- LOGW('entry.');
- w_vals:=JNI_JByteArrayToBytes(env,jbytes);
- LOGW(pchar('length(w_vals):'+inttostr(length(w_vals))));
- if length(w_vals)>=3 then begin
- w_vals[0]:=w_vals[0]+1;
- w_vals[1]:=w_vals[1]+1;
- w_vals[2]:=w_vals[2]+1;
- end;
- result:=JNI_BytesToJByteArray(env,w_vals);
- end;
- function testIntegerArray(env: pJniEnv; this: jObject; jIntegers:jintArray): jintArray; cdecl;
- var w_vals:TIntegerDynArray;
- begin
- w_vals:=JNI_JIntArrayToIntegers(env,jIntegers);
- if length(w_vals)>=3 then begin
- w_vals[0]:=w_vals[0]+1;
- w_vals[1]:=w_vals[1]+1;
- w_vals[2]:=w_vals[2]+1;
- end;
- result:=JNI_IntegersToJIntArray(env,w_vals);
- end;
- function testStringArray(env: pJniEnv; this: jObject; jstrs:jarray): jarray; cdecl;
- var w_vals:jniutil.TStringDynArray;
- begin
- w_vals:=JNI_JStringArrayToStrings(env,jstrs);
- if length(w_vals)>=3 then begin
- w_vals[0]:='第一行:'+w_vals[0];
- w_vals[1]:='第二行:'+w_vals[1];
- w_vals[2]:='第三行:'+w_vals[2];
- end;
- result:=JNI_StringsToJStringArray(env,w_vals);
- end;
- procedure testThrowException(env: pJniEnv; this: jObject; message:jstring); cdecl;
- begin
- JNI_ThrowException(env,Exception.Create(JNI_JStringToString(env,message)));
- end;
-
- exports
- testAddint name 'Java_jnidemo_JniDemo_testAddint',
- testSubfloat name 'Java_jnidemo_JniDemo_testSubfloat',
- testString name 'Java_jnidemo_JniDemo_testString',
- testByteArray name 'Java_jnidemo_JniDemo_testByteArray',
- testIntegerArray name 'Java_jnidemo_JniDemo_testIntegerArray',
- testStringArray name 'Java_jnidemo_JniDemo_testStringArray',
- testThrowException name 'Java_jnidemo_JniDemo_testThrowException',
- JNI_OnLoad,
- JNI_OnUnLoad;
- //JNI函式命名原則:Java_<Java專案下的Package路徑,若當中有「.」則用「_」替換之,例如「com.example」則變成「com_example」>_<Class名稱>_<函式名稱>
-
- begin
- end.
Android方面的代码:
[java] view plaincopy 
- package jnidemo;
-
- public class JniDemo {
- static{
- System.loadLibrary("jni_demo3");
- }
- public static native int testAddint(int a,int b);
- public static native double testSubfloat(double a,double b);
- public static native String testString(String str);
- public static native byte[] testByteArray(byte[] vals);
- public static native int[] testIntegerArray(int[] vals);
- public static native String[] testStringArray(String[] vals);
- public static native void testThrowException(String message);
- }
-
-
-
- Activity的调用例子:
- public static class PlaceholderFragment extends Fragment {
-
- public PlaceholderFragment() {
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- View rootView = inflater.inflate(R.layout.fragment_main, container,
- false);
- ((Button)rootView.findViewById(R.id.btn_int)).setOnClickListener(new View.OnClickListener() {
-
- @Override
- public void onClick(View v) {
- //整數傳遞
- int a=123;
- int b=234;
- int c=JniDemo.testAddint(a, b);
- Toast.makeText(_this, a+"+"+b+"="+c, Toast.LENGTH_SHORT).show();
- }
- });
- ((Button)rootView.findViewById(R.id.btn_float)).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- double a=1.2345;
- double b=0.2045;
- double c=JniDemo.testSubfloat(a, b);
- Toast.makeText(_this, a+"+"+b+"="+c, Toast.LENGTH_SHORT).show();
- }
- });
- ((Button)rootView.findViewById(R.id.btn_string)).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- //string的互相傳遞,繁簡中文沒問題
- String w_ret=JniDemo.testString("rock(陳大文)");
- Toast.makeText(_this, w_ret, Toast.LENGTH_SHORT).show();
- }
- });
- ((Button)rootView.findViewById(R.id.btn_bytes)).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- byte[] w_val=new byte[3];
- w_val[0]=1;
- w_val[1]=2;
- w_val[2]=3;
- w_val=JniDemo.testByteArray(w_val);
- Toast.makeText(_this, String.format("[0]=%d, [1]=%d,[2]=%d",w_val[0],w_val[1],w_val[2]),
- Toast.LENGTH_SHORT).show();
- }
- });
-
- ((Button)rootView.findViewById(R.id.btn_integers)).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- int[] w_val=new int[3];
- w_val[0]=10;
- w_val[1]=20;
- w_val[2]=30;
- w_val=JniDemo.testIntegerArray(w_val);
- Toast.makeText(_this, String.format("[0]=%d, [1]=%d,[2]=%d",w_val[0],w_val[1],w_val[2]),
- Toast.LENGTH_SHORT).show();
- }
- });
- ((Button)rootView.findViewById(R.id.btn_exception)).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- try{
- JniDemo.testThrowException("這是一個異常!");
- }
- catch (Exception e){
- Toast.makeText(_this, e.getMessage(), Toast.LENGTH_SHORT).show();
- }
- }
- });
-
- ((Button)rootView.findViewById(R.id.btn_strings)).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- String[] w_val=new String[3];
- w_val[0]="first(第一)";
- w_val[1]="second(第二)";
- w_val[2]="third(第三)";
- w_val=JniDemo.testStringArray(w_val);
- Toast.makeText(_this, String.format("[0]=%s, [1]=%s,[2]=%s",w_val[0],w_val[1],w_val[2]),
- Toast.LENGTH_SHORT).show();
- }
- });
-
- return rootView;
- }
- }
运行如下图: 
本例代码下载:
android_jni_2.zip(1.02M) |