Overview
Examples
Screenshots
Comparisons
Applications
Download
Documentation
Tutorials
UppHub
Status & Roadmap
FAQ
Authors & License
Forums
Funding U++
Search on this site











SourceForge.net Logo

SourceForge.net Logo

GitHub Logo

Discord Logo

AndroidMath

 

Android builder juicy example

Description

The main goal of this example is to show major capabilities of Android Builder. We draw the attention on mixing Java and C/C++ code in one project. Moreover we show how to use supportive package (AndroidMathUtility). It is really important, because whole U++ architecture is highly modular.

Please notice that you can generate JNI stubs by clicking on preprocess button inside TheIDE during editing Java files. Before doing this make sure you have selected AndroidBuilder base build method.

Result

 

 

MemoryManager.h

 

#ifndef _JniMath_MemoryManager_h_

#define _JniMath_MemoryManager_h_

 

#include <jni.h>

#include <vector>

#include <string>

#include <sstream>

 

static const char* FieldNativeAddress = "nativeAdress";

 

static const char* LongSig = "J";

 

/**

* Java simple memory manager.

*/

template <class T>

class MemoryManager {

public:

    ~MemoryManager()

    {

        for(int i = 0; i < values.size(); i++) {

            delete values[i];

        }

    }

 

    void Insert(JNIEnv *env, jobject jobj, T* value)

    {

        if(jobj != NULL) {

            values.push_back(value);

            

            SetNativeAdress(env, jobj, values[values.size() - 1]);

        }

    }

    

    void MakeCopy(JNIEnv *env, jobject jobjThis, jobject jobjThat)

    {

        if(!env->IsSameObject(jobjThis, jobjThat)) {

            T* t = Get(env, jobjThat);

            Insert(env, jobjThis, t);

        }

    }

    

    void Erase(JNIEnv *env, jobject jobj)

    {

        int idx = FindIdx(env, jobj);

        if(idx >= 0)

            values.erase(values.begin() + idx);

    }

    

    T* Get(JNIEnv *env, jobject jobj)

    {

        int idx = FindIdx(env, jobj);

        return idx >= 0 ? values[idx] : NULL;

    }

    

    int GetCount()

    {

        return static_cast<int>(values.size());

    }

    

private:

    int FindIdx(JNIEnv *env, jobject jobj)

    {

        for(int i = 0; i < values.size(); i++) {

            if(GetNativeAdress(env, jobj) == values[i]) {

                return i;

            }

        }

        return -1;

    }

    

private:

    T* GetNativeAdress(JNIEnv* env, jobject jobj)

    {

        jclass objectClass = env->GetObjectClass(jobj);

        

        jfieldID adressField = GetNativeAdressField(env, objectClass);

        

        env->DeleteLocalRef(objectClass);

        return (T*)env->GetLongField(jobj, adressField);

    }

    

    void SetNativeAdress(JNIEnv* env, jobject jobj, T* obj)

    {

        jclass objectClass = env->GetObjectClass(jobj);

        

        jfieldID adressField = GetNativeAdressField(env, objectClass);

        env->SetLongField(jobj, adressField, (jlong)obj);

        

        env->DeleteLocalRef(objectClass);

    }

    

    jfieldID GetNativeAdressField(JNIEnv* env, jclass clazz)

    {

        return env->GetFieldID(clazz, FieldNativeAddress, LongSig);

    }

    

private:

    std::vector<T*> values;

};

 

#endif

 

 

 

Vector.cpp

 

#include <jni.h>

#include <map>

#include <vector>

#include <sstream>

#include <string>

 

#include <AndroidMathUtility/AndroidMathUtility.h>

 

#include "MemoryManager.h"

 

using AndroidMathUtility::Vector;

 

static MemoryManager<Vector> mm;

 

extern "C" {

 

    JNIEXPORT void JNICALL Java_org_upp_AndroidMath_Vector_construct(

        JNIEnv *env,

        jobject obj,

        jint size)

    {

        mm.Insert(env, obj, new Vector(size));

    }

 

    JNIEXPORT void JNICALL Java_org_upp_AndroidMath_Vector_copyConstruct(

        JNIEnv *env,

        jobject jobjThis,

        jobject jobjThat)

    {

        mm.MakeCopy(env, jobjThis, jobjThat);

    }

 

    JNIEXPORT void JNICALL Java_org_upp_AndroidMath_Vector_nativeFinalize(

        JNIEnv *env,

        jobject obj)

    {

        mm.Erase(env, obj);

    }

    

    JNIEXPORT jint JNICALL Java_org_upp_AndroidMath_Vector_getSize(

        JNIEnv *env,

        jobject obj)

    {

        Vector* vec = mm.Get(env, obj);

        

        return vec->GetSize();

    }

 

    JNIEXPORT jfloat JNICALL Java_org_upp_AndroidMath_Vector_get(

        JNIEnv *env,

        jobject obj,

        jint id)

    {

        Vector* vec = mm.Get(env, obj);

        

        return vec->Get(id);

    }

    

    JNIEXPORT void JNICALL Java_org_upp_AndroidMath_Vector_set(

        JNIEnv *env,

        jobject obj,

        jint id,

        jfloat value)

    {

        Vector* vec = mm.Get(env, obj);

        vec->Set(id, value);

    }

    

    JNIEXPORT void JNICALL Java_org_upp_AndroidMath_Vector_multipleByScalar(

        JNIEnv *env,

        jobject obj,

        jfloat scalar)

    {

        Vector* vec = mm.Get(env, obj);

        vec->MultipleByScalar(scalar);

    }

    

    JNIEXPORT jstring JNICALL Java_org_upp_AndroidMath_Vector_toString(

        JNIEnv *env,

        jobject obj)

    {

        Vector* vec = mm.Get(env, obj);

        

        return env->NewStringUTF((vec->ToString()).c_str());

    }

 

} // extern "C"

 

 

 

