1. 程式人生 > 資料庫 >List插入資料庫報錯oracle-00926:缺失VALUES關鍵字

List插入資料庫報錯oracle-00926:缺失VALUES關鍵字

技術標籤:jni

JNI 的使用(callback)

一:定義
JNI是 Java Native Interface的縮寫
使用JNI可以使Java程式碼和其他語言寫的程式碼(如C/C++程式碼)進行互動。

二:JNI 使用之前的配置(AS3.0以上)

  1. 首先在src/main 資料夾下建立jni資料夾
  2. 建立 .cpp檔案Android.mk和Application.mk檔案(如果配置JNI需要引入第三方的so庫,需要在存放第三方so庫的資料夾下建立一個Android.mk檔案)
    配置結束如圖,其中libnative-radio.so為第三方庫。
    在這裡插入圖片描述libs中的mk檔案:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
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 $(BUILD_SHARED_LIBRARY)
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方法

第一次寫,上面是自己的一些理解,如果有不對的地方,希望大神支出!!!