實現PHP伺服器+Android客戶端(Retrofit+RxJava)第五天學一學ndk開發吧
前兩天發現一本相當可以的書Java 效能權威指南,粗略的看了兩天,對於我這種還在去中級的路上的人,看著的確是挺累的,所以也就歇了幾天沒有寫部落格了。看了那麼高深的東西還是要繼續回來鞏固一下實戰水平,所以今天繼續來講我的這個應用的實現過程,在上篇文章實現PHP伺服器+Android客戶端(Retrofit+RxJava)第四天客戶端與伺服器通訊的實現之後相信大家對簡單的資料通訊已經不在話下了,今天我要說的東西其實是為了後續講我要在這個應用中要用到的兩個框架打下基礎,兩個非常好的框架:fresco,ijkplayer,fresco是圖片載入框架,ijkplayer是視訊載入播放框架,這兩個框架都用到了ndk開發,什麼是ndk開發這裡就不多說了,自行百度!
ndk環境配置
可直接參考: Android Studio建立jni開發環境
我用的是android studio,這裡也只講android studio的ndk環境配置,首先下載最新的ndk版本,地址:NDK Downloads,下載之後解壓即可,先配置android studio的ndk路徑,點選”File”,”Project Structure”,大致效果如下:
看到下面的ndk location,選擇剛剛解壓的ndk就行
其實還有一種方法下載ndk
在Toolbare可以找到Android的更新圖示:
在SDK Tools的Tab頁中,勾選LLDB 2.1和NDK:
但是上面這種方法比較的慢,還是自己下載比較快
隨後新增環境變數 NDK_ROOT 為: D:\Android\android-ndk-r10d(解壓路徑)
在環境變數 PATH 下追加 :%NDK_ROOT%;
不寫Hello World
每次學一門語言的時候,我們老是hello world,我就不再這hello world了,在這裡我實現的效果是傳入一個數,做個平方,然後輸出。比如輸入5,然後輸出25.
首先右鍵點選App(對應的module)新建jni目錄:
新建java類:
package com.sqq.beginndk;
import android.content.Context;
import android.widget.Toast;
/**
* Created by sqq on 2016/6/21.
*/
public class LoadRetJni {
Context con;
static {
System.loadLibrary("getRet");
}
public LoadRetJni(Context context){
con = context;
}
/**
* 這個函式的目的是為了展示底層c語言怎麼呼叫
* java函式
* @param value 這個value值來自本地c程式碼
*/
public void showMsg(int value){
Toast.makeText(con, "The Value" + value, Toast.LENGTH_LONG);
}
public native int getSquare(int in);
}
gradle中配置支援ndk
defaultConfig {
applicationId "com.sqq.beginndk"
minSdkVersion 15
targetSdkVersion 23
versionCode 1
versionName "1.0"
//指定.so的目錄
sourceSets.main{
jniLibs.srcDir 'src/main/libs'
}
ndk{
moduleName 'getRet'
}
}
還需要在gradle.properties中設定android.useDeprecatedNdk=true
接下來生成 .h檔案
javah -d src/main/jni/ -classpath build/intermediates/classes/debug/ com.sqq.beginndk.LoadRetJni
其中-d是生成.h檔案的儲存目錄
-classpath是指定.class所在的目錄,專案build成功之後,會在build/intermediates/classes/debug/目錄裡生成.class檔案。
com.sqq.beginndk.LoadRetJni是包名加上類名。
就可以在jni目錄下得到一個com.sqq.beginndk.LoadRetJni.h的檔案。
實現這個標頭檔案中方法
新建.c檔案實現getSquare方法。直接複製標頭檔案中的宣告(記得把引數加上),然後實現其中的方法就行了,具體程式碼如下:
#include "com.sqq.beginndk.LoadRetJni.h"
JNIEXPORT void JNICALL JNIEXPORT jstring JNICALL Java_com_sqq_beginndk_LoadRetJni(JNIEnv *env, jobject object) {
jclass clazz = (*env)->GetObjectClass(env,object);
jmethodID id = (*env)->GetMethodID(env,clazz,"showMsg","(I)V");
jint ret= in*in;
(*env)->CallVoidMethod(env,object,id,ret);
(*env)->DeleteLocalRef(env,clazz);
return ret;
}
新增Application.mk
APP_MODULES := getRet
APP_ABI :=all
新增Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE :=getRet
LOCAL_SRC_FILES := com_sqq_beginndk_LoadRetJni.c
include $(BUILD_SHARED_LIBRARY)
最後一步,在../app/src/main/jni目錄下,執行命令
ndk-build
隨後你會發現生成了so檔案,這時候你就可以運行了,但是不要高興的太宰,你可能會發現有檔案衝突的錯誤,解決的辦法就是把src/main目錄下生成的libs和obj檔案刪除就行了,在執行就可以了,會顯示25,toast會輸出the Values 25。
說到這裡,其實大家可能也和我一樣不知道為什麼libs檔案和build下的檔案為什麼都會有so檔案,而且兩者還衝突,刪除build下的還沒有用,它會自動又生成,這個先不管,我要實現的效果是實現了。
最後還要說的是,如何在其他的工程中使用我們自己生成的so檔案,首先建立java類,程式碼就是上面的java類一樣,如下:
package com.sqq.beginndk;
import android.content.Context;
import android.widget.Toast;
/**
* Created by sqq on 2016/6/21.
*/
public class LoadRetJni {
Context con;
static {
System.loadLibrary("getRet");
}
public LoadRetJni(Context context){
con = context;
}
/**
* 這個函式的目的是為了展示底層c語言怎麼呼叫
* java函式
* @param value 這個value值來自本地c程式碼
*/
public void showMsg(int value){
Toast.makeText(con, "The Value" + value, Toast.LENGTH_LONG);
}
public native int getSquare(int in);
}