Passing parameters and receiving returns in primitive types

Java code can pass parameters to native methods and receive the processing results returned. This recipe walks through how to pass parameters and receive returns in primitive types.

Getting ready

You should have built at least one Android application with native code before reading this recipe. If you haven't done so, please read the Writing a Hello NDK program recipe in Chapter 1, Hello NDK first.

How to do it…

The following steps create a sample Android application with native methods receiving input parameters from the Java code and returning the processing result back:

  1. Create a project named PassingPrimitive. Set the package name as cookbook.chapter2. Create an activity named PassingPrimitiveActivity. Under this project, create a folder named jni. Please refer to the Loading native libraries and registering native methods recipe in this chapter if you want more detailed instructions.
  2. Add a file named primitive.c under the jni folder and implement the native methods. In our sample project, we implemented one native method for each of the eight primitive data types. Following is the code for jboolean, jint, and jdouble. Please refer to the downloaded code for the complete list of methods:
    #include <jni.h>
    #include <android/log.h>
    
    JNIEXPORT jboolean JNICALL Java_cookbook_chapter2_PassingPrimitiveActivity_passBooleanReturnBoolean(JNIEnv *pEnv, jobject pObj, jboolean pBooleanP){
      __android_log_print(ANDROID_LOG_INFO, "native", "%d in %d bytes", pBooleanP, sizeof(jboolean));
      return (!pBooleanP);
    }
    
    JNIEXPORT jint JNICALL Java_cookbook_chapter2_PassingPrimitiveActivity_passIntReturnInt(JNIEnv *pEnv, jobject pObj, jint pIntP) {
      __android_log_print(ANDROID_LOG_INFO, "native", "%d in %d bytes", pIntP, sizeof(jint));
      return pIntP + 1;
    }
    
    JNIEXPORT jdouble JNICALL Java_cookbook_chapter2_PassingPrimitiveActivity_passDoubleReturnDouble(JNIEnv *pEnv, jobject pObj, jdouble pDoubleP) {
      __android_log_print(ANDROID_LOG_INFO, "native", "%f in %d bytes", pDoubleP, sizeof(jdouble));
      return pDoubleP + 0.5;
    }
  3. In the PassingPrimitiveActivity.java Java code, we add code to load the native library, declare the native methods, and call the native methods. Following is that part of the code. The "" indicates the part that is not shown. Please refer to the source file downloaded from the website for the complete code:
    @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_passing_primitive);
            StringBuilder strBuilder = new StringBuilder();
            strBuilder.append("boolean: ").append(passBooleanReturnBoolean(false)).append(System.getProperty("line.separator"))
             ......
    
              .append("double: ").append(passDoubleReturnDouble(11.11)).append(System.getProperty("line.separator"));
            TextView tv = (TextView) findViewById(R.id.display_res);
            tv.setText(strBuilder.toString());
        }
        private native boolean passBooleanReturnBoolean(boolean p);
        private native byte passByteReturnByte(byte p);
        private native char passCharReturnChar(char p);
        private native short passShortReturnShort(short p);
        ......
        static {
            System.loadLibrary("PassingPrimitive");
        }
  4. Modify the res/layout/activity_passing_primitive.xml file according to step 8 of the Loading native libraries and registering native methods recipe of this chapter or the downloaded project code.
  5. Create a file named Android.mk under the jni folder, and add the following content to it:
    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_MODULE    := PassingPrimitive
    LOCAL_SRC_FILES := primitive.c
    LOCAL_LDLIBS := -llog
    include $(BUILD_SHARED_LIBRARY)
  6. Start a terminal, go to the jni folder, and type ndk-build to build the native library PassingPrimitive.
  7. In Eclipse, select Window | Show View | LogCat to show the logcat console. Alternatively, start a terminal and enter the following command in your terminal to show logcat output on it:
    $adb logcat -v time
  8. Run the project on an Android device or emulator. You should see something similar to the following screenshot:
    How to do it…

    The logcat output is as follows:

    How to do it…

How it works…

The code illustrates how to pass parameters and receive returns in primitive types from the native method. We created one method for each primitive type. In the native code, we printed the received value to logcat, modified the value, and returned it back.

  • JNI primitive type and Java primitive type mapping: The primitive types in JNI and Java have the following mapping:

    Java Type

    JNI Type

    Number of bytes

    Sign

    boolean

    jboolean

    1

    unsigned

    byte

    jbyte

    1

    signed

    char

    jchar

    2

    unsigned

    short

    jshort

    2

    signed

    int

    jint

    4

    signed

    long

    jlong

    8

    signed

    float

    jfloat

    4

    -

    double

    jdouble

    8

    -

    Note that both Java char and JNI jchar are two bytes, while the C/C++ char type is only one byte long. In fact, C/C++ char are interchangeable with jbyte instead of jchar in JNI programming.

  • Android log library: We output the received values to the Android logging system at a native method, by using the following code:
    __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__);

    ANDROID_LOG_INFO is an enum value defined in android/log.h, which indicates that we're using the info-level logging. LOG_TAG can be any strings, and __VA_ARGS__ is replaced by the parameters passed to the API, in a format similar to the printf method in C.

    We must include the android/log.h header in the native code to use the log functions:

    #include <android/log.h>

    Besides this, we'll need to include the NDK log library in the Android.mk file in order to use the API:

    LOCAL_LDLIBS := -llog

We will cover more details about Android logging API in Chapter 3, Build and Debug NDK Applications, while utilizing logging API for debugging purposes.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset