Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A simple ndk project using the Eigen library and jni

Tags:

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 :)

like image 899
James andresakis Avatar asked Dec 17 '11 06:12

James andresakis


People also ask

What is NDK and JNI?

JNI is just the way that Java handles calling into native/C++ code, and calling back into Java from there. It has nothing to say about Android - it is a Java language feature. The Android NDK is a way to write Android applications using code called by JNI.

What is JNI in Android R?

JNI is the Java Native Interface. It defines a way for the bytecode that Android compiles from managed code (written in the Java or Kotlin programming languages) to interact with native code (written in C/C++).


1 Answers

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

like image 152
James andresakis Avatar answered Oct 22 '22 09:10

James andresakis