android – A simple ndk project using the Eigen library and jni-ThrowExceptions

Exception or error:

So today with some help from the people on here I put together a simple android app that uses the ndk. I imported the eigen library right into the jni folder that I created in the source tree and then using cygwin I was able to compile the project. Heres the source so other people trying to learn jni basics passing data back and forth from c++ to java and back have some code to go by. The app just takes 6 numbers in edittext fields and when the user clicks the button two float arrays are passed to the native method and loaded into two eigen float vectors where they are then added together. The product of the two vectors is passed back to java and then displayed in a textview.

Heres a link to the eigen library for android:

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

You just need the actual eigen folder which is one layer down in the file tree. Just copy and paste the eigen folder thats one layer into the eigen source and place inside the jni folder that you create to hold your c++ code in your android project.

Heres the 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");
}
}

And the C++ code:

#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;

}
}

Now heres the Android.mk file:

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

Youll also need to set up an Application.mk so you can use the stl to use eigen:

APP_STL := stlport_static

Last but not least is the layout file:

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

I actually used cygwin to use the ndk-build command but you can now use the good old windows command line to do the same thing. Go ahead and use this as a sample to learn how to pass some data from java to c++ using the ndk. There definitely is a severe lack of really good documentation on the matter. Also if your looking to use a fast native math library check out eigen at this link:

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

I hope this stuff helps some one out like it helped me to learn how to pass data from java to the native side and back 🙂

How to solve:

So this was something that got me started being able to pass values back and forth from java to c++ but here’s a really great full fledged tutorial on the ndk

http://code.google.com/p/awesomeguy/wiki/JNITutorial

I picked up a bunch of stuff from there as well as this book

http://www.amazon.com/Android-Beginners-Guide-Sylvain-Ratabouil/dp/1849691525

Leave a Reply

Your email address will not be published. Required fields are marked *