Get Paid To Promote, Get Paid To Popup, Get Paid Display Banner

Tuesday, August 23, 2011

Horizontal View Swiping with ViewPager

[This post is by Rich “geekyouup” Hyndman, inspired by the fact that life just got that little bit easier — Tim Bray]

Whether you have just started out in Android app development or are a veteran of the craft, it probably won’t be too long before you’ll need to implement horizontally scrolling sets of views. Many existing Android apps already use this UI pattern, such as the new Android Market, Google Docs and Google+. ViewPager standardizes the implementation.

ViewPager was released as part of the Compatibility Package revision 3 and works with Android 1.6 upwards. After following the instructions to obtain the package you can right-click on your Android project in Eclipse, choose ‘Android Tools’ and ‘Add Compatibility Library’, making the new classes available.

ViewPager is a ViewGroup and works in a similar manner to AdapterViews (like ListView and Gallery) so it shouldn’t feel too foreign. Note that if you use ViewPager in an xml layout, be sure to use the full class reference, e.g.

 <android.support.v4.view.ViewPager
android:layout_width="match_parent"
android:layout_height="match_parent"
… />

ViewPagers source their views from PagerAdapters which give you have full control over the reuse and recycling of the views. A PagerAdapter implementation called FragmentPagerAdapter is provided to facilitate the use of Fragments in a ViewPager; This is immensely powerful and as simple as implementing getCount() and getItem(). There is a sample called Fragment Pager Support provided in the Support Demos to illustrate this.

    public static class MyAdapter extends FragmentPagerAdapter {
public MyAdapter(FragmentManager fm) {
super(fm);
}

@Override
public int getCount() {
return NUM_ITEMS;
}

@Override
public Fragment getItem(int position) {
return ArrayListFragment.newInstance(position);
}
}

FragmentPagerAdapter will detach each fragment as you swipe through the list, but keep them in memory so they can simply be reattached when the user swipes back. If you have a larger number of Fragments, the FragmentStatePagerAdapter is worth considering as it will remove them, with the downside being they need to be rebuilt as the user swipes back to them. So, if you have fewer, more complex fragments the FragmentPagerAdapter makes sense, but consider FragmentStatePagerAdapter for larger sets.

On the more simplistic side I recently wrote a ViewPager/PagerAdapter example that serves up simple TextViews. One thing to note is that if you are implementing your own PagerAdapter it is up to you, the developer, to add and remove your views to and from the ViewGroup. To facilitate this the ViewPager is passed into the PagerAdapter methods instantiateItem() and destroyItem().

    @Override
public Object instantiateItem(View collection, int position) {
View v = layoutInflater.inflate(...);
...
((ViewPager) collection).addView(v,0);
return tv;
}

@Override
public void destroyItem(View collection, int position, Object view) {
((ViewPager) collection).removeView((TextView) view);
}

The source code for ViewPager is also included and available in <android-sdk>/extras/android/compatibility/v4/src. It is worth checking as you can generate the reference documentation from it using Javadoc. In the reference docs / source you’ll find other useful methods, for example setOnPageChangeListener(), which enables your application to track which View is currently visible.

If you are launching an app onto Android Market that uses ViewPager then please ping me on Google+ or Twitter, I’d love to see how widely it is being used and the innovative scenarios in which it appears.


Monday, August 22, 2011

Preview of Google TV Add-on for the Android SDK

[This post is by Ambarish Kenghe, who’s a Product Manager for Google TV — Tim Bray]

At Google I/O, we announced that Android Market is coming to Google TV. Today, we’re announcing a preview of the Google TV Add-on for the Android SDK. With the upcoming OS update to Honeycomb, Google TV devices will be Android compatible. That means developers can build great new Android apps for TV, optimize existing mobile or tablet apps for TV, and distribute those apps through Android Market.

While the add-on does not contain all features of Google TV, it enables developers to emulate Google TV and build apps using standard Android SDK tools. It also provides new APIs for TV interaction, such as TV channel line-up. Google TV emulation is currently supported on Linux with KVM only, and we are working on support for other operating systems. We’re very happy that through KVM we’ve been able to create a fast Android emulator for TV.

