Android JNI學(xué)習(xí)筆記

搞了好久Android 一直沒(méi)搞過(guò)NDK開發(fā)
以前被卡在環(huán)境搭建
后面Android Studio 支持NDK之后
又被沒(méi)有C++代碼提示卡住了
最近發(fā)現(xiàn)用vscode寫C++代碼有代碼提示后
封裝一個(gè)sqlite3的庫(kù)試試水

總結(jié)

我發(fā)現(xiàn)如果不去熟悉源碼,很多方法使用都是不科學(xué)的胧弛。

  • 首先就是Android自帶的Cusor.getColumnIndex 我發(fā)現(xiàn)源碼是讀取查詢結(jié)果所有列名之后 將列名放在hashmap里面 再?gòu)膆aspmap里面查找index 如果sql語(yǔ)句是自己寫的那個(gè)列在第幾個(gè)位置完全知道 不需要掉這個(gè)方法 雖然浪費(fèi)不了多少時(shí)間
  • 其次就是Cusor.getCount 方法 sqlite3的源碼里面我就沒(méi)有找到獲取查詢結(jié)果行數(shù)的方法
    我也沒(méi)有找到源碼是怎么實(shí)現(xiàn)的 我猜估計(jì)是執(zhí)行過(guò)一次sql select count(*) from 不然我也想不到其他高效的方法了 這個(gè)方法只能說(shuō)能不用盡量不用吧
開發(fā)環(huán)境

怎么搭建就不說(shuō)了 百度一大堆
寫說(shuō)明下最重要的2點(diǎn)

  • 第一 VSCODE代碼提示
    c_cpp_properties.json 配置JNI的頭文件地址 配置好之后就有代碼提示了
{
  "configurations": [
    {
      "name": "Win32",
      "includePath": [
        "${workspaceFolder}/**",
        "${workspaceFolder}/include",
        "E:\\android_sdk\\ndk\\21.4.7075529\\toolchains\\llvm\\prebuilt\\windows-x86_64\\sysroot\\usr\\include\\",
        "E:\\android_sdk\\ndk\\21.4.7075529\\toolchains\\llvm\\prebuilt\\windows-x86_64\\sysroot\\usr\\include\\c++\\v1",
        "E:\\android_sdk\\ndk\\21.4.7075529\\toolchains\\llvm\\prebuilt\\windows-x86_64\\sysroot\\usr\\include\\x86_64-linux-android"
      ],
      "defines": ["_DEBUG", "UNICODE", "_UNICODE"],
      "compilerPath": "E:\\soft\\TDM-GCC-64\\bin\\gcc.exe",
      "cStandard": "gnu11",
      "cppStandard": "gnu++98",
      "intelliSenseMode": "windows-gcc-x64"
    }
  ],
  "version": 4
}

  • 第二 NDK編譯
    Android現(xiàn)在推薦用的CMAKE編譯 需要把編譯的文件添加到這個(gè)列表
    網(wǎng)上好像有自動(dòng)添加所有文件的代碼 問(wèn)題我加上之后 就一直卡在編譯中
    只能放棄了
    CMakeLists.txt
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

 add_library(native-lib SHARED
 native-lib.cpp
 include/changeType.cpp
 sqlite/shell.c
 sqlite/sqlite3.c
 sqlite/sqliteDb.cpp
 )

 #include的文件夾
 include_directories(jniSTDualCamPreview
                     ${CMAKE_SOURCE_DIR}/include
                     ${CMAKE_SOURCE_DIR}/sqlite
                     )

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

find_library( # Sets the name of the path variable.
              log-lib

              # Specifies the name of the NDK library that
              # you want CMake to locate.
              log )

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
                       native-lib

                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )
sqlite3庫(kù)的引入

可以去官網(wǎng)下載 源碼SQLite Home Page

sqlite3操作介紹
  • 打開數(shù)據(jù)庫(kù)
bool SqliteDb::open(const char* file)
{  
    //返回值: 成功返回SQLITE_OK,失敗返回其他值泼各。
        // 一個(gè)打開的數(shù)據(jù)庫(kù)實(shí)例

    // 根據(jù)文件路徑打開數(shù)據(jù)庫(kù)連接。如果數(shù)據(jù)庫(kù)不存在啄骇,則創(chuàng)建宵蛀。
    // 數(shù)據(jù)庫(kù)文件的路徑必須以C字符串傳入旺上。
    int result = sqlite3_open_v2(file, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_SHAREDCACHE, NULL);

    if (result == SQLITE_OK) {
        LOGE("打開數(shù)據(jù)庫(kù)連接成功");
        return true;
    }
    else {
         LOGE("打開數(shù)據(jù)庫(kù)連接失敗");
        return false;
    }
}
  • 關(guān)閉數(shù)據(jù)庫(kù)
