Thursday, May 17, 2012

Android + NDK tips, part 3: the actual tips

Previous parts

Android development download checklist

General tips

  • Android programs don't have a specific entry point. The AndroidManifest.xml file specifies which Activity is started by your application icon in the launcher. But I forget how it works exactly.
  • Android programs don't have a specific exit event, either. The system can be terminate inactive programs at any time without notice. Read about the "Activity Lifecycle" in the documentation of the Activity class for more information. Each activity is supposed to save state whenever it is paused (e.g. the user clicks Home) and restore that state automatically when the activity is restarted.
  • Activities are created on a "stack", and the back button takes the top activity off the stack. I think I heard that if your app crashes with several activities on the stack, Android may restart the app with all activities except the last one. Visually it may appear that only one activity stopped, when in fact the entire process was stopped and restarted.
  • Android apps are fundamentally Java-based. I don't know any way to make a pure C/C++ program. Although it is possible to write a program without any Java source files, it will rely on Google code that accesses JNI internally and it will still be compiled to a *.so file, not an executable. The vast majority of functionality is only available through calls to Java, so it's best to just accept Java and live with it.
  • All Android applications are stored as a *.apk file, in the zip file format. Now, earlier I compared apk files to Windows Mobile cab files, but there is a big difference. Specifically, an apk is not unpacked! The program runs on Android "directly" from the apk (only being unpacked in memory, or perhaps to a temp folder, I don't know.) That's not to say that the apk does not have to be installed, though. Each Android app has its own user ID, and must somehow get its icon in the app launcher, so Android probably has some kind of installation process, I just don't know anything about it.
  • Android doesn't use a "real" Java Virtual Machine. It uses a Java alternative called Dalvik, which has its own instruction set (*.dex = Dalvik executable file), which is more compact than Java bytecode. Even so, it looks like a normal Java compiler is used and then its output, the *.class files, are converted afterward to Dalvik format prior to deployment on Android. The Dalvik JIT is said to run code more slowly than Oracle's hotspot JIT.

Eclipse

  • Don't like Eclipse key shortcuts? Use Window|Preferences, then General|Keys. For example, if you think F3 should find the next occurrance of your search text, type Find Next in the search box, click Binding and press F3. However, F3 is already used by some other, minor command. So you should probably search for F3 to find that other command and unbind it.
  • If Eclipse "intellisense" isn't working very well for you, reconfigure it in Window -> Preferences -> Java/Editor/Content Assist; see http://stackoverflow.com/questions/2943131/eclipse-intellisense
  • Eclipse is unaware of the NDK. However, once the NDK build is complete, Elipse automatically detects and deploys your *.so file without any instruction from you. However, when you rebuild your *.so file (outside Eclipse, presumably--I don't know how to build it inside Eclipse), Eclipse does not detect the new version automatically and therefore may not deploy it. To tell Eclipse about the new file, click the "libs" folder in Package Explorer and press F5 to Refresh before running your program (there is no visual indication that a Refresh occurred).

C/C++/NDK

  • There are two options for using C++ code:
    1. Build it with the command-line ndk-build script that comes with the NDK, then use Eclipse or another Android-supporting tool to build the Java code and deploy. This is the best approach if your program is mainly written in Java.
    2. Use a vs-android project with Visual Studio 2010 (Express is not supported). This is the best approach if your program is mainly written in C++, with minimal Java (vs-android has no features or IntelliSense for Java, and certainly no debugging support.)
  • Either way, you'll need to write JNI wrappers in C in order to call the C/C++ code from Java. (If you use Mono for Android, you can use P/Invoke to call C from C#.)
  • In C++, __android_log_print () can print messages to the LogCat pane in Eclipse. In Java, one-letter methods such as Log.w and Log.d do the same thing.
  • If a project uses a jni\Android.mk file, the C++ code is built on the command line by going into the jni\ folder and running the ndk-build script. ndk-build builds C++ only; you need to use Eclipse or some other tool to build the Java code and deploy the project.
  • I have been able to hook ndk-build into a Visual Studio 2008 project (WITHOUT vs-android) by creating a Custom Build Step that looks like this:
      SET NDK=C:\...\android-ndk-r7b
      SET SED=%NDK%\prebuilt\windows\bin\sed
      rem For some reason [0-9]+ does not work. Use [0-9][0-9]* instead.
      %NDK%\ndk-build -C C:\...\jni 2>&1 | %SED% "s#:\([0-9][0-9]*\):#(\1):#" | %SED% "s#//jni#/jni#"
    
  • I used the "sed" command to reformats the error messages slightly so that Visual Studio understands them. This allows you to double-click an error to view the correct location in the source code.

vs-android tips

  • vs-android doesn't come with the ability to create a new project. You must copy a sample project and modify it.
  • If a project uses a vs-android *.vcxproj file, you can open the project in Visual Studio 2010 and run it like any other C++ project. vs-android will build both the C++ code and the Java code. vs-android does not notice C++ source files automatically; you must add them to the project. However, it automatically picks up all Java source files from the "src" directory (recursively).
  • vs-android doesn't support the "Start without debugging" command (let alone "Start Debugging"). To restart a program that you already built, you must restart it from the Android device's launcher.
  • vs-android requires you to issue a three "setx" commands in order to configure it on your machine. There is one more command that the setup instructions don't tell you about; without this command Java may give an out-of-memory error. The command is: setx _JAVA_OPTIONS "-Xms256m -Xmx512m"
  • There is a small bug in vs-android (0.93) when configured to create output for the armv7-a architecture. The .so file goes to libs/armeabi (which is the folder for armv5te) instead of libs/armeabi-v7a. An ARM v7a device will prefer to load the .so from armeabi-v7a, but it will use libs/armeabi as a fallback.
  • Using precompiled headers in vs-android

Mono for Android

  • Currently, even programs written in C# using Mono for Android use JNI to access most of their functionality. Unfortunately, if you want to access Java classes from C# (classes that are not explicitly supported by Mono for Android) you must currently do so through the same clumsy JNI interface that C/C++ code must use.

Unsolved mysteries

  • I can't get Mono for Android to work. All of the sample programs crash on startup for me.
  • Eclipse: how to set the "startup project" that runs when you press Ctrl+F11?
  • Which SDK version is honored, this one in AndroidManifest.xml, or the one in project.properties or default.properties?
  • How to debug C/C++ code (details)?

0 Comments:

Post a Comment

<< Home