Android JNI学习笔记

搞了好久Android 一直没搞过NDK开发
以前被卡在环境搭建
后面Android Studio 支持NDK之后
又被没有C++代码提示卡住了
最近发现用vscode写C++代码有代码提示后
封装一个sqlite3的库试试水

总结

我发现如果不去熟悉源码,很多方法使用都是不科学的。

  • 首先就是Android自带的Cusor.getColumnIndex 我发现源码是读取查询结果所有列名之后 将列名放在hashmap里面 再从haspmap里面查找index 如果sql语句是自己写的那个列在第几个位置完全知道 不需要掉这个方法 虽然浪费不了多少时间
  • 其次就是Cusor.getCount 方法 sqlite3的源码里面我就没有找到获取查询结果行数的方法
    我也没有找到源码是怎么实现的 我猜估计是执行过一次sql select count(*) from 不然我也想不到其他高效的方法了 这个方法只能说能不用尽量不用吧
开发环境

怎么搭建就不说了 百度一大堆
写说明下最重要的2点

  • 第一 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现在推荐用的CMAKE编译 需要把编译的文件添加到这个列表
    网上好像有自动添加所有文件的代码 问题我加上之后 就一直卡在编译中
    只能放弃了
    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库的引入

可以去官网下载 源码SQLite Home Page

sqlite3操作介绍
  • 打开数据库
bool SqliteDb::open(const char* file)
{  
    //返回值: 成功返回SQLITE_OK,失败返回其他值。
        // 一个打开的数据库实例

    // 根据文件路径打开数据库连接。如果数据库不存在,则创建。
    // 数据库文件的路径必须以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("打开数据库连接成功");
        return true;
    }
    else {
         LOGE("打开数据库连接失败");
        return false;
    }
}
  • 关闭数据库
void SqliteDb::close(){
    if(db!=NULL)
    {
        if(inTransaction)
        {
            commitTransaction();
        }

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

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

    //进行插入前的准备工作——检查语句合法性
    //-1代表系统会自动计算SQL语句的长度
    int result = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);

    if (result == SQLITE_OK) {
       
        //执行该语句
        sqlite3_step(stmt);
        LOGE("执行SQL成功");
    }
    else {
        LOGE("SQL语句有误");
    }
    //清理语句句柄,准备执行下一个语句
    sqlite3_finalize(stmt);

    return result == SQLITE_OK;
}
  • 执行查询语句
sqlite3_stmt * SqliteDb::querySql(const char* sql){
    // const char *sqlSentence = "SELECT name, age FROM t_person WHERE age < 30;";    //SQL语句
    sqlite3_stmt *stmt = NULL;    // stmt语句句柄

    //进行查询前的准备工作——检查语句合法性
    //-1代表系统会自动计算SQL语句的长度
    int result = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);

    if (result == SQLITE_OK) {
        //每调一次sqlite3_step()函数,stmt语句句柄就会指向下一条记录
        // while (sqlite3_step(stmt) == SQLITE_ROW) {
        //     // 取出第0列字段的值
        //     const unsigned char *name = sqlite3_column_text(stmt, 0);
        //     // 取出第1列字段的值
        //     int age = sqlite3_column_int(stmt, 1);
        //     //输出相关查询的数据
        //     // std::clog << "name = " << name <<", age = "<< age;
        // }

        // LOGE("执行SQL成功");
        return stmt;
    }
    else {
        LOGE("SQL语句有误");
        //清理语句句柄,准备执行下一个语句
        sqlite3_finalize(stmt);
        return NULL;
    }
    
}
  • 查询结果的读取
    要封装的方法太多了 只封装了几个重要的方法
//获取查询结果的列数
int getColumnCount(sqlite3_stmt* stmt){
    return sqlite3_column_count(stmt);
}

//销毁以防止内存泄露
void closeCusor(sqlite3_stmt* stmt){
    if(stmt!=NULL)
    {
        sqlite3_finalize(stmt);
        stmt=NULL;
    }   
}

//查询结果读取下一行
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;
}

//获取结果中的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;
}

//获取结果中的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;
}

//获取结果中的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

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容