Reader small image

You're reading from  Asynchronous Android Programming - Second Edition

Product typeBook
Published inJul 2016
Reading LevelBeginner
PublisherPackt
ISBN-139781785883248
Edition2nd Edition
Languages
Tools
Right arrow
Author (1)
Steve Liles
Steve Liles
author image
Steve Liles

Steve Liles is a self-confessed geek and has been an Android fan since the launch day of the G1. When he isn't at work building publishing systems and apps for newspapers and magazines, you'll find him tinkering with his own apps, building 3D printers, or playing RTS games. He is currently working with a start-up to build an advertising system that links the print and digital worlds using computer vision on Android and iOS devices.
Read more about Steve Liles

Right arrow

Chapter 9. Asynchronous Work on the Native Layer

In previous chapters, we have been using Java thread APIs and concurrent primitives delivered by the Android SDK to build our asynchronous constructs. A Java thread, an independent line of execution in our application, is automatically attached to the Android virtual machine and is bound to one native thread on the system. In previous chapter examples, we executed Java compiled bytecode on the JVM and used Java synchronization and concurrent primitives to solve correctness and liveness issues.

In this chapter, we will make use of the Java Native Interface (JNI) to execute code written in C/C++ and compile it to native code. The native code, which runs directly on the hardware and makes use of the native CPU Application Binary Interface (ABI), generally runs faster than the bytecode due to optimizations made by the compilers, or optimizations introduced by developers with the use of specific ABI techniques. Hence, when we perform intensive...

Introduction to JNI


JNI is an interface that allows the execution of native code, written on C, C++, or Assembly, from the Java Virtual Machine (JVM). The interface strictly defines the way that any JNI implementation should act to manage and control the interactions between Java code and the machine code. Moreover, the machine code is able to interact with the JVM and create objects, execute member functions, modify the member variables and handle Java exceptions.

The JNI, which allows you to execute machine code along with your Java code, is typically used to:

  • Accelerate some critical portions of your application. Since the code runs directly on the hardware, it could make use of specific instruction sets to improve the execution:

    • Example: The use of SIMD instructions to accelerate audio or video floating-point operations.

  • Integrate existing C/C++ libraries in to your Android application. You can port any legacy code or library written to the Android platform and use it on your Android...

Calling C functions from Java code


The powerful JNI interface, as referred to before, is able to manage interaction in both directions, from Java to C and from C to Java.

A regular Java class declaring a method with the keyword native declares that the method behavior is implemented in native code. Like a regular Java method, the JNI native method is able to receive Java objects or primitive types as arguments and return primitive types and objects.

Let's see how a native method definition will look like in a Java class:

public class MyNativeActivity extends Activity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    ...
    cTv.setText(isPrime(2) ? "true" : "false");
  }
  …
  private native boolean isPrime(int number );
}

The preceding activity will call the native code to check whether a number is prime or not and print the result on the UI.

Notice that our function receives a primitive as an argument and return a primitive boolean as a result and does not have any...

Calling C++ functions from native code


So far, we have called a C function implemented in the c_functions.c source, so, in the next section, we will show you how to call a C++ member class.

First, we will add the isPrimeCPlusPlus native method to MyNativeActivty that returns String as a result. Let's see how the native function declaration will look:

public class MyNativeActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
      ...
      TextView cPlusTv = (TextView)  
          findViewById(R.id.helloFromCPlusPlus);
      cPlusTv.setText(isPrimeCPlusPlus(4));
    }

    public native String isPrimeCPlusPlus(int number);
}

Running the javah tool against the new MyNativeActivity class definition will generate a new function declaration with the following signature:

JNIEXPORT jstring JNICALL Java_com_packpublishing_asynchronousandroid_chapter9_MyNativeActivity_isPrimeCPlusPlus(JNIEnv *, jobject, jint);

Next, we are going to implement the prime function...

Accessing Java objects from native code


When we call a native function, the C or C++ function receives a JNIEnv pointer to a table of JNI methods used to interact with JVM Runtime. The JNIEnv pointer provides us with a set of primitives ready to find a Java class definition, set or get Java object field values, call static or member Java object functions, create Java objects, interact with Java monitors, or deal with exceptions.

Our next example will count the number of words on an EditText UI Widget on a native function and update a TextView text with count results from the native code. Therefore, we will learn how to use JNIEnv to access a member Java object field and how to call a Java object method (TextView.setText) using the JNIEnv interface.

Let's start by defining our native function and invoke it every time the EditField content changes:

public class MyNativeActivity extends Activity {
   
  protected EditText inputTextEt = null;
  protected TextView charCountTv = null;

