編輯:關於Android編程
NDK開發環境的搭建
將NDK的路徑拷貝到環境變量path中 cmd中運行ndk-build可驗證是否添加成功JNI_HelloWorld
步驟
1.創建Android工程 2.java代碼中聲明native方法 3.在工程根目錄下創建jni文件夾,編寫c代碼,名字要對應 4.編寫Android.mk文件 5.NDK編譯生成動態鏈接庫 6.java代碼load動態庫,調用native代碼實現
通過一個點擊事件來調用C代碼 在Activity中添加方法public native String hello();
在該項目的根目錄下添加文件夾 名為jni 在jni文件夾下添加文件 hello.c(命名與Activity中的native方法名一樣) hello.c文件中的代碼:LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE:= hello-jni//要生成的動態庫
LOCAL_SRC_FILES := hello-jni.c//源文件
include $(BUILD_SHARED_LIBRARY)
修改LOCAL_MODULE和LOCAL_SRC_FILES然後在 ndk-build 編譯
[armeabi] Compile thumb : helloJNI <= hello.c
[armeabi] SharedLibrary : libhelloJNI.so<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPlthcm1lYWJpXSBJbnN0YWxsOiBsaWJoZWxsb0pOSS5zbyA9Jmd0OyBsaWJzL2FybWVhYmkvbGliaGVsbG9KTkkuc288L3A+DQo8cD7J+rPJtq/MrL/iPC9wPg0KamF2YbT6wuu147v3ysK8/tbQIMztvNMgU3lzdGVtLmxvYWRMaWJyYXJ5KCZsZHF1bztoZWxsb0pOSSZyZHF1bzspOzxiciAvPg0Kv+K1xMP7s8bKxyBsaWJoZWxsb0pOSS5zbyC9q2xpYrrNLnNvyKW19CC+zb/J0tQNCjxoMSBpZD0="javah生成頭文件">Javah生成頭文件 如果將native方法名改為public native String hello_from_jni();那麼在c代碼中的方法名是這樣的:
jstring Java_com_example_jnihello_MainActivity_hello_from_jni(JNIEnv* env,jobject jobj)
ndk-build編譯也不會報錯,但是運行的時候會崩潰
No implementation found for native Lcom/example/jnihello/MainActivity;.hello_from_jni:()Ljava/lang/String;
在c代碼中將Java的全類名中的.變為_ ,原來有下劃線的地方需要在後面加個1,改成這樣的:
jstring Java_com_example_jnihello_MainActivity_hello_1from_1jni(JNIEnv* env,jobject jobj)
但是如果native方法中有很多下劃線和數字的話,這樣修改起來就會顯得很麻煩,需要一個便捷的方法來實現–javah
JDK1.6在工程的bin/classes目錄下使用 JDK1.7在工程的src目錄下使用使用方法:javah+空格+java全類名
例如:native方法名為public native String hello_1_1_23_from_jni();
在src目錄下啟動cmd,輸入Javah com.example.jnihello.MainActivity
就行了。將生成的.h文件移動到jni目錄下。 在c代碼中原來的#include
修改為#include "com_example_jnihello_MainActivity.h"
並把c代碼中的方法名修改為com_example_jnihello_MainActivity.h
中的方法名
For example, to support hardware FPU instructions on ARMv7 based devices, use:
APP_ABI := armeabi-v7a
Or to support ARMv8 AArch64 instruction set, use:
APP_ABI := arm64-v8a
Or to support the IA-32 instruction set, use:
APP_ABI := x86
Or to support the Intel64 instruction set (r1), use:
APP_ABI := x86_64
Or to support the MIPS32 instruction set, use:
APP_ABI := mips
Or to support the MIPS64 instruction set (r6), use:
APP_ABI := mips64
Or to support all at the same time, use:
APP_ABI := armeabi armeabi-v7a x86 mips arm64-v8a x86_64 mips64
Or even better, since NDK r7, you can also use the special value ‘all’ which means “all ABIs supported by this NDK release”:
APP_ABI := all
#$:調用系統的工具鏈函數,當前的作用:調用當前目錄
LOCAL_PATH := $(call my-dir)
#清除LOCAL環境變量並且初始化工具鏈工具,但是不會清除LOCAL_PATH
include $(CLEAR_VARS)
#要生成的.so文件名稱,前面省略lib可以不寫,但是後綴不需要寫
LOCAL_MODULE := hello-jni
#指向源文件,多個源文件用空格連接
LOCAL_SRC_FILES := hello-jni.c
#編譯成動態鏈接庫BUILD_SHARED_LIBRARY,後綴.so ,文件比較小
#BUILD_STATIC_LIBRARY編譯成靜態鏈接庫,後綴.a,文件比較大
include $(BUILD_SHARED_LIBRARY)
一開始我的Eclipse沒有NDK這個選項,百度之後解決。
新建Android Progect
右鍵Android Tools ->Add Native Support 填上庫的名字,這時候會生成jni文件夾,其中有Android.mk文件和一個cpp文件,關聯源碼#include
並使用宏定義#define LOGD(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
LOCAL_LDLIBS += -llog
在C代碼中直接使用定義好的LOGD,並將要打印的信息傳入即可。
將Java中的String類型轉換成C中的char*類型
char* jstringTostring(JNIEnv* env, jstring jstr) {
char* rtn = NULL;
jclass clsstring = env->FindClass("java/lang/String");
jstring strencode = env->NewStringUTF("utf-8");
jmethodID mid = env->GetMethodID(clsstring, "getBytes",
"(Ljava/lang/String;)[B");
jbyteArray barr = (jbyteArray) env->CallObjectMethod(jstr, mid, strencode);
jsize alen = env->GetArrayLength(barr);
jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
if (alen > 0) {
rtn = (char*) malloc(alen + 1);
memcpy(rtn, ba, alen);
rtn[alen] = 0;
}
env->ReleaseByteArrayElements(barr, ba, 0);
return rtn;
JNI中對數組的操作
獲取數組的長度int size = (*env)->GetArrayLength(env, jarray);
獲取數組中每個元素
jint* arrayElement = (*env)->GetIntArrayElements(env, jarray, JNI_FALSE);
for (i = 0; i < size;i++){
jint s = *(arrayElement + i);
}
Java反射機制主要提供的功能:
1.在運行時判斷任意一個對象所屬的類 2.在運行時構造任意一個類的對象 3.在運行是判斷任意一個類所具有的成員變量和方法 4.在運行是調用任意一個對象的方法Java Reflection API簡介
Class類:代表一個類,位於java.lang包下。 Field類:代表類的成員變量(成員變量也稱為類的屬性)。 Method類:代表類的方法。 Constructor類:代表類的構造方法。 Array類:提供了動態創建數組,以及訪問數組的元素的靜態方法。反射步驟:
1.得到字節碼文件 2.得到字節碼對應的方法 3.得到這個類的實例 4.執行方法MainActivity.java
package com.example.ccalljavademo;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends Activity {
private JNI jni;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
jni = new JNI();
}
public void helloFromJava(View v) {
jni.cMethods_call_helloFromJava();
}
public void add(View v) {
jni.cMethods_call_add();
}
public void printString(View v) {
jni.cMethods_call_printString("sad");
}
public void callStatic(View cv) {
jni.cMethods_call_sayHello();
}
}
JNI.java
package com.example.ccalljavademo;
public class JNI {
{
System.loadLibrary("CCallJavaDemo");
}
/**
* C調用Java空方法
*/
public void helloFromJJava() {
System.out.println("Hello Form Java");
}
/**
* C調用Java兩個int參數方法
* @param x
* @param y
* @return
*/
public int add(int x, int y) {
int result = x + y;
System.out.println("被c調用" + result);
return result;
}
/**
* C調用Java參數為String方法
* @param s
*/
public void printString(String s) {
System.out.println(s);
}
/**
* 靜態方法
*/
public static void sayHello (){
System.out.println("Hello");
}
/**
* 讓C語言調用JNI.java中的 helloFromJava
*/
public native void cMethods_call_helloFromJava();
/**
* 調用JNI.java中的add方法
*/
public native void cMethods_call_add();
/**
* 調用JNI.java中的printString方法
* @param s
*/
public native void cMethods_call_printString(String s);
/**
* 調用靜態方法
*/
public native void cMethods_call_sayHello();
}
CCallJavaDemo.c
#include "com_example_ccalljavademo_JNI.h"
#include
#include
/**
* 讓c語言調用Java中的HelloFromJava
*/
JNIEXPORT void JNICALL Java_com_example_ccalljavademo_JNI_cMethods_1call_1helloFromJava(
JNIEnv *env, jobject jobj) {
// 1.得到字節碼文件
// jclass (*FindClass)(JNIEnv*, const char*);
// 第二個參數 是全類名 com.example.ccalljavademo.JNI 將.換成/
jclass jclazz = (*env)->FindClass(env, "com/example/ccalljavademo/JNI");
// 2.得到字節碼對應的方法
// jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
// 第三個參數:方法名
// 第四個參數:方法簽名
jmethodID jmethodid = (*env)->GetMethodID(env, jclazz, "helloFromJJava",
"()V");
// 3.得到類的實例
// jobject (*AllocObject)(JNIEnv*, jclass);
jobject obj = (*env)->AllocObject(env, jclazz);
// 4.執行方法
// void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
(*env)->CallVoidMethod(env, obj, jmethodid); //成功調用JNI.java中的helloFromJava方法
}
/***
*C調用Java中帶有兩個int參數的方法
*
*/JNIEXPORT void JNICALL Java_com_example_ccalljavademo_JNI_cMethods_1call_1add(
JNIEnv *env, jobject jobj) {
// 1.得到字節碼文件
// jclass (*FindClass)(JNIEnv*, const char*);
// 第二個參數 是全類名 com.example.ccalljavademo.JNI 將.換成/
jclass jclazz = (*env)->FindClass(env, "com/example/ccalljavademo/JNI");
// 2.得到字節碼對應的方法
// jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
// 第三個參數:方法名
// 第四個參數:方法簽名
jmethodID jmethodid = (*env)->GetMethodID(env, jclazz, "add", "(II)I");
// 3.得到類的實例
// jobject (*AllocObject)(JNIEnv*, jclass);
jobject obj = (*env)->AllocObject(env, jclazz);
// 4.執行方法
// jint (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);
(*env)->CallIntMethod(env, obj, jmethodid, 99, 12); //成功調用JNI.java中的add方法
}
JNIEXPORT void JNICALL Java_com_example_ccalljavademo_JNI_cMethods_1call_1printString(
JNIEnv *env, jobject jobj, jstring jstr) {
// 1.得到字節碼文件
// jclass (*FindClass)(JNIEnv*, const char*);
// 第二個參數 是全類名 com.example.ccalljavademo.JNI 將.換成/
jclass jclazz = (*env)->FindClass(env, "com/example/ccalljavademo/JNI");
// 2.得到字節碼對應的方法
// jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
// 第三個參數:方法名
// 第四個參數:方法簽名
jmethodID jmethodid = (*env)->GetMethodID(env, jclazz, "printString",
"(Ljava/lang/String;)V");
// 3.得到類的實例
// jobject (*AllocObject)(JNIEnv*, jclass);
jobject obj = (*env)->AllocObject(env, jclazz);
// 4.執行方法
// void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
(*env)->CallVoidMethod(env, obj, jmethodid, jstr); //成功調用JNI.java中的add方法
}
JNIEXPORT void JNICALL Java_com_example_ccalljavademo_JNI_cMethods_1call_1sayHello(
JNIEnv *env, jobject jobj) {
// 1.得到字節碼文件
// jclass (*FindClass)(JNIEnv*, const char*);
// 第二個參數 是全類名 com.example.ccalljavademo.JNI 將.換成/
jclass jclazz = (*env)->FindClass(env, "com/example/ccalljavademo/JNI");
// 2.得到字節碼對應的方法
// jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
// 第三個參數:方法名
// 第四個參數:方法簽名
jmethodID jmethodid = (*env)->GetStaticMethodID(env, jclazz, "sayHello",
"()V");
// 3.得到類的實例
// jobject (*AllocObject)(JNIEnv*, jclass);
// jobject obj = (*env)->AllocObject(env, jclazz);
// 4.執行方法
// void (*CallStaticVoidMethod)(JNIEnv*, jclass, jmethodID, ...);
(*env)->CallStaticVoidMethod(env, jclazz, jmethodid);
}
Android Lint Android Lint是在ADT 16(和 Tools 16)引入的一個新工具,可以掃描Android 項目源碼中潛在的bug
?今天在新建一個Activity的時候, 隨手就創建了一個空的activity,而且, AS 還會給你自動生成xml文件, 跟一些activity裡默認的代碼。?到這裡,
Android中所有控件(也稱組件)都繼承自adnroid.view.View類,android.view.ViewGroup是View類的重要子類,絕大多書的布局類就繼
本文實例講述了Android開發圓角Button按鈕實現過程,分享給大家供大家參考,具體內容如下需求及效果圖:實現思路:1、shape實現圓角在drawable新建兩個x
前言:在上篇中,分析了MediaPlayer的從創建到setDataSo