AndroidMath.cpp

 

#include <string.h>

#include <jni.h>

 

#include <AndroidMathUtility/AndroidMathUtility.h>

 

extern "C" {

 

    JNIEXPORT jint JNICALL Java_org_upp_AndroidMath_AndroidMath_power(

        JNIEnv *,

        jclass,

        jint number,

        jint n)

    {

        return AndroidMathUtility::Power(number, n);

    }

 

} // extern "C"

 

 

 

AndroidMathActivity.java

 

package org.upp.AndroidMath;

 

import android.app.Activity;

import android.widget.TextView;

import android.widget.ScrollView;

import android.os.Bundle;

 

public class AndroidMathActivity extends Activity

{

    @Override

    public void onCreate(Bundle savedInstanceState)

    {

        super.onCreate(savedInstanceState);

        

        ScrollView scroller = new ScrollView(this);

        TextView tv = new TextView(this);

        

        calculatePowerOperations(tv, 20);

        calculateVectorOperations(tv);

        

        scroller.addView(tv);

        setContentView(scroller);

    }

 

    private void calculatePowerOperations(TextView tv, int maxPower)

    {

        String text = "Power:\n";

        int maxNumber = maxPower;

        for(int i = 1; i <= maxNumber; i++) {

            int pow = AndroidMath.power(i, 2);

            text += Integer.toString(i) + "^2 = " + Integer.toString(pow) + "\n";

        }

        

        tv.append(text);

    }

    

    private void calculateVectorOperations(TextView tv)

    {

        String text = "Vector operations:\n";

        

        Vector vec1 = new Vector(3);

        vec1.set(0, 3.0f);

        vec1.set(1, -1.0f);

        vec1.set(2, 5.0f);

        

        text += "Vec1: " + vec1.toString() + "\n";

        

        Vector vec1Copy = new Vector(vec1);

        vec1Copy.multipleByScalar(5.0f);

        text += "3 * Vec1: " + vec1Copy.toString() + "\n";

        

        Vector vec2 = new Vector(4);

        vec2.set(0, -2.0f);

        vec2.set(1, 4.0f);

        vec2.set(2, 7.0f);

        vec2.set(3, -9.0f);

        

        text += "Vec2: " + vec2.toString() + "\n";

        

        tv.append(text);

    }

    

    static {

        // For Android version less than 5.0 we need to specific standard library

        // If you have a crash uncomment library that you specific in your Android Builder

        // specification.

        

        // System.loadLibrary("stlport_shared");

        // System.loadLibrary("gnustl_shared");

        // System.loadLibrary("c++_shared");

        

        // In this place we are loading native libraries (In revers dependency order).

        // IMPORTANT: Native library always has upp package name!!!

        System.loadLibrary("AndroidMathUtility");

        System.loadLibrary("AndroidMath");

    }

}

 

 

 

Vector.java

 

package org.upp.AndroidMath;

 

/**

* Math vector class which whole implementation is native (c/c++).

*/

public class Vector

{

    /**

     * Field use by MemoryManager to store pointer to c++ object.

     * If you want to use MemoryManager with your class make sure you have this field

     * in your class.

     */

    private long nativeAdress = 0;

    

    /**

     * We override finalize method, because we need to destroy native c++ object when

     * there is not more reference to Java object. This method is called by default

     * by garbage collector.

     */

    @Override

    protected void finalize() throws Throwable

    {

        nativeFinalize();

        super.finalize();

    }

    

    public Vector(int size)

    {

        construct(size);

    }

    

    public Vector(Vector vec)

    {

        copyConstruct(vec);

    }

    

    // Native stuff - C/C++

    public native int   getSize();

    public native float get(int id);

    

    public native void set(int id, float value);

    

    public native void multipleByScalar(float scalar);

    

    public native String toString();

    

    private native void construct(int size);

    private native void copyConstruct(Vector vec);

    private native void nativeFinalize();

}

 

 

 

AndroidMath.java

 

package org.upp.AndroidMath;

 

/**

* Native math functions from package AndroidMathUtility.

*/

public class AndroidMath

{

    private AndroidMath() {}

    

    // Native stuff - C/C++

    public static native int power(int number, int n);

    

}

 

 

 

AndroidManifest.xml

 

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

     package="org.upp.AndroidMath">

    <uses-sdk android:minSdkVersion="21" />

   <application

        android:allowBackup="true">

       <activity android:name=".AndroidMathActivity"

                 android:label="AndroidMath">

           <intent-filter>

               <action android:name="android.intent.action.MAIN" />

               <category android:name="android.intent.category.LAUNCHER" />

           </intent-filter>

       </activity>

    </application>

</manifest>

 

 

 

 

Do you want to contribute?