  @Override...

Executing native background work on Java threads


In previous sections, we used the JNI interface to execute native functions on the main thread. Since they run on the main thread, the functions were able to update the UI, access the Activity instance fields, and or update any UI widget directly.

However, as we discussed before, for long computing or intensive tasks we have to execute them on the background thread.

In previous sections, we learned how to use the AsyncTask, Loader, Handler, and Remote Services to execute work on background threads that don't reduce the UI responsiveness or interfere with UI rendering.

In any of these Android specific constructs, the background thread is already attached to the JVM. Hence, the background thread already possesses access to a ready to use JNI environment.

In our next example, we will make use of the Loader construct and build AsyncTaskLoader, that loads an image on the background, converts the image to gray scale in native code, and publishes...

Executing asynchronous work on a native thread


The Android NDK is bundled with the POSIX thread C API that provides an API to create and destroy native threads, native mutual exclusion synchronization primitives, named mutexes, and condition variables, that like Java monitors, allow threads to wait until a change in a resource happens. Apart from this global API, the developer also has access to a higher level C++11 thread API available on clang and gnu_stl C++ Runtimes.

Since both of these frameworks offer the same kind of concurrent functionalities we will use C++11 thread framework for its simplicity and similarity with the Java Thread API.

First, let's update our ndk build.gradle to use the clang C++ Runtime that supports the thread API that we are going to use in our following code examples:

ndk {
  moduleName "mylib"
  stl "c++_shared"
  cppFlags.add("-frtti")
  cppFlags.add("-exceptions)
}

Attaching and detaching native threads from JVM

In order to interact with our JVM and execute background...

Handling Java exceptions in the native layer


While in Java, when an exception is thrown during a method execution, the JVM stops the normal method execution and tries to find an exception handler in the runtime to take control of execution, the same does not apply when you execute the Java method from the JNI code.

The JNI requires developers to explicitly implement the exception handling after an exception has occurred in a Java method invocation.

Moreover, when exception handling is pending, only a few JNI functions are safe to be invoked: DeleteGlobalRef, DeleteLocalRef, DeleteWeakGlobalRef, ExceptionCheck, ExceptionClear, ExceptionDescribe, ExceptionOccurred, MonitorExit, PopLocalFrame, PushLocalFrame, Release<PrimitiveType>ArrayElements, ReleasePrimitiveArrayCritical, ReleaseStringChars, ReleaseStringCritical, and ReleaseStringUTFChars.

There are three ways to handle Java exceptions in a native function.

The first way is to clear the pending exception with ExceptionClear and continue...

Interacting with a Java monitor from native code


So far, we have been synchronizing access to shared resources in Java threads using synchronized statements or synchronized methods:

synchronized (obj) { ... // synchronized block }
synchronized void incrementCount() { ... // synchronized methods }

When we are executing a native method and want to have access to a resource or variable shared between multiple Java code and native code, the JNI offers us MonitorEnter and MonitorExit methods to control access to the mutual exclusion zone managed by a Java synchronized block:

jint MonitorEnter(JNIEnv *env, jobject obj);
jint MonitorExit(JNIEnv *env, jobject obj);

MonitorEnter, the function responsible for acquiring access to the Java monitor scope, might block when another native thread or Java thread is the owner of the monitor. When any thread acquires access to the block, JVM will make sure that no other thread enters the critical section apart from the current thread.

MonitorExit is the function...

Summary


In this chapter we introduce you to the JNI, a standard API available on Java to interact with native code written in Assembly, C or C++ that it is available to any Android Developer with the Android NDK kit installed.

In the first section we explain how to setup a project with JNI code on Android Studio and how to call C function and C++ member functions from any Java class on your application.

Later, we use the JNI interface to execute a Loader asynchronous background work on a native function. The native function was able to convert a colorful image to a gray image on a Java background thread created by the AsyncTaskLoader.

Next, we discover how to attach and detach a pure native thread created using the C++ standard library to the JVM. The attached thread worked as a normal Java thread and managed its own JNI Environment, resources and references.

In the meantime, we also discovered the differences between JNI global and Local references and how to access a Java object field from...

lock icon
The rest of the chapter is locked
You have been reading a chapter from
Asynchronous Android Programming - Second Edition
Published in: Jul 2016Publisher: PacktISBN-13: 9781785883248
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Author (1)

author image
Steve Liles

Steve Liles is a self-confessed geek and has been an Android fan since the launch day of the G1. When he isn't at work building publishing systems and apps for newspapers and magazines, you'll find him tinkering with his own apps, building 3D printers, or playing RTS games. He is currently working with a start-up to build an advertising system that links the print and digital worlds using computer vision on Android and iOS devices.
Read more about Steve Liles