編輯:關於Android編程
上篇文章我們安裝了NDK系統,在NDK系統文件中包含samples文件夾,打開該文件夾,我們發現裡面有大量的案例項目,這裡我們通過Eclipse導入一個名為hello-jni的項目
導入成功後,我們可以看到項目目錄如下:
然後,我們逐個學習案例源碼
package com.example.hellojni; import android.app.Activity; import android.widget.TextView; import android.os.Bundle; public class HelloJni extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); /* Create a TextView and set its content. * the text is retrieved by calling a native * function. */ TextView tv = new TextView(this); tv.setText( stringFromJNI() ); setContentView(tv); } /* A native method that is implemented by the * 'hello-jni' native library, which is packaged * with this application. */ public native String stringFromJNI(); /* This is another native method declaration that is *not* * implemented by 'hello-jni'. This is simply to show that * you can declare as many native methods in your Java code * as you want, their implementation is searched in the * currently loaded native libraries only the first time * you call them. * * Trying to call this function will result in a * java.lang.UnsatisfiedLinkError exception ! */ public native String unimplementedStringFromJNI(); /* this is used to load the 'hello-jni' library on application * startup. The library has already been unpacked into * /data/data/com.example.hellojni/lib/libhello-jni.so at * installation time by the package manager. */ static { System.loadLibrary("hello-jni"); } }
這裡我給大家做個注釋
#include#include /** * 原生方法stringFromJNI也用一個名為Java_com_example_hellojni_HelloJni_stringFromJNI的完全 * 限定的函數來聲明,這種顯示的函數命名讓虛擬機在加載的共享庫中自動查找原生函數。函數命名規則為: *Java_類全路徑_方法名。如Java_com_example_hellojni_HelloJni_stringFromJNI,其中Java_是函數的前 *綴,com_example_hellojni_HelloJni是類名,stringFromJNI是方法名,它們之間用 _(下劃線) 連接 */ jstring Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz )// 第一個參數JNIEnv是指向可用JNI函數表的接口指針 // 第二個參數jobject是HelloJni類實例的Java對象引用 { // env指向java當前線程的實例,訪問一個NewStringUTF函數 return (*env)->NewStringUTF(env, "Hello Castiel" ABI "."); }
下面我對代碼中的各個函數做一下講解
原生代碼通過JNIEnv接口指針提供的各種函數來使用虛擬機的功能。JNIEnv是一個執行線程-局部數據的指針,而線程-局部數據中包含執行函數表的指針。
C代碼中,JNIEnv指向JNINativeInterface結構的指針,為了訪問任何一個JNI函數,該指針需要首先被解引用。調用格式如下:
return (*env)->NewStringUTF(env,"hello china");
C++代碼中,JNIEnv實際上是C++類實例,JNI函數以成員函數的形式存在。
return env->NewStringUTF("hello china");
在標准的Java平台下,每個Process裡可以產生很多JavaVM對象,每個JavaVM對象都有一個與之對應的JavaVM對象,但是在Android平台上,每個Process只能產生一個DalvikVM對象,也就是說在一個Android的進程中是通過有且只有一個虛擬器對象來服務所有Java和C++代碼的。
1、JNIEnv 內部包含一個Pointer,Pointer指向Dalvik的JavaVM對象的Fanction Table,JNIEnv 關於程序執行環境的眾多函數正是來源於Dalvik虛擬機
2、Android中每當一個Java線程第一次要調用本地C/C++代碼時,Dalvik虛擬機實例會為該Java線程產生一個JNIEnv *指針
3、Java每條線程在和C/C++互相調用時,JNIEnv*是相互獨立的,互不干擾
4、每本地的C/C++代碼想獲得當前線程所要使用的JNIEnv時,可以使用Dalvik VM對象的Java VM* jvm->getEnv()方法,該方法即會返回當前線程所在的JNIEnv*
Java程序中有兩類方法:實例方法和靜態方法。靜態方法和實例方法均可以聲明為原生的,可以通過JNI技術以原生代碼的形式提供它們的實現。原生實例方法通過第二個參數獲取實例引用,該參數是jobject類型的。如:
a.原生實例方法定義:
JNIEXPORT jstring JNICALL Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz )
因為靜態方法沒有與實例綁定,因此通過第二個參數獲取類引用而不是實例引用,第二個參數是jclass值類型的。
b.原生靜態方法定義:
JNIEXPORT jstring JNICALL Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jclass clazz )
JNI提供了自己的數據類型從而讓原生代碼了解java數據類型
3.使用NDK-Build腳本編譯
開發過程中我們可以使用NDK-Build腳本啟動Android NDK構建系統。
● 默認情況下,NDK-Build腳本應該在主項目目錄中執行,-C參數可以用於指定命令行中NDK項目的位置,這樣一來NDK-Build腳本可以從任意位置開始:
ndk-build -C /path/to/the/project
● 如果源文件沒被修改,Android NDK構建系統不會重構建目標。可以用-B執行NDK-Build腳本來強制重構建所有源代碼。
ndk-build -B
● 為了清理生成的二進制文件和目標文件,可以在命令行執行ndk-build clean命令。Android NDK構建系統會刪除生成的二進制文件。
ndk-build clean
● Android NDK構建系統依賴與GUN Make工具對模塊進行構建。默認情況下GUN Make工具一次執行依據構建命令,等這一句執行完了以後再執行下一句。如果在命令行使用-j參數,GUN Make就可以並行執行構建命令。另外也可以通過執行該參數之後的數字來指定並行執行的命令總數。
ndk-build -j 4
OK,我們開始編譯項目,在cmd命令行下,我們首先進入HelloJni項目的目錄中,然後執行ndk-build命令。
編譯成功後,我們發現整個項目目錄生成libs和obj兩個文件夾
這裡給大家解釋一下這些文件的用途
jni:該目錄包含原生組件的源代碼及描述原生組件構建方法的Android.mk構建文件。Android NDK構建系統將該目錄作為NDK項目目錄並希望在項目根目錄中找到它。mk文件不用改動,是留給ndk-build編譯使用的。
Libs:在Android NDK構建系統的構建過程中創建該目錄,它包含指定的目標機體系結構的獨立子目錄,例如ARM的armeabi,在打包過程中,該目錄被包含在APK文件中。
Obj:這是一個中間目錄,編譯源代碼後產生的目標文件都被保存在該目錄下,開發人員不需要訪問該目錄。
最後,我們運行項目,得到我們想要的結果
安卓5.0Lollipop發布以來VectorDrawable作為安卓環境下的矢量化圖形的方式一直由於兼容性問題而很少被用到,由於只能用於5.0以上系統,導致現在多少安卓
先上預覽圖:流程1.一個勻速圓周運動的點 2.多個勻速圓周運動的點 3.多個圓周運動的點,速度由快到慢 4.點與點之間的間距線性減少,動畫的最後合為一個點 5.為了讓動畫
對於想要攔截一些莫名的陌生號碼,就需要電話攔截功能與刪除其電話記錄功能。攔截的主要業務邏輯,分別是在一個服務裡面進行:1、注冊電話監聽;2、取消注冊電話監聽(當然注冊於取
先看下項目結構: http多線程斷點下載涉及到 數據庫,多線程和http請求等幾個模塊,東西不是很多,想弄清楚也不是很困難,接下來我和大家分享下我的做法。 一、先看Ma
以在搜索框搜索時,自動補全為例:其中還涉及到一個詞,Tokenizer: