【Android游戏开发十三】(保存游戏数据 [下文])详解SQLite存储方式,并把SQLite的数据库文件存储在SD卡中!!!
分类: 【 Android 游戏开发】
2011-01-04 02:08
15605人阅读
收藏
举报
sqlite 存储 游戏 数据库 android layout
李华明Himi 原创,转载务必在明显处注明:
转载自
【黑米GameDev街区】 原文链接: http://www.himigame.com/android-game/329.html
很多童鞋说我的代码运行后,点击home或者back后会程序异常,如果你也这样遇到过,那么你肯定没有仔细读完Himi的博文,第十九篇Himi专门写了关于这些错误的原因和解决方法,这里我在博客都补充说明下,省的童鞋们总疑惑这一块;请点击下面联系进入阅读:
【Android游戏开发十九】(必看篇)SurfaceView运行机制详解—剖析Back与Home按键及切入后台等异常处理!
上一篇跟各位童鞋介绍了SharedPreference 和 File流如何存储数据,并且推荐使用FileOutputStream/FileInputStream来存储咱们游戏数据,那么这一篇则是像大家介绍另外一种适合游戏数据存储的方式:SQLite 轻量级数据库!
先介绍几个基本概念知识:
什么是SQLite:
SQLite是一款轻量级数据库,它的设计目的是嵌入式,而且它占用的资源非常少,在嵌入式设备中,只需要几百KB!!!!!
SQLite的特性:
- 轻量级
使用 SQLite 只需要带一个动态库,就可以享受它的全部功能,而且那个动态库的尺寸想当小。
- 独立性
SQLite 数据库的核心引擎不需要依赖第三方软件,也不需要所谓的“安装”。
- 隔离性
SQLite 数据库中所有的信息(比如表、视图、触发器等)都包含在一个文件夹内,方便管理和维护。
- 跨平台
SQLite 目前支持大部分操作系统,不至电脑操作系统更在众多的手机系统也是能够运行,比如:Android。
- 多语言接口
SQLite 数据库支持多语言编程接口。
- 安全性
SQLite 数据库通过数据库级上的独占性和共享锁来实现独立事务处理。这意味着多个进程可以在同一时间从同一数据库读取数据,但只能有一个可以写入数据.
优点:1.能存储较多的数据。
2.能将数据库文件存放到SD卡中!
什么是 SQLiteDatabase?
一个 SQLiteDatabase 的实例代表了一个SQLite 的数据库,通过SQLiteDatabase 实例的一些方法,我们可以执行SQL 语句,对数 据库进行增、删、查、改的操作。需要注意的是,数据库对于一个应用来说是私有的,并且在一个应用当中,数据库的名字也是惟一的。
什么是 SQLiteOpenHelper ?
根据这名字,我们可以看出这个类是一个辅助类。这个类主要生成一个数据库,并对数据库的版本进行管理。当在程序当中调用这个类的 方法getWritableDatabase(),或者getReadableDatabase()方法的时候,如果当时没有数据,那么Android 系统就会自动生成一 个数 据库。SQLiteOpenHelper 是一个抽象类,我们通常需要继承它,并且实现里边的3 个函数,
什么是 ContentValues 类?
ContentValues 类和Hashmap/Hashtable 比较类似,它也是负责存储一些名值对,但是它存储的名值对当中的名是一个
String 类型,而值都是基本类型。
什么是 Cursor ?
Cursor 在Android 当中是一个非常有用的接口,通过Cursor 我们可以对从数据库查询出来的结果集进行随 机的读写访问。
OK,基本知识就介绍到这里,下面开始上代码:还是按照我的一贯风格,代码中该解释的地方都已经在代码中及时注释和讲解了!
顺便来张项目截图:
先给出xml:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical" android:layout_width="fill_parent"
- android:layout_height="fill_parent">
- <TextView android:layout_width="fill_parent"
- android:layout_height="wrap_content" android:text="SQL 练习!(如果你使用的SD卡存储数据方式,为了保证正常操作,请你先点击创建一张表然后再操作)"
- android:textSize="20sp" android:textColor="#ff0000" android:id="@+id/tv_title" />
- <Button android:id="@+id/sql_addOne" android:layout_width="fill_parent"
- android:layout_height="wrap_content" android:text="插入一条记录"></Button>
- <Button android:id="@+id/sql_check" android:layout_width="fill_parent"
- android:layout_height="wrap_content" android:text="查询数据库"></Button>
- <Button android:id="@+id/sql_edit" android:layout_width="fill_parent"
- android:layout_height="wrap_content" android:text="修改一条记录"></Button>
- <Button android:id="@+id/sql_deleteOne" android:layout_width="fill_parent"
- android:layout_height="wrap_content" android:text="删除一条记录"></Button>
- <Button android:id="@+id/sql_deleteTable" android:layout_width="fill_parent"
- android:layout_height="wrap_content" android:text="删除数据表单"></Button>
- <Button android:id="@+id/sql_newTable" android:layout_width="fill_parent"
- android:layout_height="wrap_content" android:text="新建数据表单"></Button>
- </LinearLayout>
xml中定义了我们需要练习用到的几个操作按钮,这里不多解释了,下面看java源码:先看我们继承的 SQLiteOpenHelper 类
- package com.himi;
- import android.content.Context;
- import android.database.sqlite.SQLiteDatabase;
- import android.database.sqlite.SQLiteOpenHelper;
- import android.util.Log;
-
-
-
-
-
-
- public class MySQLiteOpenHelper extends SQLiteOpenHelper {
- public final static int VERSION = 1;
- public final static String TABLE_NAME = "himi";
- public final static String ID = "id";
- public final static String TEXT = "text";
- public static final String DATABASE_NAME = "Himi.db";
- public MySQLiteOpenHelper(Context context) {
-
-
-
-
-
- super(context, DATABASE_NAME, null, VERSION);
- }
- @Override
-
- public void onCreate(SQLiteDatabase db) {
- String str_sql = "CREATE TABLE " + TABLE_NAME + "(" + ID
- + " INTEGER PRIMARY KEY AUTOINCREMENT," + TEXT + " text );";
-
-
-
-
-
-
- db.execSQL(str_sql);
-
-
-
- }
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
-
-
-
-
- Log.v("Himi", "onUpgrade");
- }
- }
我喜欢代码中立即附上解释,感觉这样代码比较让大家更容易理解和寻找,当然如果童鞋们不喜欢,可以告诉我,我改~嘿嘿~
下面看最重要的MainActivity中的代码:
- package com.himi;
- import java.io.File;
- import java.io.IOException;
- import android.app.Activity;
- import android.content.ContentValues;
- import android.database.Cursor;
- import android.database.sqlite.SQLiteDatabase;
- import android.os.Bundle;
- import android.view.View;
- import android.view.Window;
- import android.view.WindowManager;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- import android.widget.TextView;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- public class MainActivity extends Activity implements OnClickListener {
- private Button btn_addOne, btn_deleteone, btn_check, btn_deleteTable,
- btn_edit, btn_newTable;
- private TextView tv;
- private MySQLiteOpenHelper myOpenHelper;
- private SQLiteDatabase mysql ;
-
-
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
- WindowManager.LayoutParams.FLAG_FULLSCREEN);
- this.requestWindowFeature(Window.FEATURE_NO_TITLE);
- setContentView(R.layout.main);
- tv = (TextView) findViewById(R.id.tv_title);
- btn_addOne = (Button) findViewById(R.id.sql_addOne);
- btn_check = (Button) findViewById(R.id.sql_check);
- btn_deleteone = (Button) findViewById(R.id.sql_deleteOne);
- btn_deleteTable = (Button) findViewById(R.id.sql_deleteTable);
- btn_newTable = (Button) findViewById(R.id.sql_newTable);
- btn_edit = (Button) findViewById(R.id.sql_edit);
- btn_edit.setOnClickListener(this);
- btn_addOne.setOnClickListener(this);
- btn_check.setOnClickListener(this);
- btn_deleteone.setOnClickListener(this);
- btn_deleteTable.setOnClickListener(this);
- btn_newTable.setOnClickListener(this);
- myOpenHelper = new MySQLiteOpenHelper(this);
-
-
-
-
-
-
-
-
-
-
-
-
- }
- @Override
- public void onClick(View v) {
- try {
-
-
-
- mysql = myOpenHelper.getWritableDatabase();
- if (v == btn_addOne) {
-
-
-
-
- ContentValues cv = new ContentValues();
- cv.put(MySQLiteOpenHelper.TEXT, "测试新的数据");
- mysql.insert(MySQLiteOpenHelper.TABLE_NAME, null, cv);
-
-
-
-
-
-
-
- tv.setText("添加数据成功!点击查看数据库查询");
- } else if (v == btn_deleteone) {
-
- mysql.delete("himi", MySQLiteOpenHelper.ID + "=1", null);
-
-
-
-
-
-
- tv.setText("删除数据成功!点击查看数据库查询");
- } else if (v == btn_check) {
-
- Cursor cur = mysql.rawQuery("SELECT * FROM "
- + MySQLiteOpenHelper.TABLE_NAME, null);
- if (cur != null) {
- String temp = "";
- int i = 0;
- while (cur.moveToNext()) {
- temp += cur.getString(0);
-
- temp += cur.getString(1);
-
- i++;
- temp += " ";
- if (i % 3 == 0)
- temp += "/n";
- }
- tv.setText(temp);
- }
- } else if (v == btn_edit) {
-
- ContentValues cv = new ContentValues();
- cv.put(MySQLiteOpenHelper.TEXT, "修改后的数据");
- mysql.update("himi", cv, "id " + "=" + Integer.toString(3), null);
-
-
-
-
- tv.setText("修改数据成功!点击查看数据库查询");
- } else if (v == btn_deleteTable) {
- mysql.execSQL("DROP TABLE himi");
- tv.setText("删除表成功!点击查看数据库查询");
- } else if (v == btn_newTable) {
- String TABLE_NAME = "himi";
- String ID = "id";
- String TEXT = "text";
- String str_sql2 = "CREATE TABLE " + TABLE_NAME + "(" + ID
- + " INTEGER PRIMARY KEY AUTOINCREMENT," + TEXT
- + " text );";
- mysql.execSQL(str_sql2);
- tv.setText("新建表成功!点击查看数据库查询");
- }
-
-
- } catch (Exception e) {
- tv.setText("操作失败!");
- } finally {
- mysql.close();
- }
- }
- }
以上代码中我们实现了两种存储方式:
一种存储默认系统路径/data-data-com.himi-databases下,另外一种则是保存在了/sdcard-himi下,生成数据库文件himi.db
那么这里两种实现方式大概步骤和区别说下:
-----------如果我们使用默认系统路径存储数据库文件:
第一步:新建一个类继承SQLiteOpenHelper;写一个构造,重写两个函数!
第二步:在新建的类中的onCreate(SQLiteDatabase db) 方法中创建一个表;
第三步:在进行删除数据、添加数据等操作的之前我们要得到数据库读写句柄得到一个数据库实例;
注意: 继承写这个辅助类,是为了在我们没有数据库的时候自动为我们生成一个数据库,并且生成数据库文件,这里也同时创建了一张表,因为我们在onCreate里是在数据库中创建一张表的操作;这里还要注意在我们new 这个我们这个MySQLiteOpenHelper 类实例对象的时候并没有创建数据库哟~!而是在我们调用 (备注3)MySQLiteOpenHelper ..getWritableDatabase() 这个方法得到数据库读写句柄的时候,android 会分析是否已经有了数据库,如果没有会默认为我们创建一个数据库并且在系统路径data-data-com.himi-databases下生成himi.db 文件!
(如果我们使用sd卡存储数据库文件,就没有必要写这个类了,而是我们自己Open自己的文件得到一个数据库,西西,反而方便~ )
-----------如果我们需要把数据库文件存储到SD卡中:
第一步:确认模拟器存在SD卡,关于SD卡的两种创建方法见我的博文:【Android 2D游戏开发之十】
第二步:(备注1)先创建SD卡目录和路径已经我们的数据库文件!这里不像上面默认路径中的那样,如果没有数据库会默认系统路径生成一个数据库和一个数据库文件!我们必须手动创建数据库文件!
第三步:在进行删除数据、添加数据等操作的之前我们要得到数据库读写句柄得到一个数据库实例;(备注2)此时的创建也不是像系统默认创建,而是我们通过打开第一步创建好的文件得到数据库实例。这里仅仅是创建一个数据库!!!!
第四步:在进行删除数据、添加数据等操作的之前我们还要创建一个表!
第五步:在配置文件AndroidMainfest.xml 声明写入SD卡的权限,上一篇已经介绍权限了,不知道的自己去看下吧。
有些童鞋不理解什么默认路径方式中就有表?那是因为我们在它默认给我们创建数据库的时候我们有创建表的操作,就是MySQLiteOpenHelper类中的onCreate()方法里的操作!所以我们如果要在进行删除数据、添加数据等操作的之前还要创建一个表,创建表的方法都是一样的。
总结:不管哪种方式我们都要-创建数据库-创建表-然后进行操作!
备注4:
在Android中查询数据是通过Cursor类来实现的,当我们使用SQLiteDatabase.query()方法时,会得到一个Cursor对象,Cursor指向的就是每一条数据。它提供了很多有关查询的方法,具体方法如下:
以下是方法和说明:
move 以当前的位置为参考,将Cursor移动到指定的位置,成功返回true, 失败返回false
moveToPosition 将Cursor移动到指定的位置,成功返回true,失败返回false
moveToNext 将Cursor向前移动一个位置,成功返回true,失败返回false
moveToLast 将Cursor向后移动一个位置,成功返回true,失败返回 false。
movetoFirst 将Cursor移动到第一行,成功返回true,失败返回false
isBeforeFirst 返回Cursor是否指向第一项数据之前
isAfterLast 返回Cursor是否指向最后一项数据之后
isClosed 返回Cursor是否关闭
isFirst 返回Cursor是否指向第一项数据
isLast 返回Cursor是否指向最后一项数据
isNull 返回指定位置的值是否为null
getCount 返回总的数据项数
getInt 返回当前行中指定的索引数据
对于SQLite的很多童鞋有接触过,但是就不知道怎么存储在SD中,所以我也研究了下,这篇也写了把sd卡中的方式也提供给大家。
OK 这元旦放假几天就光给大家写这个了,呵呵~凌晨2点了,咳咳~该睡觉了。(我一般凌成3点睡觉,早8点起来上班 呵呵~习惯了~)
(推荐大家订阅本博客,因为咱的更新速度可是很快的~娃哈哈)
本篇源码: http://www.himigame.com/android-game/329.html