編輯:關於Android編程
2)Native程序中的函數可以調用Java層的函數,也就是說C/C++程序可以調用Java函數。
1、JNI本地調用:(以例子介紹)
java:(HelloWorld.java)
class HelloWorld { private native void print(); public static void main(String[] args){ new HelloWorld().print(); } static { System.loadLibrary("HelloWorld"); } }
******* /* * Class: HelloWorld * Method: print * Signature: ()V */ JNIEXPORT void JNICALL Java_HelloWorld_print (JNIEnv *, jobject); *******
第二個參數的意義取決於該方法是靜態還是實例方法,當本地方法作為一個實例方法時,第二個參數相當於對象本身,即this,當本地方法作為一個靜態方法時,指向所在類。
C:(HelloWorld.c)
<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+PC9wPgo8cHJlIGNsYXNzPQ=="brush:java;">#include
下面是生成動態庫。
$:gcc -I/usr/lib/jvm/java-6-sun/include/linux/ -I/usr/lib/jvm/java-6-sun/include/ -fPIC -shared -o libHelloWorld.so HelloWorld.c
gcc是c程序的編譯命令,-I用來指定路徑下的相關頭文件,最後執行java HelloWorld就可以完成調用。
2、android下jni調用(eclipse)
(1)ubuntu下Android NDK開發環境搭建(僅參考我本地搭建方法)
①下載NDK,http://dl.google.com/android/ndk/android-ndk-r4b-linux-x86.zip
②解壓到當前目錄
$pwd <--查看當前目錄 ~/android-ndk-r4b
③配置環境變量
$gedit ~/.bashrc :在打開的文件末尾添加以下內容
NDK=~/android-ndk-r4d
export NDK
④在當前環境下讀取並執行~/.bashrc中的命令:
$source ~/.bashrc
⑤查看是否生效
$echo $NDK
~/android-ndk-r4b/
(2)注冊JNI函數
①靜態注冊
java:
package com.example.hellojni;
import android.app.Activity;
import android.widget.TextView;
import android.os.Bundle;
public class HelloJni extends Activity
{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
TextView tv = new TextView(this);
tv.setText( stringFromJNI() );
setContentView(tv);
}
public native String stringFromJNI();
static {
System.loadLibrary("hello-jni");
}
}
此時會在工程目錄中/bin/classes/com/example/hellojni中會自動生成.class文件,
此時可以利用命令javah -jni -classpath bin/classes/ com.example.hellojni.HelloJni生成.h文件,可見當前文件夾下生成了一個有包名類名組成的com_example_hellojni_HelloJni.h文件,
新建一個jni文件夾,並新建一個hello-jni.c和Android.mk。
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c
include $(BUILD_SHARED_LIBRARY)
代碼如上,android.mk是android提供的一種makefile文件,用來指定編譯生成的so庫名、引用的頭文件等。LOCAL_PATH 用於給出當前文件的路徑;LOCAL_MODULE是模塊的名字,必須唯一切不能包含空格;LOCAL_SRC_FILES指定要編譯的源文件列表;LOCAL_SHARED_LIBRARIES則表示模塊在運行時要以來的共享庫,在鏈接時需要。
hello-jni.c
#include
這個文件中的函數名必須和生成的.h文件中的函數名一致,否則可能會無法找到,也就是Java、對應的包名類名和函數名組成了新函數名。
執行ndk:/home/wesley/android-ndk-r4b/ndk-build,在obj文件中生成庫,在eclipse中全部加載運行就可以在模擬器中顯示。
總結:當Java層調用 stringFromJNI函數時,它會從對應的JNI庫中尋找Java_com_example_hellojni_HelloJni_stringFromJNI函數,如果沒有,便回報錯,如果找到,則會為這個stringFromJNI和Java_com_example_hellojni_HelloJni_stringFromJNI建立一個關聯關系,其實就是保存JNI層函數的函數指針,以後調用stringFromJNI函數時,直接使用這個函數指針就可以了,當然這個工作是由虛擬機來完成的。
②動態注冊
從靜態注冊中可以看出來,它有幾個弊端,首先就是需要編譯所有聲明了native函數的Java類,每個所生成的class文件都得用javah生成頭文件;其次javah生成的JNI層函數名特別長,書寫不便;最後初次調用native函數時要根據函數名搜索對應的JNI層函數來建立關聯關系,這樣很影響效率。故動態注冊,直接讓native函數知道JNI層對應函數的函數指針。
上面的工程改成動態注冊只要改C文件:
HelloWorld.c:
#include
在jni.h中定義了JNINativeMethod結構體,利用這個結構體就可以把java中native函數和此處的函數名對應。那為什麼需要這個簽名信息呢?因為Java支持函數重載,也就是說,可以定義同名但不同參數的函數。但僅僅根據函數名是沒法找到具體函數的,JNI技術中就將參數類型和返回值類型的組合成為了一個函數的簽名信息,有了簽名信息和函數名,就能順利地找到Java中的函數了。
typedef struct {
//java中native函數的名字,不用帶包路徑
char *name; //Java函數的簽名信息。
char *signature; //JNI層對應的函數指針
void *fnPtr;
} JNINativeMethod;
此結構體中的signature可以通過命令來取得,在class文件所在的目錄執行javap -p-s HelloWorld。
然後加載庫就可以完成動態注冊。
總結:當Java層通過System.loadLibrary加載萬JNI動態庫後,緊接著會查找該庫中一個叫JNI_OnLoad的函數,如果有,就調用它,而動態注冊的工作就是從這裡完成的。
(3)通過JNIEnv操作jobject:
java對象是由成員變量和成員函數組成的,操作jobject的本質就應當是操作這些對象的成員變量和成員函數。它們是類的屬性,所以在JNI規則中,用jfieldID和jmethodID來表示Java累的成員變量和成員函數,可通過JNIEnv的下面兩個函數得到:
jfieldID GetFieldID(jclass clazz, const char *name, const char *sig)
jmethodID GetMethodID(jclass clazz, const char *name, const char *sig)
其中,jclass代表Java類,name表示成員函數或成員變量的名字,sig為這個函數和變量的簽名信息。將獲取的ID可以保存以下,這樣可以提高效率。
(4)垃圾回收
①Local Reference:本地引用。在JNI層函數中使用的非全局引用對象都是ocal Reference,它包括函數調用時傳入的jobject和JNI層函數中創建的jobject。ocal Reference最大的特點就是一旦JNI層函數返回,這些jobject就可能被垃圾回收。
②Global Reference:全局引用,這種對象如不住動釋放,它永遠不會被垃圾回收。
③Weak Global Reference:弱全局引用,一種特殊的Global Reference,在運行過程中可能會被垃圾回收,所以在使用之前,需JNIEnv的IsSameObject判斷是否被回收了。
在Android開發和調試的過程中,Log的使用是非常頻繁的,一個好的Log工具可以幫你節省很多時間,所以凱子哥抽空寫了個這個開源項目KLog,希望可以幫助大家提高開發
接引:Android NDK r7以上集成了cywin,在開發NDK時不用那麼麻煩的在去下載與配置cywin.Android NDK 開發步驟:Eclipse 首先配置N
前言ScrollView可以說是android裡最簡單的滑動控件,但是其中也蘊含了很多的知識點。今天嘗試通過ScrollView的源碼來了解ScrollView內部的細節
1、打開手機迅雷點擊切換到我的迅雷個人中心,點擊左上角[登錄],已登錄請跳過2、在手機迅雷個人中心的最下面,倒數第二項[常用設置]點擊進行設置3、繼續在常用