void SqliteDb::close(){
    if(db!=NULL)
    {
        if(inTransaction)
        {
            commitTransaction();
        }

        sqlite3_close(db);
        db=NULL;
    }
}
  • 執(zhí)行sql
bool SqliteDb::execSql(const char* sql)
{
    if(db==NULL)
    {
        return false;
    }

    // const char *sqlSentence = "INSERT INTO t_person(name, age)     VALUES('夏明', 22); ";        //SQL語(yǔ)句
    sqlite3_stmt *stmt = NULL;        //stmt語(yǔ)句句柄

    //進(jìn)行插入前的準(zhǔn)備工作——檢查語(yǔ)句合法性
    //-1代表系統(tǒng)會(huì)自動(dòng)計(jì)算SQL語(yǔ)句的長(zhǎng)度
    int result = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);

    if (result == SQLITE_OK) {
       
        //執(zhí)行該語(yǔ)句
        sqlite3_step(stmt);
        LOGE("執(zhí)行SQL成功");
    }
    else {
        LOGE("SQL語(yǔ)句有誤");
    }
    //清理語(yǔ)句句柄,準(zhǔn)備執(zhí)行下一個(gè)語(yǔ)句
    sqlite3_finalize(stmt);

    return result == SQLITE_OK;
}
  • 執(zhí)行查詢語(yǔ)句
sqlite3_stmt * SqliteDb::querySql(const char* sql){
    // const char *sqlSentence = "SELECT name, age FROM t_person WHERE age < 30;";    //SQL語(yǔ)句
    sqlite3_stmt *stmt = NULL;    // stmt語(yǔ)句句柄

    //進(jìn)行查詢前的準(zhǔn)備工作——檢查語(yǔ)句合法性
    //-1代表系統(tǒng)會(huì)自動(dòng)計(jì)算SQL語(yǔ)句的長(zhǎng)度
    int result = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);

    if (result == SQLITE_OK) {
        //每調(diào)一次sqlite3_step()函數(shù)糖埋,stmt語(yǔ)句句柄就會(huì)指向下一條記錄
        // while (sqlite3_step(stmt) == SQLITE_ROW) {
        //     // 取出第0列字段的值
        //     const unsigned char *name = sqlite3_column_text(stmt, 0);
        //     // 取出第1列字段的值
        //     int age = sqlite3_column_int(stmt, 1);
        //     //輸出相關(guān)查詢的數(shù)據(jù)
        //     // std::clog << "name = " << name <<", age = "<< age;
        // }

        // LOGE("執(zhí)行SQL成功");
        return stmt;
    }
    else {
        LOGE("SQL語(yǔ)句有誤");
        //清理語(yǔ)句句柄宣吱,準(zhǔn)備執(zhí)行下一個(gè)語(yǔ)句
        sqlite3_finalize(stmt);
        return NULL;
    }
    
}
  • 查詢結(jié)果的讀取
    要封裝的方法太多了 只封裝了幾個(gè)重要的方法
//獲取查詢結(jié)果的列數(shù)
int getColumnCount(sqlite3_stmt* stmt){
    return sqlite3_column_count(stmt);
}

//銷毀以防止內(nèi)存泄露
void closeCusor(sqlite3_stmt* stmt){
    if(stmt!=NULL)
    {
        sqlite3_finalize(stmt);
        stmt=NULL;
    }   
}

//查詢結(jié)果讀取下一行
extern "C" JNIEXPORT jboolean JNICALL Java_com_test_sqlite_SqliteDb_moveNext(JNIEnv* env,
                                                                                 jobject /* this */
                                                                                 ,jlong ptr)
{
    if(ptr==0)
    {
        return 0;
    }
    sqlite3_stmt* stmt=(sqlite3_stmt*)ptr;
    if(sqlite3_step(stmt) == SQLITE_ROW)
    {
        return 1;
    }
    else{
        return 0;
    }
}

