在JNI层创建C++实例,将其作为长整型对象传递给Java类,但方法返回垃圾值。

huangapple 未分类评论48阅读模式
英文:

Creating c++ instance in JNI Layer, passing it to Java class as a long object, but methods are returning garbage value

问题

I am new to JNI concept and concept of interaction between c++ and Java. I have created a Numbers class and wanted to add a java wrapper to abstract native layer. I have created a java class Maths.java and added functions I need to call and called native methods for each method in Java.

Main Activity.java

package com.example.maths2;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    public String TAG = "MainActivity.java";
    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //testing Maths class

        Log.d(TAG, "Creating Maths Object:");

        Maths math = new Maths(3, 5);

        Log.d(TAG, "Calling addition:");

        int addResult = math.add();

        Log.d(TAG, "Calling subtraction:");

        int subResult = math.sub();

        Log.d(TAG, "Calling Multiplication:");

        int mulResult = math.mul();

        //deleting c++ object

        math.destroy();

        // Example of a call to a native method
        TextView tv = findViewById(R.id.sample_text);

        //Testing the values
        tv.setText(stringFromJNI() + "Add: " + addResult + "Sub: " + subResult + "Mul : " + mulResult);
    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
}

Maths.java

package com.example.maths2;

public class Maths {

    private int a, b;

    private long numberptr = 0L; //Stores c++ pointer to Numbers object

    static {
        System.loadLibrary("native-lib");
    }

    public Maths(int a, int b) {
        a = a;
        b = b;
        createNumberInstance(a, b);
    }

    public int add() {
        return nativeAdd();
    }

    public int sub() {
        return nativeSub();
    }

    public int mul() {
        return nativeMul();
    }

    public void destroy() {
        numberptr = 0L;
        nativeDestroy();

    }

    //Native Methods
    public native void createNumberInstance(int a, int b);

    public native int nativeSub();

    public native int nativeAdd();

    public native int nativeMul();

    public native void nativeDestroy();
}

CmakeLists.txt

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

add_library( # Sets the name of the library.
             native-lib

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             native-lib.cpp

        Numbers.cpp)

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

find_library( # Sets the name of the path variable.
              log-lib

              # Specifies the name of the NDK library that
              # you want CMake to locate.
              log )

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
                       native-lib

                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )

native-lib.cpp

#include <jni.h>
#include <string>
#include "Numbers.h"

// Get pointer field
jfieldID getPtrFieldId(JNIEnv * env, jobject obj)
{
    static jfieldID ptrFieldId = 0;

    if (!ptrFieldId)
    {
        jclass c = env->GetObjectClass(obj);
        ptrFieldId = env->GetFieldID(c, "numberptr", "J");
        env->DeleteLocalRef(c);
    }

    return ptrFieldId;
}

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_maths2_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

extern "C"
JNIEXPORT void JNICALL
Java_com_example_maths2_Maths_createNumberInstance(JNIEnv *env, jobject thiz, jint a, jint b) {
    // TODO: implement createNumberInstance()

    env->SetLongField(thiz, getPtrFieldId(env, thiz), (jlong) new Numbers(a, b));

}

extern "C"
JNIEXPORT jint JNICALL
Java_com_example_maths2_Maths_nativeSub(JNIEnv *env, jobject thiz) {
    // TODO: implement nativeSub()

    Numbers* numb = (Numbers*) env->GetLongField(thiz, getPtrFieldId(env, thiz));

    return numb->add();

}

extern "C"
JNIEXPORT jint JNICALL
Java_com_example_maths2_Maths_nativeAdd(JNIEnv *env, jobject thiz) {
    // TODO: implement nativeAdd()

    Numbers* numb = (Numbers*) env->GetLongField(thiz, getPtrFieldId(env, thiz));

    return numb->sub();

}

extern "C"
JNIEXPORT jint JNICALL
Java_com_example_maths2_Maths_nativeMul(JNIEnv *env, jobject thiz) {
    // TODO: implement nativeMul()

    Numbers* numb = (Numbers*) env->GetLongField(thiz, getPtrFieldId(env, thiz));

    return numb->mul();
}

extern "C"
JNIEXPORT void JNICALL
Java_com_example_maths2_Maths_nativeDestroy(JNIEnv *env, jobject thiz) {
    // TODO: implement nativedestroy()

    Numbers* numb = (Numbers*) env->GetLongField(thiz, getPtrFieldId(env, thiz));

    delete numb;
}