Depending on the design and use case, an existing Android app may work well on Google TV as is, or it may require fixes. With the add-on you can test your apps to determine if they would be a good fit for TV and whether any tweaks are required. We are also publishing UI guidelines to help you with topics like optimizing for D-pad navigation, presenting information for 10-foot viewing, designing apps that work well across devices, etc. The guidelines include information on how certain UI elements on Google TV differ from other Android devices.

As with other devices, apps that require features not supported on Google TV won’t appear in Android Market on Google TV. For example, Google TV-based devices do not have a touchscreen; hence apps which require touchscreen will not appear. Conversely, if the manifest says touchscreen is not required, the app will appear. Please follow our guidelines carefully.

These are still early days for Google TV, and this release is another step in providing developer tools for the big screen. While the number of apps available on TV will initially be small, we expect that through this early release of the add-on you'll be able to bring optimized TV apps into the ecosystem more quickly. To start doing this, download the Google TV add-on today. Also, please continue to reach out to us on the Google TV Android Developer Community forum. We look forward to your contributions!


Monday, August 1, 2011

Android Developer Labs 2011

We in Android Developer Relations have been cooking up a rather special set of Android Developer Labs (ADLs) for the second half of 2011, and we’re ready to start the ball rolling.

Here’s the schedule. These are one-day events, so in Seattle and New York we’re running it twice for two audiences.

This ADL series isn’t another set of introduction-to-Android sessions, nor any other kind of general overview. It's specifically aimed at optimizing Android apps for tablets, in particular creating high-quality tablet apps with an emphasis on polish and user-experience.

Registration is a two-step process. Anyone can register, but we can only accommodate a relatively small number of attendees from among the registrants, based on whether they already have an Android app with the potential to be a top-tier tablet app in terms of quality, fit, and finish. The goal is to bring your app to the ADL, and leave equipped to make it into one that makes Android tablet users smile.

Do you think you qualify? Sign up and show us!

Thursday, July 28, 2011

Custom Class Loading in Dalvik

[This post is by Fred Chung, who’s an Android Developer Advocate — Tim Bray]

The Dalvik VM provides facilities for developers to perform custom class loading. Instead of loading Dalvik executable (“dex”) files from the default location, an application can load them from alternative locations such as internal storage or over the network.

This technique is not for every application; In fact, most do just fine without it. However, there are situations where custom class loading can come in handy. Here are a couple of scenarios:

  • Big apps can contain more than 64K method references, which is the maximum number of supported in a dex file. To get around this limitation, developers can partition part of the program into multiple secondary dex files, and load them at runtime.

  • Frameworks can be designed to make their execution logic extensible by dynamic code loading at runtime.

We have created a sample app to demonstrate the partitioning of dex files and runtime class loading. (Note that for reasons discussed below, the app cannot be built with the ADT Eclipse plug-in. Instead, use the included Ant build script. See Readme.txt for detail.)

The app has a simple Activity that invokes a library component to display a Toast. The Activity and its resources are kept in the default dex, whereas the library code is stored in a secondary dex bundled in the APK. This requires a modified build process, which is shown below in detail.

Before the library method can be invoked, the app has to first explicitly load the secondary dex file. Let’s take a look at the relevant moving parts.

Code Organization

The application consists of 3 classes.

  • com.example.dex.MainActivity: UI component from which the library is invoked

  • com.example.dex.LibraryInterface: Interface definition for the library

  • com.example.dex.lib.LibraryProvider: Implementation of the library

The library is packaged in a secondary dex, while the rest of the classes are included in the default (primary) dex file. The “Build process” section below illustrates how to accomplish this. Of course, the packaging decision is dependent on the particular scenario a developer is dealing with.

Class loading and method invocation

The secondary dex file, containing LibraryProvider, is stored as an application asset. First, it has to be copied to a storage location whose path can be supplied to the class loader. The sample app uses the app’s private internal storage area for this purpose. (Technically, external storage would also work, but one has to consider the security implications of keeping application binaries there.)

Below is a snippet from MainActivity where standard file I/O is used to accomplish the copying.

  // Before the secondary dex file can be processed by the DexClassLoader,
