一个使用Eigen库和JNI的简单NDK项目

21

今天在这里得到一些帮助后,我制作了一个简单的Android应用程序,使用了NDK。我将Eigen库直接导入到我创建的JNI文件夹中,然后使用Cygwin编译项目。以下是源代码,供其他尝试学习JNI基础知识、从C++到Java传递数据的人参考。该应用程序只是在EditText字段中输入6个数字,当用户单击按钮时,会将两个浮点数组传递到本地方法,并加载到两个Eigen浮点向量中,然后将它们相加。两个向量的积被传回Java,然后显示在TextView中。

以下是适用于Android的Eigen库链接:

https://bitbucket.org/erublee/eigen-android

你只需要实际的Eigen文件夹,该文件夹在文件树中向下一层。只需将该文件夹复制并粘贴到eigen源文件夹中,并放置在您创建的jni文件夹中,以保存您的Android项目中的c++代码。

这是Java代码:

package jnimath.act;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class JnimathActivity extends Activity {
 /** Called when the activity is first created. */

public EditText x;
public EditText y;
public EditText z;

public EditText x2;
public EditText y2;
public EditText z2;

public float[] vecArray;

public TextView textView1;
public Button run;

float[] array3 = new float[3];
float[] array1 = new float[3];
 float[] array2 = new float[3];

 @Override
 public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    x = (EditText)findViewById(R.id.x);
    y = (EditText)findViewById(R.id.y);
    z = (EditText)findViewById(R.id.z);

    x2 = (EditText)findViewById(R.id.x);
    y2 = (EditText)findViewById(R.id.y);
    z2 = (EditText)findViewById(R.id.z);




    textView1 = (TextView)findViewById(R.id.textView1);
    run = (Button)findViewById(R.id.run);

    run.setOnClickListener(new OnClickListener(){

        @Override
        public void onClick(View v) {

            array1[0] = Float.parseFloat(x.getText().toString());
            array1[1] = Float.parseFloat(y.getText().toString());
            array1[2] = Float.parseFloat(z.getText().toString());

            array2[0] = Float.parseFloat(x2.getText().toString());
            array2[1] = Float.parseFloat(y2.getText().toString());
            array2[2] = Float.parseFloat(z2.getText().toString());
            array3 = test(array1, array2);

            String text = array3[0]+" "+array3[1]+" "+array3[2];
            textView1.setText(text);

        }

    });

}

public native float[] test(float[] array1, float[] array2);

static {
    System.loadLibrary("test");
}
}

以下是C++代码:

#include <iostream>
#include <Eigen/Dense>
#include <math.h>
#include <jni.h>

using namespace Eigen;

Vector3f vec;
Vector3f vec2;
Vector3f vecRtrn;


void vecLoad(float x, float y, float z, float x2, float y2, float z2){

vec(0) = x;
vec(1) = y;
vec(2) = z;
vec2(0) = x2;
vec2(1) = y2;
vec2(2) = z2;

 }

void vecAdd(Vector3f vecA, Vector3f vecB){
vecRtrn = vecA + vecB;
 }

extern "C"
{
JNIEXPORT jfloatArray JNICALL Java_jnimath_act_JnimathActivity_test
(JNIEnv *env, jobject obj, jfloatArray fltarray1, jfloatArray fltarray2)
{

jfloatArray result;
  result = env->NewFloatArray(3);
 if (result == NULL) {
     return NULL; /* out of memory error thrown */
 }

jfloat array1[3];
jfloat* flt1 = env->GetFloatArrayElements( fltarray1,0);
jfloat* flt2 = env->GetFloatArrayElements( fltarray2,0);


vecLoad(flt1[0], flt1[1], flt1[2], flt2[0], flt2[1], flt2[2]);
vecAdd(vec, vec2);

array1[0] = vecRtrn[0];
array1[1] = vecRtrn[1];
array1[2] = vecRtrn[2];

env->ReleaseFloatArrayElements(fltarray1, flt1, 0);
env->ReleaseFloatArrayElements(fltarray2, flt2, 0);
env->SetFloatArrayRegion(result, 0, 3, array1);
return result;

}
}

这是 Android.mk 文件:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)   
LOCAL_MODULE    := test
LOCAL_SRC_FILES := test.cpp
include $(BUILD_SHARED_LIBRARY)

您还需要设置一个Application.mk文件,以便您可以使用STL来使用Eigen:

APP_STL := stlport_static

最后但同样重要的是布局文件:

<?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" >

<TextView
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/hello" />

<EditText
    android:id="@+id/x"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="z" >

    <requestFocus />
</EditText>

<EditText
    android:id="@+id/y"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="y" />

<EditText
    android:id="@+id/z"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="z" />

<EditText
    android:id="@+id/x2"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="x2" />

<EditText
    android:id="@+id/y2"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="y2" />

<EditText
    android:id="@+id/z2"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="z2" />

<Button
    android:id="@+id/run"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="run" />

<TextView
    android:id="@+id/textView1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="matrix output" />

</LinearLayout>

我曾使用Cygwin来运行ndk-build命令,但现在你可以使用传统的Windows命令行完成相同的操作。你可以将此作为样本来学习如何使用NDK从Java传递一些数据到C++。关于这个问题,确实缺乏真正好的文档。另外,如果你想使用一个快速的本地数学库,请查看此链接中的Eigen:

http://eigen.tuxfamily.org/index.php?title=Main_Page

希望这些内容能像对我学习如何在Java与原生端之间传递数据一样,对其他人有所帮助 :)


没问题 :) 我花了两天时间才弄清楚如何使用JNI来获取和传递数据,所以我想分享一下我的解决方法,希望能帮到其他人。 - James andresakis
1
发布一些内容作为答案并接受它!;) - n00b
1个回答

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接