Channels ▼
RSS

C/C++

Accessing C++11 Features of the Android NDK


Working with C++11 Features and the STL

Now, it is time to add the C++ code that uses C++11 features and STL. The following lines show the contents of the cplusplus11.cpp file that defines the Java_com_example_MainActivity_sumArray JNI function. In this case, I haven't created the header file (in order to keep things simple) and I just use a single cpp file.

#include <jni.h>

#include <algorithm>
#include <iterator>
#include <vector>

// In order to log
#include <android/log.h>

#define LOG_TAG "CPlusPlus11_sumArray"

using namespace std;

extern "C" {
	JNIEXPORT jint JNICALL
	Java_com_example_MainActivity_sumArray
	(JNIEnv *env, jobject obj, jintArray arr)
	{
		auto len = env->GetArrayLength(arr);
		__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "arr length is %d", len);

		jint *body = env->GetIntArrayElements(arr,0);
		vector<int> numbers(body, body + len);

		int sum = 0;
		for_each(numbers.begin(), numbers.end(), [&sum] (int y) {
			sum += y;
		});

		env->ReleaseIntArrayElements(arr,body,0);

		__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "sum(arr) = %d", sum);

		return sum;
	}
}

Java_com_example_MainActivity_sumArray receives three arguments and returns a jint. The third argument, named arr, is a Java int array (jintArray). The function returns the sum of the Java int array received as an argument.

The code uses the auto keyword and includes three STL headers: algorithm, iterator, and vector. There is some code to retrieve the information from the jintArray and convert it into a vector<int> named numbers. This way, the code can use for_each to calculate the sum of all the elements in the numbers vector. Of course, for_each uses a C++11 lambda expression to perform the sum, this is done just to demonstrate the use of different C++11 features. Note that the "range for" statement isn't supported, so the following code wouldn't compile:

for (auto n : numbers)
    sum += n;

There are two calls to the __android_log_print function to send formatted strings to the log. This way, it is possible to check the information in the LogCat within Eclipse when you execute the app on your Android virtual device with the C++11_sumArray tag. Because there are so many configurations involved in making C++11 features and the STL work as expected, it is usually best to send some information to the log to check whether the Java-to-native calls are working correctly.

If you build the project, a libcplusplus11.so library will be generated for each ABI specified in the Application.mk file. You will find each generated library in subfolders within the libs folder. For example, if you included x86, you will find a /libs/x86/libcplusplus11.so library in your project structure.

Finally, it is necessary to add Java code to load the libcplusplus11.so library and call the previously defined native method. The following lines show the code for src/com.example/MainActivity.java that defines the MainActivity class, loads the library, and calls the native method in OnCreate.

package com.example;

import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBar;
import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.os.Build;

public class MainActivity extends ActionBarActivity {
    private native int sumArray(int arr[]);
    
    static {
    	System.loadLibrary("cplusplus11");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        TextView textView = new TextView(this);
        
		int arr[] = new int[10];
		arr[0] = 3;
		arr[1] = 7;
		arr[2] = 45;
		arr[3] = 9;
		arr[4] = 32;
		arr[5] = 23;
		arr[6] = 44;
		arr[7] = 12;
		arr[8] = 34;
		arr[9] = 56;
		int sum = sumArray(arr);

		textView.setText(String.format("C++11 Sum: %d", sum));
        setContentView(textView);
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    /**
     * A placeholder fragment containing a simple view.
     */
    public static class PlaceholderFragment extends Fragment {

        public PlaceholderFragment() {
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            View rootView = inflater.inflate(R.layout.fragment_main, container, false);
            return rootView;
        }
    }
}

The MainActivity class includes a line with the definition of the native method in Java. As I explained before, the method returns a Java int and receives a Java int array.

private native int sumArray(int arr[]);

The call to System.loadLibrary loads and links the libcplusplus11.so library. Notice that the specified name is cplusplus11, but the method will map the name to the full path for loading the library based on the platform and will add the lib prefix and the .so extension.

static {</p>
       System.loadLibrary("cplusplus11");</p>
}

The OnCreate method creates an int array with 10 elements (arr), and uses it as an argument to call the sumArray native method. This method will end up calling the Java_com_example_MainActivity_sumArray method exported in the libcplusplus11.so library. Once the native method finishes its execution, a TextView will display the sum result (see Figure 2).

C++11andANDROID NDK
Figure 2: The Android app displaying the results of calling C++ code with C++11 features from Java.

Conclusion

Android Development Tools has made many changes in the latest versions, so many tutorials that were valid for previous versions aren't compatible with the newest releases. These latest releases really simplified working with the Android NDK without forcing you to leave Eclipse. You just need to follow a few simple steps to configure your project to add support for C++11 features and STL. In this case, I took advantage of the auto keyword, lambda expressions, iterators, vector, and for_each. Obviously, there are many other options and possible configurations to enable additional features. You can easily explore them using this example as a baseline.


Gastón Hillar is a senior contributing editor at Dr. Dobb's.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video