Numbers.cpp

#include "Numbers.h"

Numbers::Numbers(int a, int b) {
    a = a;
    b = b;
}

int Numbers::add() {
    return a+b;
}

int Numbers::mul() {
    return a*b;
}

int Numbers::sub() {
    return a-b;
}

Numbers.h

//
//
//

#ifndef MATHS_NUMBERS_H
#define MATHS_NUMBERS_H


class Numbers {
    int a, b;

public:
    Numbers(int,int);
    int add();
   

<details>
<summary>英文:</summary>

I am new to JNI concept and concept of interaction between c++ and Java. I have created a Numbers class and wanted to add a java wrapper to abstract native layer. I have created a java class Maths.java and added functions I need to call and called native methods for each method in Java. I have first of all, created instance of Maths class in MainActivity.java and when we create object of Maths class, it is calling native method to create the instance of Numbers in c++ and setting long value for Numbers pointers in Java. I am calling various native functions by using this long value in native-lib.cpp(across JNI Layer) by typecasting it to c++ class. But as I am calling these functions, I am getting garbage value.

I am attaching the code. Can someone please tell me exact issue and why it is not working. 

Main Activity.java

    package com.example.maths2;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.os.Bundle;
    import android.util.Log;
    import android.widget.TextView;
    
    public class MainActivity extends AppCompatActivity {
    
        public String TAG = &quot;MainActivity.java&quot;;
        // Used to load the &#39;native-lib&#39; library on application startup.
        static {
            System.loadLibrary(&quot;native-lib&quot;);
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
    
            //testing Maths class
    
            Log.d(TAG, &quot;Creating Maths Object: &quot;);
    
            Maths math = new Maths(3, 5);
    
            Log.d(TAG, &quot;Calling addition: &quot;);
    
            int addResult = math.add();
    
            Log.d(TAG, &quot;Calling subtraction: &quot;);
    
            int subResult = math.sub();
    
            Log.d(TAG, &quot;Calling Multiplication: &quot;);
    
            int mulResult = math.mul();
    
            //deleting c++ object
    
            math.destroy();
    
            // Example of a call to a native method
            TextView tv = findViewById(R.id.sample_text);
    
            //Testing the values
            tv.setText(stringFromJNI() + &quot;Add: &quot; + addResult + &quot;Sub: &quot; + subResult + &quot;Mul : &quot; + mulResult);
        }
    
        /**
         * A native method that is implemented by the &#39;native-lib&#39; native library,
         * which is packaged with this application.
         */
        public native String stringFromJNI();
    }

Maths.java

    package com.example.maths2;
    
    public class Maths {
    
        private int a, b;
    
        private long numberptr = 0L; //Stores c++ pointer to Numbers object
    
        static {
            System.loadLibrary(&quot;native-lib&quot;);
        }
    
        public Maths(int a, int b) {
            a = a;
            b = b;
            createNumberInstance(a, b);
        }
    
        public int add() {
            return nativeAdd();
        }
    
        public int sub() {
            return nativeSub();
        }
    
        public int mul() {
            return nativeMul();
        }
    
        public void destroy() {
            numberptr = 0L;
            nativeDestroy();
    
        }
    
        //Native Methods
        public native void createNumberInstance(int a, int b);
    
        public native int nativeSub();
    
        public native int nativeAdd();
    
        public native int nativeMul();
    
        public native void nativeDestroy();
    }

CmakeLists.txt



    # For more information about using CMake with Android Studio, read the
    # documentation: https://d.android.com/studio/projects/add-native-code.html
    
    # Sets the minimum version of CMake required to build the native library.
    
    cmake_minimum_required(VERSION 3.4.1)
    
    # Creates and names a library, sets it as either STATIC
    # or SHARED, and provides the relative paths to its source code.
    # You can define multiple libraries, and CMake builds them for you.
    # Gradle automatically packages shared libraries with your APK.
    
    add_library( # Sets the name of the library.
                 native-lib
    
                 # Sets the library as a shared library.
                 SHARED
    
                 # Provides a relative path to your source file(s).
                 native-lib.cpp
    
            Numbers.cpp)
    
    # Searches for a specified prebuilt library and stores the path as a
    # variable. Because CMake includes system libraries in the search path by
    # default, you only need to specify the name of the public NDK library
    # you want to add. CMake verifies that the library exists before
    # completing its build.
    
