(开发历程:关于AS开发NDK的博客并不多,资源也比较少。对于刚开始接触相关知识也是摸了很多次坑,自己慢慢摸索出来)
数据库的简单操作
1. 开发需要
libsqliteX.soclasses.jarsqlite3.h
官方下载 提供下载
2. 新建 Native C++工程
* 这里没有其他需求的话就一直next,最后finish * 之后导入class.jar包及相关so库,把sqlite3.h(头文件)直接复制在.cpp文件的同一级目录。 如何导入jar包 下图为整个工程目录:
3. 配置
CMakeLists.txt
cmake_minimum_required(VERSION
3.4.1)
add_library(sql SHARED
native-lib
.cpp
)
add_library(sqliteX SHARED IMPORTED
)
set_target_properties(
sqliteX
PROPERTIES IMPORTED_LOCATION
$
{CMAKE_SOURCE_DIR
}/libs
/arm64
-v8a
/libsqliteX
.so
)
find_library(log
-lib log
)
target_link_libraries(sql sqliteX
$
{log
-lib
} )
build.gradle
ndk
{
abiFilters
'arm64-v8a'
}
sourceSets
{
main
{
jniLibs
.srcDirs
= ['libs']
}
}
4. native-lib.cpp
#include
"sqlite3.h"
#include
<stdio.h>
#include
<stdlib.h>
#include
"android/log.h"
#define LOG
"JNILOG"
#define
LOGD(...) __android_log_print(ANDROID_LOG_DEBUG
,LOG
,__VA_ARGS__
)
sqlite3
* db
;
char * pErrMsg
= 0;
int ret
= 0;
char* sql
;
sqlite3_stmt
* stmt
;
打开数据库
const char *filename
= "storage//emulated//0//1//myText.db";
LOGD("------------打开数据库--------------");
ret
= sqlite3_open(filename
, &db
);
if ( ret
!= SQLITE_OK
)
{
LOGD("打开失败失败,错误码:%d------错误原因:%s",ret
,sqlite3_errmsg(db
));
return(-1);
}
创建表格
sql
= "create table myText(" \
"id int primary key not null," \
"name text not null," \
"isExistence char(4) not null);";
LOGD("------------建表--------------");
ret
= sqlite3_exec( db
, sql
, 0, 0, &pErrMsg
);
if ( ret
!= SQLITE_OK
)
{
LOGD("创建表失败,错误码:%d--------错误原因:%s",ret
,sqlite3_errmsg(db
));
sqlite3_free(pErrMsg
);
}
插入数据
sql
= "insert into myText (id, name, isExistence)" \
"values (001, 'one', 'yes');" \
"insert into myText (id, name, isExistence)" \
"values (002, 'two', 'yes');" \
"insert into myText (id, name, isExistence)" \
"values (003, 'three', 'no');" \
"insert into myText (id, name, isExistence)" \
"values (004, 'four', 'yes');" \
"insert into myText (id, name, isExistence)" \
"values (005, 'five', 'no');";
LOGD("------------插入数据--------------");
ret
= sqlite3_exec( db
, sql
, 0, 0, &pErrMsg
);
if ( ret
!= SQLITE_OK
)
{
LOGD("插入失败,错误码:%d--------错误原因:%s",ret
,sqlite3_errmsg(db
));
}
取数据
LOGD("------------取数据--------------");
sql
= "select * from myText limit 2 offset 3;";
sqlite3_prepare_v2(db
, sql
, strlen(sql
), &stmt
, NULL
);
LOGD("----------------total_column = %d-------------", sqlite3_column_count(stmt
));
while(sqlite3_step(stmt
) == SQLITE_ROW
){
LOGD("-------------------------");
int len_id
= sqlite3_column_bytes(stmt
, 0);
int len_name
= sqlite3_column_bytes(stmt
, 1);
int len_isExistence
= sqlite3_column_bytes(stmt
, 2);
LOGD("------------id = %d, len = %d-------------", sqlite3_column_int(stmt
, 0), len_id
);
LOGD("------------name = %s, len = %d------------", sqlite3_column_text(stmt
, 1), len_name
);
LOGD("------------isExistence = %s, len = %d--------", sqlite3_column_text(stmt
, 2), len_isExistence
);
}
sqlite3_finalize(stmt
);
关闭数据库
sqlite3_close(db
);
db
= 0;
LOGD("------------关闭数据库--------------");
完整代码
#include
<jni.h>
#include
<string>
#include
"sqlite3.h"
#include
<stdio.h>
#include
<stdlib.h>
#include
"android/log.h"
#define LOG
"JNILOG"
#define
LOGD(...) __android_log_print(ANDROID_LOG_DEBUG
,LOG
,__VA_ARGS__
)
int sql(){
sqlite3
* db
;
char * pErrMsg
= 0;
int ret
= 0;
char* sql
;
sqlite3_stmt
* stmt
;
const char *filename
= "storage//emulated//0//1//myText.db";
LOGD("------------打开数据库--------------");
ret
= sqlite3_open(filename
, &db
);
if ( ret
!= SQLITE_OK
)
{
LOGD("打开失败失败,错误码:%d------错误原因:%s",ret
,sqlite3_errmsg(db
));
return(-1);
}
sql
= "create table myText(" \
"id int primary key not null," \
"name text not null," \
"isExistence char(4) not null);";
LOGD("------------建表--------------");
ret
= sqlite3_exec( db
, sql
, 0, 0, &pErrMsg
);
if ( ret
!= SQLITE_OK
)
{
LOGD("创建表失败,错误码:%d--------错误原因:%s",ret
,sqlite3_errmsg(db
));
sqlite3_free(pErrMsg
);
}
sql
= "insert into myText (id, name, isExistence)" \
"values (001, 'one', 'yes');" \
"insert into myText (id, name, isExistence)" \
"values (002, 'two', 'yes');" \
"insert into myText (id, name, isExistence)" \
"values (003, 'three', 'no');" \
"insert into myText (id, name, isExistence)" \
"values (004, 'four', 'yes');" \
"insert into myText (id, name, isExistence)" \
"values (005, 'five', 'no');";
LOGD("------------插入数据--------------");
ret
= sqlite3_exec( db
, sql
, 0, 0, &pErrMsg
);
if ( ret
!= SQLITE_OK
)
{
LOGD("插入失败,错误码:%d--------错误原因:%s",ret
,sqlite3_errmsg(db
));
}
LOGD("------------取数据--------------");
sql
= "select * from myText limit 2 offset 3;";
sqlite3_prepare_v2(db
, sql
, strlen(sql
), &stmt
, NULL
);
LOGD("----------------total_column = %d-------------", sqlite3_column_count(stmt
));
while(sqlite3_step(stmt
) == SQLITE_ROW
){
LOGD("-------------------------");
int len_id
= sqlite3_column_bytes(stmt
, 0);
int len_name
= sqlite3_column_bytes(stmt
, 1);
int len_isExistence
= sqlite3_column_bytes(stmt
, 2);
LOGD("------------id = %d, len = %d-------------", sqlite3_column_int(stmt
, 0), len_id
);
LOGD("------------name = %s, len = %d------------", sqlite3_column_text(stmt
, 1), len_name
);
LOGD("------------isExistence = %s, len = %d--------", sqlite3_column_text(stmt
, 2), len_isExistence
);
}
sqlite3_finalize(stmt
);
sqlite3_close(db
);
db
= 0;
LOGD("------------关闭数据库--------------");
return 0;
}
extern
"C" JNIEXPORT jstring JNICALL
Java_com_example_jni_1jql_MainActivity_stringFromJNI(
JNIEnv
* env
,
jobject
) {
std
::string hello
= "Hello from C++";
sql();
return env
->NewStringUTF(hello
.c_str());
}
5. Java
需要添加权限 其他地方默认就好了,这里名称需要更改一下。 跟 CMakeLists.txt配置里面的 add_library里名称需要一致。
static {
System
.loadLibrary("sql");
}
6. 注意
如果运行后,出现找不到libsqliteX.so这个库的错误信息,就在这里的libs文件下也放一个so库
7. 生成db文件
8. 查看db文件
可查看db文件的软件
9. 增加一些操作
更新数据(name = two的 isExistence更改为“no”)
LOGD("------------更新数据--------------");
char* data1
= "update call back function call!\n";
sql
= "update myText set isExistence = 'no' where name='two';" \
"select * from myText where isExistence == 'yes'";
ret
= sqlite3_exec(db
, sql
, 0, data1
, &pErrMsg
);
if( ret
!= SQLITE_OK
){
LOGD("更新失败,错误码:%d--------错误原因:%s",ret
,sqlite3_errmsg(db
));
sqlite3_free(&pErrMsg
);
}
查询数据1(使用回调方法)
static int _sql_callback(void * notused
, int argc
, char ** argv
, char ** szColName
)
{
int i
;
LOGD("------------记录包含 %d 个字段--------------",argc
);
for ( i
=0; i
< argc
; i
++ )
{
LOGD( "--字段名:%s ---- 字段值:%s--", szColName
[i
], argv
[i
] );
}
return 0;
}
const char * sql1
= "select * from myText";
LOGD("------------查询数据--------------");
sqlite3_exec( db
, sql1
, _sql_callback
, 0, &pErrMsg
);
查看打印信息如下:
查询数据2(不使用回调方法)
char * errmsg
= NULL
;
char **dbResult
;
int nRow
, nColumn
;
int i
, j
;
int index
;
ret
= sqlite3_get_table( db
, "select * from myText", &dbResult
, &nRow
, &nColumn
, &errmsg
);
if( SQLITE_OK
== ret
)
{
index
= nColumn
;
LOGD("---查到%d条记录/n", nRow
);
for( i
= 0; i
< nRow
; i
++ )
{
LOGD("---第 %d 条记录---/n", i
+1 );
for( j
= 0 ; j
< nColumn
; j
++ )
{
LOGD("字段名:%s --- 字段值:%s/n", dbResult
[j
], dbResult
[index
]);
++index
;
}
}
}
sqlite3_free_table( dbResult
);
查看打印信息如下:
筛选数据
LOGD("------------筛选数据--------------");
char* data
= "----select call back function call!\n";
sql
= "select * from myText where isExistence == 'yes';";
ret
= sqlite3_exec(db
, sql
, _sql_callback
, data
, &pErrMsg
);
if( ret
!= SQLITE_OK
){
LOGD("筛选失败,错误码:%d--------错误原因:%s",ret
,sqlite3_errmsg(db
));
sqlite3_free(&pErrMsg
);
}
查看打印信息如下:
删除表
运行之后,照样会生成一个db文件。但打开这个文件,里面什么都没有。
LOGD("------------删除表--------------");
sql
= "drop table myText;";
ret
= sqlite3_exec(db
, sql
, NULL
, NULL
, &pErrMsg
);
if( ret
!= SQLITE_OK
){
LOGD("删除失败,错误码:%d--------错误原因:%s",ret
,sqlite3_errmsg(db
));
sqlite3_free(&pErrMsg
);
}
疑惑
问题:运行第一遍没问题,第二遍就出现这样的错误,虽然解决了,但不知道具体原因。 解决:重新再拷贝一个libsqliteX.so ,替换掉原来的那个。