// it has to be first copied from asset resource to a storage location.
File dexInternalStoragePath = new File(getDir("dex", Context.MODE_PRIVATE),
SECONDARY_DEX_NAME);
...
BufferedInputStream bis = null;
OutputStream dexWriter = null;

static final int BUF_SIZE = 8 * 1024;
try {
bis = new BufferedInputStream(getAssets().open(SECONDARY_DEX_NAME));
dexWriter = new BufferedOutputStream(
new FileOutputStream(dexInternalStoragePath));
byte[] buf = new byte[BUF_SIZE];
int len;
while((len = bis.read(buf, 0, BUF_SIZE)) > 0) {
dexWriter.write(buf, 0, len);
}
dexWriter.close();
bis.close();

} catch (. . .) {...}

Next, a DexClassLoader is instantiated to load the library from the extracted secondary dex file. There are a couple of ways to invoke methods on classes loaded in this manner. In this sample, the class instance is cast to an interface through which the method is called directly.

Another approach is to invoke methods using the reflection API. The advantage of using reflection is that it doesn’t require the secondary dex file to implement any particular interfaces. However, one should be aware that reflection is verbose and slow.

  // Internal storage where the DexClassLoader writes the optimized dex file to
final File optimizedDexOutputPath = getDir("outdex", Context.MODE_PRIVATE);

DexClassLoader cl = new DexClassLoader(dexInternalStoragePath.getAbsolutePath(),
optimizedDexOutputPath.getAbsolutePath(),
null,
getClassLoader());
Class libProviderClazz = null;
try {
// Load the library.
libProviderClazz =
cl.loadClass("com.example.dex.lib.LibraryProvider");
// Cast the return object to the library interface so that the
// caller can directly invoke methods in the interface.
// Alternatively, the caller can invoke methods through reflection,
// which is more verbose.
LibraryInterface lib = (LibraryInterface) libProviderClazz.newInstance();
lib.showAwesomeToast(this, "hello");
} catch (Exception e) { ... }

Build Process

In order to churn out two separate dex files, we need to tweak the standard build process. To do the trick, we simply modify the “-dex” target in the project’s Ant build.xml.

The modified “-dex” target performs the following operations:

  1. Create two staging directories to store .class files to be converted to the default dex and the secondary dex.

  2. Selectively copy .class files from PROJECT_ROOT/bin/classes to the two staging directories.

          <!-- Primary dex to include everything but the concrete library
    implementation. -->
    <copy todir="${out.classes.absolute.dir}.1" >
    <fileset dir="${out.classes.absolute.dir}" >
    <exclude name="com/example/dex/lib/**" />
    </fileset>
    </copy>
    <!-- Secondary dex to include the concrete library implementation. -->
    <copy todir="${out.classes.absolute.dir}.2" >
    <fileset dir="${out.classes.absolute.dir}" >
    <include name="com/example/dex/lib/**" />
    </fileset>
    </copy>
  3. Convert .class files from the two staging directories into two separate dex files.

  4. Add the secondary dex file to a jar file, which is the expected input format for the DexClassLoader. Lastly, store the jar file in the “assets” directory of the project.

        <!-- Package the output in the assets directory of the apk. -->
    <jar destfile="${asset.absolute.dir}/secondary_dex.jar"
    basedir="${out.absolute.dir}/secondary_dex_dir"
    includes="classes.dex" />

To kick-off the build, you execute ant debug (or release) from the project root directory.

That’s it! In the right situations, dynamic class loading can be quite useful.

Wednesday, July 27, 2011

New Tools For Managing Screen Sizes

[This post is by Dianne Hackborn and a supporting cast of thousands; Dianne’s fingerprints can be found all over the Android Application Framework — Tim Bray]

Android 3.2 includes new tools for supporting devices with a wide range of screen sizes. One important result is better support for a new size of screen; what is typically called a “7-inch” tablet. This release also offers several new APIs to simplify developers’ work in adjusting to different screen sizes.

This a long post. We start by discussing the why and how of Android “dp” arithmetic, and the finer points of the screen-size buckets. If you know all that stuff, you can skip down to “Introducing Numeric Selectors” to read about what’s new. We also provide our recommendations for how you can do layout selection in apps targeted at Android 3.2 and higher in a way that should allow you to support the maximum number of device geometries with the minimum amount of effort.

