当前位置: 代码迷 >> 综合 >> Free Pascal (Lazarus)版Android NDK的应用示例之:常用数据类型的转换
  详细解决方案

Free Pascal (Lazarus)版Android NDK的应用示例之:常用数据类型的转换

热度:9   发布时间:2023-12-15 20:56:24.0

         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的,谢谢他的奉献。


function JNI_JStringToString(Env: pJNIEnv; JStr: JString): string; cdecl;//Java String转Pascal String
varpAnsiCharTMP: pAnsiChar;IsCopy: JBoolean;pIsCopy: pJBoolean;beginIsCopy := JNI_TRUE;pIsCopy := @IsCopy;if (JStr = nil) thenbeginResult := '';Exit;end;pAnsiCharTMP := Env^^.GetStringUTFChars(Env, JStr, pIsCopy);if (pAnsiCharTMP = nil) thenbeginResult := '';endelsebeginResult := StrPas(pAnsiCharTMP); //將pAnsiChar轉為Pascal String後作為回傳值Env^^.ReleaseStringUTFChars(Env, JStr, pAnsiCharTMP);//輸入字串相關的轉換資源用完要釋放,否則會產生記憶體洩漏問題!end;
end;function JNI_StringToJString(Env: pJNIEnv; Str: string): jstring; cdecl;
beginResult := Env^^.NewStringUTF(Env, @Str[1]); //依Pascal String內容建立新的Java String回傳
end;


以下是字符串数组的互相转换:

function JNI_JStringArrayToStrings(Env: PJNIEnv; jStrings: jarray): TStringDynArray;cdecl;
varlen, i: jsize;w_ret: TStringDynArray;obj: jobject;
beginlen := Env^^.GetArrayLength(env, jStrings);SetLength(w_ret, len);for i := 0 to len - 1 dobeginobj := env^^.GetObjectArrayElement(env, jStrings, i);w_ret[i] := JNI_JStringToString(Env, jString(obj));end;Result := w_ret;
end;function JNI_StringsToJStringArray(Env: PJNIEnv; strings: TStringDynArray): jarray;cdecl;
vari, len: cardinal;w_ret: jarray;
beginlen := 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 dobeginEnv^^.SetObjectArrayElement(Env, w_ret, i, JNI_StringToJString(env, strings[i]));end;Result := w_ret;
end;

以下是整形数组的互相转换:

function JNI_JIntArrayToIntegers(Env: PJNIEnv; jarr: jintArray): TIntegerDynArray;cdecl;
varw_ret: TIntegerDynArray;len: jint;
beginlen := 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;
varlen: cardinal;intArray: JIntArray;
beginif (arr = nil) thenbeginResult := nil;Exit;end;len := High(arr) + 1;intArray := Env^^.NewIntArray(Env, Len);Env^^.SetIntArrayRegion(Env, intArray, 0, len, @arr[0]);Result := intArray;
end;


以下是字节数组的互相转换:

{ Convert byte array to JByteArray }
function JNI_BytesToJByteArray(Env: PJNIEnv; Bytes: TByteDynArray): JByteArray;cdecl;
varlen: cardinal;byteArray: JByteArray;
beginif (bytes = nil) thenbeginResult := 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;
varlen: jsize;w_ret: TByteDynArray;
beginlen := Env^^.GetArrayLength(env, JBytes);SetLength(w_ret,len);Env^^.GetByteArrayRegion(env, JBytes, 0, len, @w_ret[0]);Result := w_ret;
end;


还有一个抛出异常的函数:

procedure JNI_ThrowException(Env: PJNIEnv; E: Exception);cdecl;
varjc: JObject;
beginjc := Env^^.FindClass(Env, 'java/lang/Exception');Env^^.ThrowNew(Env, jc, PChar(E.Message));
end;

===========

以下是Native代码:

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代码。*******************************************************************************}
usesClasses, jniutil,types,sysutils,log,jni in '../jni.pas';
function JNI_OnLoad(vm: PJavaVM; reserved: pointer): jint; cdecl;
beginResult := JNI_VERSION_1_6;
end;procedure JNI_OnUnload(vm:PJavaVM;reserved:pointer); cdecl;
begin
end;function TestAddint(env: pJniEnv; this: jObject; a, b: jInt): jInt; cdecl;
beginLOGW(pchar('a='+inttostr(a)+',b='+inttostr(b)));result:=a+b;
end;
function testSubfloat(env: pJniEnv; this: jObject; a, b: jdouble): jdouble; cdecl;
beginLOGW(pchar('a='+FloatToStr(a)+',b='+FloatToStr(b)));result:=a-b;
end;
function testString(env: pJniEnv; this: jObject; str:jstring): jstring; cdecl;
beginresult:=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;
beginLOGW('entry.');w_vals:=JNI_JByteArrayToBytes(env,jbytes);LOGW(pchar('length(w_vals):'+inttostr(length(w_vals))));if length(w_vals)>=3 then beginw_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;
beginw_vals:=JNI_JIntArrayToIntegers(env,jIntegers);if length(w_vals)>=3 then beginw_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;
beginw_vals:=JNI_JStringArrayToStrings(env,jstrs);if length(w_vals)>=3 then beginw_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;
beginJNI_ThrowException(env,Exception.Create(JNI_JStringToString(env,message)));
end;exportstestAddint 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方面的代码:

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() {}@Overridepublic 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() {@Overridepublic 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() {					@Overridepublic 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() {					@Overridepublic 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() {					@Overridepublic 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() {					@Overridepublic 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() {					@Overridepublic 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() {					@Overridepublic 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;}}


运行如下图:




代码下载:

free pascal (lazarus) 版的 android NDK (JNI)调用范例、数据类型转换示例

  相关解决方案