一个简单的 SQLite 的示例

http://home.51.com/misoo1/diary/item/10052482.html

数据库大家都知道,他是一组经过计算机整理后的数据,存储在一个或多个文件中,便于快速查询,分析的一种先进工具,同样,在Android中也有数据库,现有的应用有存贮联系人,MP3歌曲,将来还可作为如:网络服务器数据库,日志记录数据库,多媒体信息收集数据库,地图信息数据库等等,为此则编写一个应用 SQLite 数据库的简单示例。

一、在 ndk 上 sqlite 的示例:
    在 android 中 已有 SQLite 库,使用方法与官方网站上的接口一致。如下则是一个使用SQLite接口写的C++示例代码:

1.建立gmain_mysqlite.cpp
/* -- START -- */
#include <sqlite3.h>
#include <stdio.h>

static int _sql_callback(void * notused, int argc, char ** argv, char ** szColName)
{
int i;
for ( i=0; i < argc; i++ )
{
printf( "%s = %s\n", szColName, argv == 0 ? "NUL" : argv );
}
return 0;
}


int main()
{
    const char * sSQL1 = "create table users(userid varchar(20) PRIMARY KEY,age int,regtime datetime);";
    const char * sSQL2 = "insert into users values('guilh',29,'2009-7-16');";
    const char * sSQL3 = "select * from users;";

sqlite3 * db = 0;
char * pErrMsg = 0;

int ret = 0;
const char* const dbname = "gtest.db";
    
//打开数据库,如果数据库不存在,会建立一个数据库
    ret = sqlite3_open(dbname, &db);

    if ( ret != SQLITE_OK )
    {
        printf("open error! : %s", sqlite3_errmsg(db));
        return(1);
    }

    printf("open db OK!\n");

    // 执行建表SQL
    sqlite3_exec( db, sSQL1, 0, 0, &pErrMsg );
    if ( ret != SQLITE_OK )
    {
        //fprintf(stderr, "SQL error: %s\n", pErrMsg);
        printf("SQL error: %s\n", pErrMsg);
        sqlite3_free(pErrMsg);
    }

    // 执行插入记录SQL
    sqlite3_exec( db, sSQL2, 0, 0, &pErrMsg);

    // 查询数据表
    sqlite3_exec( db, sSQL3, _sql_callback, 0, &pErrMsg);

    // 关闭数据库
    sqlite3_close(db);
    db = 0;

    return 0;
}

/* -- END -- */ 
操作有五步:打开/创建数据库,创建数据表,插入记录,查询数据表并显示,关闭数据库。
这里 _sql_callback 函数是个回调函数 可以从中取得查询内容。



2.建立 gmain_mysqlite.cpp 的 Android.mk 
(此文件存于 sources/mysqlite/testmysqlite/Android.mk)

#### START ####
LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)
include $(LOCAL_PATH)/../config.mk

LOCAL_SRC_FILES:= \
gmain_mysqlite.cpp

LOCAL_CFLAGS := \
-I$(ANDROID_FRAMEWORKS_BASE_INCLUDE) \
-I$(ANDROID_SYSTEM_CORE_INCLUDE) \
-I$(ANDROID_EXTERNAL_SQLITE_INCLUDE) \
-I$(LOCAL_PROJECT_PATH)

LOCAL_LDLIBS := \
-L$(ANDROID_LIB) \
-llog \
-lsqlite \
-licuuc \
-licui18n \
-licudata \
-licuuc

#$(info LOCAL_CFLAGS=$(LOCAL_CFLAGS))

LOCAL_PRELINK_MODULE := false

LOCAL_MODULE :=  testmysqlite.bin

include $(BUILD_EXECUTABLE)

### END ###

说明:
这些使用到Android 下的 SQLite库,需要指定些环境变量。
以上的各变量说明可参阅: 在NDK上建立第一个自己的项目 在此不在做说明。
其中,include $(LOCAL_PATH)/../config.mk # 这里的 config 使用的是 sources/mysqlite/config.mk 此文件存有项目环境变量。来看一下这两个config.mk的变量设定。

sources/mysqlite/config.mk
#### START ####
include usr/config/config.mk
LOCAL_PROJECT_PATH := $(ROOT_SRC)/mysqlite
### END ###

usr/config/config.mk
### START ###
ROOT_PATH := $(PWD)
ROOT_SRC := $(ROOT_PATH)/sources
#此变量根据不同环境配置
HOME_PATH := 

ANDROID_SRC := $(HOME_PATH)/android
ANDROID_FRAMEWORKS_BASE_INCLUDE := $(ANDROID_SRC)/frameworks/base/include
ANDROID_SYSTEM_CORE_INCLUDE := $(ANDROID_SRC)/system/core/include
ANDROID_DALVIK_INCLUDE := $(ANDROID_SRC)/dalvik/libnativehelper/include
ANDROID_EXTERNAL := $(ANDROID_SRC)/external
ANDROID_EXTERNAL_SQLITE_INCLUDE := $(ANDROID_EXTERNAL)/sqlite/dist

ANDROID_LIB := $(ANDROID_SRC)/out/target/product/generic/system/lib

### END ###
详细说明可参阅 借用 android 源码中的 logcat。
至此重要部份就已完成,如果需要编译尝试,还需要增加相关项目目录及配置。

二、 项目配置及目录结构:
需要建立三个文件:default.propertie、Application.mk、sources/mysqlite/Android.mk
apps/mysqlite/default.propertie
#### START ####
target=android-3
### END ###

apps/mysqlite/Application.mk
#### START ####
APP_PROJECT_PATH := $(call my-dir)
APP_MODULES := testmysqlite.bin
### END ###