Of course, the official write-up on Supporting Multiple Screens is also required reading for people working in this space.

Understanding Screen Densities and the “dp”

Resolution is the actual number of pixels available in the display, density is how many pixels appear within a constant area of the display, and size is the amount of physical space available for displaying your interface. These are interrelated: increase the resolution and density together, and size stays about the same. This is why the 320x480 screen on a G1 and 480x800 screen on a Droid are both the same screen size: the 480x800 screen has more pixels, but it is also higher density.

To remove the size/density calculations from the picture, the Android framework works wherever possible in terms of "dp" units, which are corrected for density. In medium-density ("mdpi") screens, which correspond to the original Android phones, physical pixels are identical to dp's; the devices’ dimensions are 320x480 in either scale. A more recent phone might have physical-pixel dimensions of 480x800 but be a high-density device. The conversion factor from hdpi to mdpi in this case is 1.5, so for a developer's purposes, the device is 320x533 in dp's.

Screen-size Buckets

Android has included support for three screen-size “buckets” since 1.6, based on these “dp” units: “normal” is currently the most popular device format (originally 320x480, more recently higher-density 480x800); “small” is for smaller screens, and “large” is for “substantially larger” screens. Devices that fall in the “large” bucket include the Dell Streak and original 7” Samsung Galaxy Tab. Android 2.3 introduced a new bucket size “xlarge”, in preparation for the approximately-10” tablets (such as the Motorola Xoom) that Android 3.0 was designed to support.

The definitions are:

  • xlarge screens are at least 960dp x 720dp.

  • large screens are at least 640dp x 480dp.

  • normal screens are at least 470dp x 320dp.

  • small screens are at least 426dp x 320dp. (Android does not currently support screens smaller than this.)

Here are some more examples of how this works with real screens:

  • A QVGA screen is 320x240 ldpi. Converting to mdpi (a 4/3 scaling factor) gives us 426dp x 320dp; this matches the minimum size above for the small screen bucket.

  • The Xoom is a typical 10” tablet with a 1280x800 mdpi screen. This places it into the xlarge screen bucket.

  • The Dell Streak is a 800x480 mdpi screen. This places it into the bottom of the large size bucket.

  • A typical 7” tablet has a 1024x600 mdpi screen. This also counts as a large screen.

  • The original Samsung Galaxy Tab is an interesting case. Physically it is a 1024x600 7” screen and thus classified as “large”. However the device configures its screen as hdpi, which means after applying the appropriate ⅔ scaling factor the actual space on the screen is 682dp x 400dp. This actually moves it out of the “large” bucket and into a “normal” screen size. The Tab actually reports that it is “large”; this was a mistake in the framework’s computation of the size for that device that we made. Today no devices should ship like this.

Issues With Buckets

Based on developers’ experience so far, we’re not convinced that this limited set of screen-size buckets gives developers everything they need in adapting to the increasing variety of Android-device shapes and sizes. The primary problem is that the borders between the buckets may not always correspond to either devices available to consumers or to the particular needs of apps.

The “normal” and “xlarge” screen sizes should be fairly straightforward as a target: “normal” screens generally require single panes of information that the user moves between, while “xlarge” screens can comfortably hold multi-pane UIs (even in portrait orientation, with some tightening of the space).

The “small” screen size is really an artifact of the original Android devices having 320x480 screens. 240x320 screens have a shorter aspect ratio, and applications that don’t take this into account can break on them. These days it is good practice to test user interfaces on a small screen to ensure there are no serious problems.

The “large” screen size has been challenging for developers — you will notice that it encompases everything from the Dell Streak to the original Galaxy Tab to 7" tablets in general. Different applications may also reasonably want to take different approaches to these two devices; it is also quite reasonable to want to have different behavior for landscape vs. portrait large devices because landscape has plenty of space for a multi-pane UI, while portrait may not.

Introducing Numeric Selectors

Android 3.2 introduces a new approach to screen sizes, with the goal of making developers' lives easier. We have defined a set of numbers describing device screen sizes, which you can use to select resources or otherwise adjust your UI. We believe that using these will not only reduce developers’ workloads, but future-proof their apps significantly.