//獲取列名
extern "C" JNIEXPORT jstring JNICALL Java_com_test_sqlite_SqliteDb_getColumnName(JNIEnv* env,
                                                                                 jobject /* this */
                                                                                 ,jlong ptr,int index)
{
    if(ptr==0)
    {
        return NULL;
    }
    sqlite3_stmt* stmt=(sqlite3_stmt*)ptr;
    int count=getColumnCount(stmt);
    if(index>=count)
    {
        return NULL;
    }
    const char* name=sqlite3_column_name(stmt,index);
    jstring str=env->NewStringUTF(name);

    return str;
}

//獲取結(jié)果中的int值
extern "C" JNIEXPORT jint JNICALL Java_com_test_sqlite_SqliteDb_getColumnInt(JNIEnv* env,
                                                                                 jobject /* this */
                                                                                 ,jlong ptr,int index)
{
    if(ptr==0)
    {
        return 0;
    }
    sqlite3_stmt* stmt=(sqlite3_stmt*)ptr;
    int count=getColumnCount(stmt);
    if(index>=count)
    {
        return 0;
    }
    int value=sqlite3_column_int(stmt,index);

    return value;
}

//獲取結(jié)果中的double值
extern "C" JNIEXPORT jdouble JNICALL Java_com_test_sqlite_SqliteDb_getColumnDouble(JNIEnv* env,
                                                                                 jobject /* this */
                                                                                 ,jlong ptr,int index)
{
    if(ptr==0)
    {
        return 0;
    }
    sqlite3_stmt* stmt=(sqlite3_stmt*)ptr;
    int count=getColumnCount(stmt);
    if(index>=count)
    {
        return 0;
    }
    double value=sqlite3_column_double(stmt,index);

    return value;
}

//獲取結(jié)果中的string值
extern "C" JNIEXPORT jstring JNICALL Java_com_test_sqlite_SqliteDb_getColumnString(JNIEnv* env,
                                                                                 jobject /* this */
                                                                                 ,jlong ptr,int index)
{
    if(ptr==0)
    {
        return NULL;
    }
    sqlite3_stmt* stmt=(sqlite3_stmt*)ptr;
    int count=getColumnCount(stmt);
    if(index>=count)
    {
        return NULL;
    }
    const unsigned char* value=sqlite3_column_text(stmt,index);
    jstring str=unsigchar2jstring(env,value);
    return str;
}
分享代碼

鏈接:https://pan.baidu.com/s/1PrSV8Ry9tvcSjl3yB5YqEA?pwd=4fow
提取碼:4fow

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市瞳别,隨后出現(xiàn)的幾起案子征候,更是在濱河造成了極大的恐慌,老刑警劉巖祟敛,帶你破解...
    沈念sama閱讀 222,681評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疤坝,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡馆铁,警方通過(guò)查閱死者的電腦和手機(jī)跑揉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)埠巨,“玉大人历谍,你說(shuō)我怎么就攤上這事±崩荩” “怎么了望侈?”我有些...
    開封第一講書人閱讀 169,421評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)勋桶。 經(jīng)常有香客問(wèn)我脱衙,道長(zhǎng)侥猬,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,114評(píng)論 1 300
  • 正文 為了忘掉前任捐韩,我火速辦了婚禮退唠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘荤胁。我一直安慰自己铜邮,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,116評(píng)論 6 398
  • 文/花漫 我一把揭開白布寨蹋。 她就那樣靜靜地躺著松蒜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪已旧。 梳的紋絲不亂的頭發(fā)上秸苗,一...
    開封第一講書人閱讀 52,713評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音运褪,去河邊找鬼惊楼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛秸讹,可吹牛的內(nèi)容都是我干的檀咙。 我是一名探鬼主播,決...
    沈念sama閱讀 41,170評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼璃诀,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼弧可!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起劣欢,我...
    開封第一講書人閱讀 40,116評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤棕诵,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后凿将,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體校套,經(jīng)...
    沈念sama閱讀 46,651評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,714評(píng)論 3 342
  • 正文 我和宋清朗相戀三年牧抵,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了笛匙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,865評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡犀变,死狀恐怖妹孙,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情弛作,我是刑警寧澤涕蜂,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站映琳,受9級(jí)特大地震影響机隙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜萨西,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,211評(píng)論 3 336
  • 文/蒙蒙 一有鹿、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧谎脯,春花似錦葱跋、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,699評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至废麻,卻和暖如春荠卷,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背烛愧。 一陣腳步聲響...
    開封第一講書人閱讀 33,814評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工油宜, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人怜姿。 一個(gè)月前我還...
    沈念sama閱讀 49,299評(píng)論 3 379
  • 正文 我出身青樓慎冤,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親沧卢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蚁堤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,870評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容