sources/mysqlite/Android.mk
#### START ####
#可寻找到当前目录下的所有子目录中的Android.mk
include $(call all-subdir-makefiles)
### END ###



至此可以看到整体结构如下:
# java项目目录、编译启动文件存放位置、
# 最终编译结果将从out目录中拷贝一份到apps目录下的 libs 目录中
apps

# C++项目目录
sources

# 用户自定义全局目录,如 config、include、lib等
usr

# 用户自定义全局配置makefile文件。
usr/config/config.mk

# mysqlite 项目下总makefile 和一个配置文件
apps/mysqlite/default.propertie
apps/mysqlite/Application.mk

# mysqlite 项目下的文件
sources/mysqlite/Android.mk
sources/mysqlite/config.mk
sources/mysqlite/testmysqlite/Android.mk
sources/mysqlite/testmysqlite/gmain_mysqlite.cpp

接下来在~/android-ndk-1.5_r1下进行编译并安装到sdk中测试,此时会遇到一个问题。
因为 在SQLite打开/创建数据库操作时,需要 android 系统有可读写文件权限。
如果没有设置权限,运行后会提示错误为 : unable to open database file 
解决办法可用如下命令
~/android-sdk-linux_x86-1.5_r2/tools $adb shell
# mount -o remount rw /

然后在运行
# /system/bin/testmysqlite.bin


======================================================

一个简单的 Socket 的示例


在Android 中会运用到各种对外传输,网络传输方式是其中之一,在未来的开发中可能会应用于网络传输,比如做为服务器使用,或是终端媒体设备等等,如下则是使用NDK编译运行于Android 中的一个简单的网络C/S程序示例。

一、在 ndk 上 socket 的示例:
    从 android 的架构中可以得知,android是基于Linux 内核的一个操作系统,所以在Linux上的很多系统接口与在android上的系统接口基本是一致。则可用系统接口操作socket来完成 client /server 的网络通讯功能。

1.建立服务端
其操作过程:创建本地socket,绑定监听本地socket,然后进入循环,并挂起一直等待客户端的请求,当有请求来时,通过判断获得客户端 socket,然后建立子进程,在子进程里向客户端发送消息。

服务端的代码如下: gmain_mynetserver.cpp
/* -- START -- */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define SERVPORT 3333 // 服务器监听端口号
#define BACKLOG 10 //最大同时连接请求数

int main()
{
int sockfd,client_fd;  // sockfd:监听socket;client_fd:数据传输socket
struct sockaddr_in my_addr; // 本机地址信息
struct sockaddr_in remote_addr; // 客户端地址信息

// 创建监听 socket
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
printf("socket create error!\n"); 
return 1;
}

my_addr.sin_family=AF_INET;
my_addr.sin_port=htons(SERVPORT);
my_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(my_addr.sin_zero),8);

//绑定 socket
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1)
{
printf("bind error!\n");
close(sockfd);
return 1;
}

// 监听 socket
if (listen(sockfd, BACKLOG) == -1) 
{
printf("listen error!\n");
close(sockfd);
return 1;
}

while ( true )
{
int sin_size = sizeof(struct sockaddr_in);
// 获得客户端请求 socket
if ((client_fd = accept(sockfd, (struct sockaddr *)&remote_addr, &sin_size)) == -1)
{
printf("accept error!\n");
continue;
}
printf("received a connection from %s\n", inet_ntoa(remote_addr.sin_addr));

if (!fork())  // 子进程代码段
{
// 向客户端发送消息
if ( send(client_fd, "Hello, you are connected!\n", 26, 0) == -1)
{
printf("send error!");
close(client_fd);
close(sockfd);
return 1;
}
// 关闭客户端socket
close(client_fd);
}
}
// 本地socket
close(sockfd);
return 1;
}
/* -- END -- */ 

2.建立客户端
其操作过程:创建本地socket,与服务端建立链接,然后接收服务端发来的消息。

客户端的代码如下: gmain_mynetclient.cpp 
/* -- START -- */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <unistd.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define SERVPORT 3333 // 服务端端口
#define MAXDATASIZE 100 // 每次最大数据传输量

int main(int argc, char *argv[])
{
int sockfd, recvbytes;
char buf;
struct hostent *host;
struct sockaddr_in serv_addr;

if (argc < 2)
{
fprintf(stderr,"Please enter the server's hostname!\n");
return 1;
}

//获得输入的服务端IP地址
if(( host = gethostbyname(argv[1])) == NULL)
{
herror("gethostbyname error!");
return 1;
}

//创建本地socket 
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket create error!");
return 1;
}

serv_addr.sin_family=AF_INET;
serv_addr.sin_port=htons(SERVPORT);
serv_addr.sin_addr = *((struct in_addr *)host->h_addr);
bzero(&(serv_addr.sin_zero),8);
//与服务端建立链接
if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1)
{
perror("connect error!");
return 1;
}

// 接收数据
if ((recvbytes=recv(sockfd, buf, MAXDATASIZE, 0)) ==-1)
{
perror("recv error !");
return 1;
}

buf = '\0';
printf("Received: %s",buf);

// 关闭本地socket
close(sockfd);
return 0;
}

二、运行输出:
先执行服务端执行程序 service.bin ,服务端会等待客户端连接
然后在执行客户端执行程序 client.bin ,输入 client.bin <server IP>

服务端接收到客户端请求后会显示"received a connection from <client IP>"
此时服务端会向客户端发送消息。
客户端则会显示服务端发来的消息 "Hello, you are connected!"

posted @ 2011-07-30 12:26  Colin Xie  阅读(3058)  评论(0编辑  收藏  举报