The numbers describing the screen size are all in “dp” units (remember that your layout dimensions should also be in dp units so that the system can adjust for screen density). They are:

  • width dp: the current width available for application layout in “dp” units; changes when the screen switches orientation between landscape and portrait.

  • height dp: the current height available for application layout in “dp” units; also changes when the screen switches orientation.

  • smallest width dp: the smallest width available for application layout in “dp” units; this is the smallest width dp that you will ever encounter in any rotation of the display.

Of these, smallest width dp is the most important. It replaces the old screen-size buckets with a continuous range of numbers giving the effective size. This number is based on width because that is fairly universally the driving factor in designing a layout. A UI will often scroll vertically, but have fairly hard constraints on the minimum space it needs horizontally; the available width is also the key factor in determining whether to use a phone-style one-pane layout or tablet-style multi-pane layout.

Typical numbers for screen width dp are:

  • 320: a phone screen (240x320 ldpi, 320x480 mdpi, 480x800 hdpi, etc).

  • 480: a tweener tablet like the Streak (480x800 mdpi).

  • 600: a 7” tablet (600x1024).

  • 720: a 10” tablet (720x1280, 800x1280, etc).

Using the New Selectors

When you are designing your UI, the main thing you probably care about is where you switch between a phone-style UI and a tablet-style multi-pane UI. The exact point of this switch will depend on your particular design — maybe you need a full 720dp width for your tablet layout, maybe 600dp is enough, or 480dp, or even some other number between those. Either pick a width and design to it; or after doing your design, find the smallest width it supports.

Now you can select your layout resources for phones vs. tablets using the number you want. For example, if 600dp is the smallest width for your tablet UI, you can do this:

res/layout/main_activity.xml           # For phones
res/layout-sw600dp/main_activity.xml # For tablets

For the rare case where you want to further customize your UI, for example for 7” vs. 10” tablets, you can define additional smallest widths:

res/layout/main_activity.xml           # For phones
res/layout-sw600dp/main_activity.xml # For 7” tablets
res/layout-sw720dp/main_activity.xml # For 10” tablets

Android will pick the resource that is closest to the device’s “smallest width,” without being larger; so for a hypothetical 700dp x 1200dp tablet, it would pick layout-sw600dp.

If you want to get fancier, you can make a layout that can change when the user switches orientation to the one that best fits in the current available width. This can be of particular use for 7” tablets, where a multi-pane layout is a very tight fit in portrait::

res/layout/main_activity.xml          # Single-pane
res/layout-w600dp/main_activity.xml # Multi-pane when enough width

Or the previous three-layout example could use this to switch to the full UI whenever there is enough width:

res/layout/main_activity.xml                 # For phones
res/layout-sw600dp/main_activity.xml # Tablets
res/layout-sw600dp-w720dp/main_activity.xml # Large width

In the setup above, we will always use the phone layout for devices whose smallest width is less than 600dp; for devices whose smallest width is at least 600dp, we will switch between the tablet and large width layouts depending on the current available width.

You can also mix in other resource qualifiers:

res/layout/main_activity.xml                 # For phones
res/layout-sw600dp/main_activity.xml # Tablets
res/layout-sw600dp-port/main_activity.xml # Tablets when portrait

Selector Precedence

While it is safest to specify multiple configurations like this to avoid potential ambiguity, you can also take advantage of some subtleties of resource matching. For example, the order that resource qualifiers must be specified in the directory name (documented in Providing Resources) is also the order of their “importance.” Earlier ones are more important than later ones. You can take advantage of this to, for example, easily have a landscape orientation specialization for your default layout:

res/layout/main_activity.xml                 # For phones
res/layout-land/main_activity.xml # For phones when landscape
res/layout-sw600dp/main_activity.xml # Tablets

In this case when running on a tablet that is using landscape orientation, the last layout will be used because the “swNNNdp” qualifier is a better match than “port”.

Combinations and Versions

One final thing we need to address is specifying layouts that work on both Android 3.2 and up as well as previous versions of the platform.

Previous versions of the platform will ignore any resources using the new resource qualifiers. This, then, is one approach that will work:

