Lazarus中文社区

 找回密码
 立即注册(注册审核可向QQ群索取)

QQ登录

只需一步,快速开始

Lazarus IDE and 组件 下载地址版权申明
查看: 12360|回复: 14

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

[复制链接]

该用户从未签到

发表于 2014-4-15 16:18:29 | 显示全部楼层 |阅读模式
本帖最后由 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(vmJavaVM;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)
回复

使用道具 举报

该用户从未签到

 楼主| 发表于 2014-4-15 16:23:09 | 显示全部楼层
是不够权限上传附件吗??没看到按钮。。。
回复 支持 反对

使用道具 举报

  • TA的每日心情
    开心
    2020-9-18 14:51
  • 签到天数: 47 天

    [LV.5]常住居民I

    发表于 2014-4-15 21:45:30 | 显示全部楼层
    本帖最后由 lhxzui 于 2014-4-15 21:47 编辑


    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有账号?立即注册(注册审核可向QQ群索取)

    x
    回复 支持 反对

    使用道具 举报

    该用户从未签到

     楼主| 发表于 2014-4-16 08:14:27 | 显示全部楼层
    lhxzui 发表于 2014-4-15 21:45

    谢谢,已上传
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2014-4-16 12:07:32 | 显示全部楼层
    tiger 很赞。。。。。。
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2014-4-16 16:03:11 | 显示全部楼层

    @tiger
    ZenGL 2D 游戏引擎中有一个GUI 函数库,修改后应该支持 android 皮肤纹理都是可以自己改的。
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2014-4-16 16:05:13 | 显示全部楼层
    哈,能收到拋磚引玉之效,花時間寫心得&範例就值得了......推一個!
    回复 支持 反对

    使用道具 举报

    该用户从未签到

     楼主| 发表于 2014-4-17 09:44:11 | 显示全部楼层
    roolive 发表于 2014-4-16 16:03
    @tiger
    ZenGL 2D 游戏引擎中有一个GUI 函数库,修改后应该支持 android 皮肤纹理都是可以自己改的。

    应该跟这个没关系吧?http://baike.baidu.com/view/10079848.htm
    有没有入门资料,比如安装、sample project之类的
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2014-4-17 19:56:57 | 显示全部楼层
    此 ZenGL 2D 并非你查到的这个。 而是 http://www.zengl.org/
    回复 支持 反对

    使用道具 举报

    该用户从未签到

     楼主| 发表于 2014-4-18 08:55:22 | 显示全部楼层
    roolive 发表于 2014-4-17 19:56
    此 ZenGL 2D 并非你查到的这个。 而是 http://www.zengl.org/

    我知道的,在装傻骗回复
    回复 支持 反对

    使用道具 举报

    *滑块验证:

    本版积分规则

    QQ|手机版|小黑屋|Lazarus中国|Lazarus中文社区 ( 鄂ICP备16006501号-1 )

    GMT+8, 2025-5-1 11:45 , Processed in 0.038910 second(s), 9 queries , Redis On.

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表