搞了好久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