res/layout/main_activity.xml           # For phones
res/layout-xlarge/main_activity.xml # For pre-3.2 tablets
res/layout-sw600dp/main_activity.xml # For 3.2 and up tablets

This does require, however, that you have two copies of your tablet layout. One way to avoid this is by defining the tablet layout once as a distinct resource, and then making new versions of the original layout resource that point to it. So the layout resources we would have are:

res/layout/main_activity.xml           # For phones
res/layout/main_activity_tablet.xml # For tablets

To have the original layout point to the tablet version, you put <item> specifications in the appropriate values directories. That is these two files:

res/values-xlarge/layout.xml
res/values-sw600dp/layout.xml

Both would contain the following XML defining the desired resource:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<item type="layout" name="main_activty">
@layout/main_activity_tablet
</item>
</resources>

Of course, you can always simply select the resource to use in code. That is, define two or more resources like “layout/main_activity” and “layout/main_activity_tablet,” and select the one to use in your code based on information in the Configuration object or elsewhere. For example:

public class MyActivity extends Activity {
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate();

Configuration config = getResources().getConfiguration();
if (config.smallestScreenWidthDp >= 600) {
setContentView(R.layout.main_activity_tablet);
} else {
setContentView(R.layout.main_activity);
}
}
}

Conclusion

We strongly recommend that developers start using the new layout selectors for apps targeted at Android release 3.2 or higher, as we will be doing for Google apps. We think they will make your layout choices easier to express and manage.

Furthermore, we can see a remarkably wide variety of Android-device form factors coming down the pipe. This is a good thing, and will expand the market for your work. These new layout selectors are specifically designed to make it straightforward for you to make your apps run well in a future hardware ecosystem which is full of variety (and surprises).

Thursday, July 21, 2011

Multiple APK Support in Android Market

[This post is by Eric Chu, Android Developer Ecosystem. —Dirk Dougherty]

At Google I/O we announced our plans to add several new capabilities to help developers manage their products more effectively in Android Market. We’re pleased to let you know that the latest of those, multiple APK support, is now available. Multiple APK support is a new publishing option in Android Market for those developers who want extra control over distribution.

Until now, each product listing on Android Market has included a single APK file, a universal payload that is deliverable to all eligible devices — across all platform versions, screen sizes, and chipsets. Broad distribution of a single APK works very well for almost all applications and has the advantage of simplified product maintenance.

With multiple APK support, you can now upload multiple versions of an APK for a single product listing, with each one addressing a different subset of your customers. These APKs are complete, independent APKs that share the same package name, but contain code and resources to target different Android platform versions, screen sizes, or GL texture-compression formats. When users download or purchase your app, Android Market chooses the right APK to deliver based on the characteristics of the device.

When you upload multiple APK files, Android Market handles them as part of a single product listing that aggregates the app details, ratings, and comments across the APKs. All users who browse your app’s details page see the same product with the same description, branding assets, screenshots, video, ratings, and comments. Android Market also aggregates the app’s download statistics, reviews, and billing data across all of the APKs.

Multiple APK support gives you a variety of ways to control app distribution. For example, you could use it to create separate APKs for phones and tablets under the same product listing. You could also use it to take advantage of new APIs or new hardware capabilities without impacting your existing customer base.

To support this new capability, we’ve updated the Developer Console to include controls for uploading and managing APKs in a product listing — we encourage you to take a look. If you’d like to learn more about how multiple APK support works, please read the developer documentation. As always, please feel free to give us feedback on the feature through the Market Help Center.

Tuesday, July 19, 2011

Debugging Android JNI with CheckJNI

[This post is by Elliott Hughes, a Software Engineer on the Dalvik team — Tim Bray]

Although most Android apps run entirely on top of Dalvik, some use the Android NDK to include native code using JNI. Native code is harder to get right than Dalvik code, and when you have a bug, it’s often a lot harder to find and fix it. Using JNI is inherently tricky (there’s precious little help from the type system, for example), and JNI functions provide almost no run-time checking. Bear in mind also that the developer console’s crash reporting doesn’t include native crashes, so you don’t even necessarily know how often your native code is crashing.

What CheckJNI can do