    find_library( # Sets the name of the path variable.
                  log-lib
    
                  # Specifies the name of the NDK library that
                  # you want CMake to locate.
                  log )
    
    # Specifies libraries CMake should link to your target library. You
    # can link multiple libraries, such as libraries you define in this
    # build script, prebuilt third-party libraries, or system libraries.
    
    target_link_libraries( # Specifies the target library.
                           native-lib
    
                           # Links the target library to the log library
                           # included in the NDK.
                           ${log-lib} )

native-lib.cpp

    #include &lt;jni.h&gt;
    #include &lt;string&gt;
    #include &quot;Numbers.h&quot;
    
    // Get pointer field
    jfieldID getPtrFieldId(JNIEnv * env, jobject obj)
    {
        static jfieldID ptrFieldId = 0;
    
        if (!ptrFieldId)
        {
            jclass c = env-&gt;GetObjectClass(obj);
            ptrFieldId = env-&gt;GetFieldID(c, &quot;numberptr&quot;, &quot;J&quot;);
            env-&gt;DeleteLocalRef(c);
        }
    
        return ptrFieldId;
    }
    
    extern &quot;C&quot; JNIEXPORT jstring JNICALL
    Java_com_example_maths2_MainActivity_stringFromJNI(
            JNIEnv* env,
            jobject /* this */) {
        std::string hello = &quot;Hello from C++&quot;;
        return env-&gt;NewStringUTF(hello.c_str());
    }
    
    
    extern &quot;C&quot;
    JNIEXPORT void JNICALL
    Java_com_example_maths2_Maths_createNumberInstance(JNIEnv *env, jobject thiz, jint a, jint b) {
        // TODO: implement createNumberInstance()
    
        env-&gt;SetLongField(thiz, getPtrFieldId(env, thiz), (jlong) new Numbers(a, b));
    
    }
    
    extern &quot;C&quot;
    JNIEXPORT jint JNICALL
    Java_com_example_maths2_Maths_nativeSub(JNIEnv *env, jobject thiz) {
        // TODO: implement nativeSub()
    
        Numbers* numb = (Numbers*) env-&gt;GetLongField(thiz, getPtrFieldId(env, thiz));
    
        return numb-&gt;add();
    
    }
    
    extern &quot;C&quot;
    JNIEXPORT jint JNICALL
    Java_com_example_maths2_Maths_nativeAdd(JNIEnv *env, jobject thiz) {
        // TODO: implement nativeAdd()
    
        Numbers* numb = (Numbers*) env-&gt;GetLongField(thiz, getPtrFieldId(env, thiz));
    
        return numb-&gt;sub();
    
    }
    
    extern &quot;C&quot;
    JNIEXPORT jint JNICALL
    Java_com_example_maths2_Maths_nativeMul(JNIEnv *env, jobject thiz) {
        // TODO: implement nativeMul()
    
        Numbers* numb = (Numbers*) env-&gt;GetLongField(thiz, getPtrFieldId(env, thiz));
    
        return numb-&gt;mul();
    }
    
    extern &quot;C&quot;
    JNIEXPORT void JNICALL
    Java_com_example_maths2_Maths_nativeDestroy(JNIEnv *env, jobject thiz) {
        // TODO: implement nativedestroy()
    
        Numbers* numb = (Numbers*) env-&gt;GetLongField(thiz, getPtrFieldId(env, thiz));
    
        delete numb;
    }

Numbers.cpp


    #include &quot;Numbers.h&quot;
    
    Numbers::Numbers(int a, int b) {
        a = a;
        b = b;
    }
    
    int Numbers::add() {
        return a+b;
    }
    
    int Numbers::mul() {
        return a*b;
    }
    
    int Numbers::sub() {
        return a-b;
    }

Numbers.h

    //
    //
    //
    
    #ifndef MATHS_NUMBERS_H
    #define MATHS_NUMBERS_H
    
    
    class Numbers {
        int a, b;
    
    public:
        Numbers(int,int);
        int add();
        int mul();
        int sub();
    };
    
    
    #endif //MATHS_NUMBERS_H

Please someone tell me what should be done or can correct the things that are getting wrong. 

</details>


huangapple
  • 本文由 发表于 2020年5月29日 15:40:00
  • 转载请务必保留本文链接:https://java.coder-hub.com/62080981.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定