編輯:關於Android編程
少壯不努力,老大徒傷悲。大學時光的潇灑散漫導致今天連C/C++編程都不會。作為一個程序員,不會C/C++說出去簡直丟人啊。最近浏覽公司招聘信息(Android職位),發現對NDK開發的要求越來越普遍了。筆者學習的是java,從事Android開發,對於Android底層的東西多少有點畏懼,因為沒有涉及過,但是我們知道,不能因為怕就放棄。如我曾經簽名所言:現在開始行動,就比還在猶豫的人快了一步。
回到正題,NDK開發真的很難嗎?其實不是的,覺得難是因為你沒懂,不懂是因為沒學。那就來吧
NDK:什麼是NDK
Android NDK(Native Development Kit )是一套工具集合,允許你用像C/C++語言那樣實現應用程序的一部分。
提高性能。在某些情況下使用C/C++處理邏輯算法的效率高於java(圖片相關處理算法等) 使用第三方庫。許多第三方庫由C/C++語言編寫,而Android應用程序需要使用現有的第三方庫,如Ffmpeg、OpenCV這樣的庫。 底層程序設計。例如,應用程序不依賴Dalvik Java虛擬機 。NDK:什麼時候使用NDK
別的不說,光看 提高性能 這一塊就很有吸引力了。入門篇,不說那些虛的,先跑起來。
不會的話百度,這個不難,秒配置。1.下載ndk文件,解壓;2.配置到環境變量;3.cmd測試ndk是否已經安裝配置成功
目標實現: 從Android層面傳遞兩個int值到底層,使用C/C++處理比較兩個值的大小,返回結果信息(string)給Android使用。
項目問題: Android如何將java的數據類型傳遞給C/C++使用?如何將C/C++數據類型傳遞給java使用?中間的橋梁是什麼?
項目分析: Android將java數據類型傳遞給native層,通過JNI“編碼”轉化為C/C++可用的數據類型,反過來一樣也是使用JNI作為橋梁溝通java和C++
創建一個Android項目。
HelloNdk 中定義 native 接口,在C++中計算兩個int數的大小,返回結果信息string
public native String getMaxInt(int first, int second);
在HelloNdk 中使用static 靜態塊調用so庫。
static {
System.loadLibrary("hi-ndk");
}
HelloNdk(Activity)完整代碼
public class HelloNdk extends Activity {
static {
System.loadLibrary("hi-ndk");//"hi-ndk" so 名稱
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView tv = new TextView(this);
tv.setText(getMaxInt(15, 10));
setContentView(tv);
}
public native String getMaxInt(int first, int second);
}
首先配置JNI,在項目中新建 jni 文件夾。jni包含 Android.mk,Application.mk,頭文件[cn_r_ndk_android_HelloNdk.h],C++文件
新建Android.mk,Application.mk,這兩個文件內容不必記,配置文件嘛,理解一下什麼意思就好,也可以從ndk的sample項目中拷貝,解壓ndk<喎?/kf/ware/vc/" target="_blank" class="keylink">vc3Ryb25nPtauuvPL5rD8uL20+NPQc2FtcGxlo6zV0rW9IDxzdHJvbmc+aGVsbG8tam5pPC9zdHJvbmc+ILi01sbP7sS/1tC1xCA8c3Ryb25nPkFuZHJvaWQubWs8L3N0cm9uZz6jrDxzdHJvbmc+QXBwbGljYXRpb24ubWs8L3N0cm9uZz48L3A+DQo8cD48aW1nIGFsdD0="這裡寫圖片描述" src="/uploadfile/Collfiles/20160709/20160709092100800.png" title="\" />
Android.mk 文件代碼。(看文件中注釋)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hi-ndk
#so項目名稱
LOCAL_SRC_FILES := hi-ndk.cpp
#資源文件名稱,對應的c/c++代碼文件
include $(BUILD_SHARED_LIBRARY)
Application.mk 文件代碼。(看文件中注釋)
APP_ABI := all
#APP_ABI:= armeabi armeabi-v7a x86 mips mips-r2 mips-r2-sf
#如果是普通arm處理器的Android手機,使用APP_ABI := armeabi;
#如果是x86處理器的,使用APP_ABI := x86,等等。
#如果APP_ABI := all,會編譯所有指令的so
APP_STL := stlport_static
#NDK中C++標准庫、STL的配置
#如未配置可能出現錯誤: fatal error: iostream: No such file or directory
頭文件[cn_r_ndk_android_HelloNdk.h]。C++頭文件,通過 javah 生成頭文件。javah 命令使用詳情,可以在 cmd 中查看敲入 javah 查看
生成頭文件方式:打開cmd面板,直接進入項目src目錄,然後執行
javah -d ../jni cn.r.ndk.android.HelloNdk
備注:cn.r.ndk.android.HelloNdk 是(定義了native接口)類的完整路徑
執行成功之後可以在 jni 文件夾中查看 [cn_r_ndk_android_HelloNdk.h]
前面兩步完成了基本的配置,現在接下來進入重點的邏輯代碼編寫。
寫代碼之前就有幾個問題啦:
1.java數據類型和C++數據類型怎麼打通?
答:使用JNI。前面有提及到,JNI是java和C++這兩種語言的橋梁,JNI提供了一種規范,打通兩種語言之間的障礙
2.java數據類型如何轉化為JNI?
基本數據類型:
引用類型:
通過上表,不難看出,通過JNI規范,java中的基礎類型轉化成JNI數據類型基本都是加上了 j。
例:int:int -> jint
3.JNI數據類型與C++數據類型 如何相互轉換?
這個就比較麻煩啦,需要自行查閱資料了解JNI編程中如何處理字符串以及對象類型的數據。
先看一下主要需要解釋的代碼。(這裡使用C++語言實現,引入頭文件什麼的就不說了,筆者也是一邊學習NDK,一邊學習C++,所以C++代碼寫的很水的話請不要嘲笑,麻煩指正出來)
jstring Java_cn_r_ndk_android_HelloNdk_getMaxInt(JNIEnv * env, jobject thiz,
jint first, jint second) {
int first_j = first;
int second_j = second;
int max = maxInt(first_j, second_j);
/**
* int > string
*/
string msg_result = xToString(max);
string msg_tip = "the max number:";
string msg = msg_tip + msg_result;
const char* msg_j_a = msg.c_str();
jstring msg_j = env->NewStringUTF(msg_j_a);
return msg_j;
}
C++語言跟java很相似,筆者基本是按照java的思想寫代碼
這裡的基本數據類型 jint直接轉換成C++的int。接下來調用方法計算兩個數的最大值。這裡想吐槽一下的是,原來C++將 int 數據類型和 string類型拼接在一起這麼麻煩,在 java 中 String 和 int 使用 + 可以直接拼接。C++中需要使用轉換好多次。
我們想要把將 “the max number: XX” 這樣的結果返回給 java。這裡使用
env->NewStringUTF(msg_j_a);
由於NewStringUTF()方法中接收的參數是 char* ch類型的,所以才有代碼中各種轉換。
筆者先將int轉化為string,然後拼接兩個string,接著使用string.c_str()將字符串轉化為char*,最終才調用NewStringUTF()方法返回jstring
備注:如果使用C語言調用JNI的方法有所不同
(*env)->NewStringUTF(env, "Hello from JNI ! ");
關於C/C++部分的代碼這裡就不多說了,因為我也不太會,萬一說錯了,那就尴尬了。讀者只能自行捉摸了。
關於C/C++和JNI之間的數據類型“轉換”有兩點我還是要分享一下:
1.基本數據類型可以直接轉換;
2.string類型處理的幾個方法:
http://blog.csdn.net/xyang81/article/details/42066665
看看完整版的代碼 hi-ndk.cpp
#include
#include
#include
#include "cn_r_ndk_android_HelloNdk.h"
using namespace std;
// 函數聲明
int maxInt(int first, int second);
string xToString(int x);
jstring Java_cn_r_ndk_android_HelloNdk_getMaxInt(JNIEnv * env, jobject thiz,
jint first, jint second) {
int first_j = first;
int second_j = second;
int max = maxInt(first_j, second_j);
/**
* int > string
*/
string msg_result = xToString(max);
string msg_tip = "the max number:";
string msg = msg_tip + msg_result;
const char* msg_j_a = msg.c_str();
jstring msg_j = env->NewStringUTF(msg_j_a);
return msg_j;
}
/**
* 比較兩個數大小
*/
int maxInt(int first, int second) {
if (first > second) {
return first;
} else {
return second;
}
}
/**
* X轉化為string
*/
string xToString(int x) {
char ch[10];
sprintf(ch, "%d", x);
string result(ch);
return result;
}
OK,到這裡基本的工作就做完了,會不會有點蒙圈?不會最好,如果蒙圈那就休息一下,再理一理思路,停下來想想實現步驟:
1. Native (Android層面開發)
簡述:【一個定義了native方法的類】
2. JNI(Android和C/C++連接層處理)
簡述:【一個JNI文件夾,裡面有四個重要文件, Android.mk,Application.mk,頭文件,C++文件】
3. C/C++(邏輯處理層)
簡述:【java->jni;jni<->c++;業務邏輯處理】
這樣一看是不是就簡單明了了呢?三部分組成,一看簡述能知道每一步大概做什麼了,如果還是一片空白就回去那一步再看看。
如果沒問題了,那就進行最後一步了,ndk-build 編譯 so 文件。
編譯成功的畫面總是看的那麼自然,整齊劃一。
人們說黎明前最黑暗,成功前最渺茫。是的沒錯,在這一步你也可能卡很久,不過別怕,這一部分編譯出錯基本上是C/C++文件代碼的問題了,如果是數據類型轉換問題可參考上面提到的兩點,1基本數據類型直接使用,2.string問題參考友情鏈接。如果是代碼邏輯和規范問題的話,那就只能問度娘了,耐心點,你總能編譯成功。說出來不怕別人笑話,那個數字轉換和字符串拼接的需求我弄了很久,C++語言不熟悉,硬是問著百度寫完的。
編譯成功之後可以在lib文件夾中看到so文件,名稱為:hi-ndk
你會不會想問那我Android怎麼使用這個so文件啊?怎麼拿到C++計算得到結果?
其實一開始就給出了,HelloNdk中代碼
類靜態塊中加載so文件,注意這裡不要寫 libhi-ndk.so ,除去前面的 【lib】 和後面的 【.so】 ,只需要hi-ndk
static {
System.loadLibrary("hi-ndk");//"hi-ndk" so 名稱
}
方法調用
TextView tv = new TextView(this);
tv.setText(getMaxInt(15, 10));
OK,到這裡第一個NDK項目就寫完了,很難嗎?也不是很難啊。用點心,一切沒多難,只是看你有多想做成一件事情。成功的那種喜悅是用錢買不到的,哈哈。同時還學習了新的語言C++。何樂而不為呢?
有什麼不懂的地方可以留言討論,有不足的地方還望指正批評。
一直感覺AndroidStudio沒有eclipse快,但是最近由於遇到一個問題不得不將工程遷移到AndroidStudio上,遷移後之前在eclipse上所做的所有批量
今天學習了新的功能那就是滑動刪除數據。先看一下效果我想這個效果大家都很熟悉吧。是不是在qq上看見過這個效果。俗話說好記性不如賴筆頭,為了我的以後,為了跟我一樣自學的小伙伴
前面文章介紹了Android利用麥克風采集並顯示模擬信號的實現方法,這種采集手段適用於無IO控制、單純讀取信號的情況。如果傳感器本身需要包含控制電路(例如采集血氧信號需要
Android是一個開源的開放的操作系統,世界上的任何人都可以基於這個系統進行適合自己的定制活動。Android的這樣一個特點使得android世界的碎片化很嚴重,形形色