To help, there’s CheckJNI. It can catch a number of common errors, and the list is continually increasing. In Gingerbread, for example, CheckJNI can catch all of the following kinds of error:

  • Arrays: attempting to allocate a negative-sized array.

  • Bad pointers: passing a bad jarray/jclass/jobject/jstring to a JNI call, or passing a NULL pointer to a JNI call with a non-nullable argument.

  • Class names: passing anything but the “java/lang/String” style of class name to a JNI call.

  • Critical calls: making a JNI call between a GetCritical and the corresponding ReleaseCritical.

  • Direct ByteBuffers: passing bad arguments to NewDirectByteBuffer.

  • Exceptions: making a JNI call while there’s an exception pending.

  • JNIEnv*s: using a JNIEnv* from the wrong thread.

  • jfieldIDs: using a NULL jfieldID, or using a jfieldID to set a field to a value of the wrong type (trying to assign a StringBuilder to a String field, say), or using a jfieldID for a static field to set an instance field or vice versa, or using a jfieldID from one class with instances of another class.

  • jmethodIDs: using the wrong kind of jmethodID when making a Call*Method JNI call: incorrect return type, static/non-static mismatch, wrong type for ‘this’ (for non-static calls) or wrong class (for static calls).

  • References: using DeleteGlobalRef/DeleteLocalRef on the wrong kind of reference.

  • Release modes: passing a bad release mode to a release call (something other than 0, JNI_ABORT, or JNI_COMMIT).

  • Type safety: returning an incompatible type from your native method (returning a StringBuilder from a method declared to return a String, say).

  • UTF-8: passing an invalid Modified UTF-8 byte sequence to a JNI call.

If you’ve written any amount of native code without CheckJNI, you’re probably already wishing you’d known about it. There’s a performance cost to using CheckJNI (which is why it isn’t on all the time for everybody), but it shouldn’t change the behavior in any other way.

Enabling CheckJNI

If you’re using the emulator, CheckJNI is on by default. If you’re working with an Android device, use the following adb command:

adb shell setprop debug.checkjni 1

This won’t affect already-running apps, but any app launched from that point on will have CheckJNI enabled. (Changing the property to any other value or simply rebooting will disable CheckJNI again.) In this case, you’ll see something like this in your logcat output the next time each app starts:

D Late-enabling CheckJNI

If you don’t see this, your app was probably already running; you just need to force stop it and start it again.

Example

Here’s the output you get if you return a byte array from a native method declared to return a String:

W JNI WARNING: method declared to return 'Ljava/lang/String;' returned '[B'
W failed in LJniTest;.exampleJniBug
I "main" prio=5 tid=1 RUNNABLE
I | group="main" sCount=0 dsCount=0 obj=0x40246f60 self=0x10538
I | sysTid=15295 nice=0 sched=0/0 cgrp=default handle=-2145061784
I | schedstat=( 398335000 1493000 253 ) utm=25 stm=14 core=0
I at JniTest.exampleJniBug(Native Method)
I at JniTest.main(JniTest.java:11)
I at dalvik.system.NativeStart.main(Native Method)
I
E VM aborting

Without CheckJNI, you’d just die via SIGSEGV, with none of this output to help you!

New JNI documentation

We’ve also recently added a page of JNI Tips that explains some of the finer points of JNI. If you write native methods, even if CheckJNI isn’t rejecting your code, you should still read that page. It covers everything from correct usage of the JavaVM and JNIEnv types, how to work with native threads, local and global references, dealing with Java exceptions in native code, and much more, including answers to frequently-asked JNI questions.

What CheckJNI can’t do

There are still classes of error that CheckJNI can’t find. Most important amongst these are misuses of local references. CheckJNI can spot if you stash a JNIEnv* somewhere and then reuse it on the wrong thread, but it can’t detect you stashing a local reference (rather than a global reference) and then reusing it in a later native method call. Doing so is invalid, but currently mostly works (at the cost of making life hard for the GC), and we’re still working on getting CheckJNI to spot these mistakes.

We’re hoping to have more checking, including for local reference misuse, in a future release of Android. Start using CheckJNI now, though, and you’ll be able to take advantage of our new checks as they’re added.