List插入資料庫報錯oracle-00926:缺失VALUES關鍵字
技術標籤:jni
JNI 的使用(callback)
一:定義
JNI是 Java Native Interface的縮寫
使用JNI可以使Java程式碼和其他語言寫的程式碼(如C/C++程式碼)進行互動。
二:JNI 使用之前的配置(AS3.0以上)
- 首先在src/main 資料夾下建立jni資料夾
- 建立 .cpp檔案Android.mk和Application.mk檔案(如果配置JNI需要引入第三方的so庫,需要在存放第三方so庫的資料夾下建立一個Android.mk檔案)
配置結束如圖,其中libnative-radio.so為第三方庫。
libs中的mk檔案:
LOCAL_PATH := $(call my-dir)
LOCAL_MODULE := native-radio
LOCAL_SRC_FILES := libnative-radio.so
include $(PREBUILT_SHARED_LIBRARY)
jni中的mk檔案
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := RadioJni
LOCAL_SRC_FILES := RadioJni.cpp
LOCAL_LDLIBS := -lm -llog
LOCAL_SHARED_LIBRARIES := native-radio
include $(LOCAL_PATH)/libs/Android.mk
Application.mk
APP_MODULES := RadioJni
APP_ABI := armeabi-v7a
APP_PLATFORM := android-14
三:JNI的使用
1. 在JAVA程式中,首先需要在類中宣告所呼叫的庫名稱,並且可以不用寫出副檔名,系統會自己判定,如下:
static {
System.loadLibrary(“RadioJni”);
}
並且程式入口呼叫
mRadioJni = new RadioJni();
mRadioJni.open(_seekState, _muteState);
2.定義 native 方法
這裡是將要呼叫的方法做本地宣告,關鍵字是 :native
package com.neusoft.optimus.blaster.specific;
import android.util.Log;
import com.neusoft.optimus.blaster.specific.receiver.RadioEventReceiver;
public class RadioJni {
private static final String cTag = "RadioJni";
//定義的native方法 open(RadioSeekState state);
public native boolean open(RadioSeekState state);
public RadioEventReceiver radioEventReceiver;
public RadioEventReceiver getRadioEventReceiver() {
return radioEventReceiver;
}
public void setRadioEventReceiver(RadioEventReceiver radioEventReceiver) {
this.radioEventReceiver = radioEventReceiver;
}
//此方法雖然不是native方法,但是卻是實現jni callback的關鍵方法,此方法的方法名可任意定義。
public void seekCallback(RadioSeekState state){
Log.i(cTag,"seekCallback RadioSeekState:" + state);
if (state != null){
if (radioEventReceiver != null){
radioEventReceiver.registerFreqChangeReceiver(state);
}
3.使用JAVAH命令生成 .h 檔案(也可以自己手寫.cpp檔案,一步到位),並且實現。
手寫 .cpp時,可以這樣寫:將宣告native方法的類,包名中所有的 . 替換成_,並且在開頭加上Java_,結尾加上_native的方法名
#include <jni.h>
#include "Radio.h"
#include <string.h>
#include <dlfcn.h>
#include <cstddef>
#include <stddef.h>
#ifndef _Included_com_neusoft_optimus_blaster_specific_RadioJni
#define _Included_com_neusoft_optimus_blaster_specific_RadioJni
#ifdef __cplusplus
extern "C" {
#endif
#include <android/log.h>
#define LOG_TAG "RadioJniTAG" // 這個是自定義的LOG的標識
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG, __VA_ARGS__)
using namespace xui::adaptapi::radio;
Radio* radio;
static jobject object;
static jobject seekStateObject;
SeekCallback seekCallback;
JavaVM *g_JavaVM;
//Dalvik虛擬機器載入C庫時,第一件事是呼叫JNI_OnLoad()函式,所以在JNI_OnLoad()裡面進行一些初始化工作,如註冊JNI函式等等。註冊本地函式,可以加快java層呼叫本地函式的效率。
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
{
JNIEnv *env = NULL;
g_JavaVM=vm;
jint result = -1;
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
goto fail;
}
if(env == NULL){
goto fail;
}
result = JNI_VERSION_1_4;
fail:
return result;
}
void seekResultCallback(RadioSeekState state) {
JNIEnv* jniEnv = NULL;
LOGI("seekResultCallback state frequency %d", state.frequency);
int status = g_JavaVM->GetEnv((void**)&jniEnv, JNI_VERSION_1_4);
if(status < 0)
{
g_JavaVM->AttachCurrentThread(&jniEnv,NULL);
}
jclass RadioJniClass = jniEnv->GetObjectClass(object); //返回物件的類。
if (RadioJniClass == NULL) {
LOGI("RadioJniClass == NULL");
return;
}
jmethodID seekCallback = jniEnv->GetMethodID(RadioJniClass, "seekCallback", "(Lcom/neusoft/optimus/blaster/specific/RadioSeekState;)V"); // 第一引數是Java 類物件。第二個引數是引數(或方法名),第三個引數是該引數(或方法)的簽名
if (seekCallback == NULL) {
LOGI("seekCallback == NULL");
return;
}
jclass RadioStateClass = jniEnv->GetObjectClass(seekStateObject);//返回物件的類。
if (RadioStateClass == NULL) {
LOGI("RadioStateClass == NULL");
return;
}
//下面就是通過jni,將值賦值給java層的程式碼,實現callback
jmethodID construction_id = jniEnv->GetMethodID(RadioStateClass,"<init>", "()V");// 構造方法的方法名使用<init>代替
jobject radioState = jniEnv->NewObject(RadioStateClass, construction_id);// NewObject需要指明呼叫的構造方法,構建一個新的類物件,並初始化成員變數,呼叫指定的構造方法
jfieldID frequency = jniEnv->GetFieldID(RadioStateClass,"frequency","I");// 第一個引數:Java類物件;第二個引數:引數名(或方法名);第三個引數:該引數(或方法)的簽名;
jfieldID seekFrequencyStatus = jniEnv->GetFieldID(RadioStateClass,"seekFrequencyStatus","I");
jfieldID audioChannelCfg = jniEnv->GetFieldID(RadioStateClass,"audioChannelCfg","I");
//到下面才是真正的賦值,第一個引數:java中對應類物件 第二個引數:這個是java層級的引數 第三個引數:這個是變化的引數,通過該方法將變化的引數實時設定給java層,實現callback
jniEnv->SetIntField(radioState, frequency, state.frequency);
jniEnv->SetIntField(radioState, seekFrequencyStatus, state.isStation);
jniEnv->SetIntField(radioState, audioChannelCfg, state.audioChannelCfg);
//這裡是callback“呼叫”java的方法seekCallback,到此結束了jni 的 callback
jniEnv->CallVoidMethod(object, seekCallback, radioState);
jniEnv->DeleteLocalRef(RadioJniClass);
jniEnv->DeleteLocalRef(radioState);
jniEnv->DeleteLocalRef(RadioStateClass);
}
/*
* Class: com_neusoft_optimus_blaster_specific_RadioJni
* Method: open
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_com_neusoft_optimus_blaster_specific_RadioJni_open(JNIEnv * env, jobject ob ,jobject seekStateobj){
object = env->NewGlobalRef(ob);
seekStateObject = env->NewGlobalRef(seekStateobj); //這裡將java層呼叫 open方法傳遞的引數進行儲存,用於seekResultCallback方法尋找java中類
seekCallback = seekResultCallback; //此處是實現callback 的關鍵,
radio = Radio::get();
bool openResult = radio->open(seekCallback); //這裡會執行到c++的程式碼中
return (jboolean) openResult;
}
//當虛擬機器釋放該C庫時,則會呼叫JNI_OnUnload()函式來進行善後清除動作。
//在此方法中手動釋放不用的物件
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved)
{
LOGI("JNI_OnUnload");
JNIEnv* jniEnv = NULL;
vm->GetEnv((void**)&jniEnv, JNI_VERSION_1_4);
jniEnv->DeleteGlobalRef(object);
jniEnv->DeleteGlobalRef(seekStateObject);
delete radio;
delete object;
delete seekStateObject;
}
#ifdef __cplusplus
}
#endif
#endif
4.用到的類
public class RadioSeekState {
// 搜臺時,此頻率狀態
public int frequency; // 頻率
public int seekFrequencyStatus; // 頻率狀態
public int audioChannelCfg; // 聲音通道
public int band; // band
public class RadioState {
public int frequency; // 頻率
}
四:總結
jni的實現最中的就是
1.首先需要在類中宣告所呼叫的庫名稱
2.定義native方法
第一次寫,上面是自己的一些理解,如果有不對的地方,希望大神支出!!!