Android游戏开发基础part9--游戏数据存储
Android游戏开发基础part9--游戏数据存储
在Android中,对于数据的存储,提供了4种保存方式:
1.SharedPreference
此方式适用于简单的数据的保存,文如其名,属于配置性质的保存,不适合数据比较大的情况,默认存放在手机内存里。
2.FileInputStream/FileOutputStream
此方式比较适合游戏的保存和使用,流文件存储可以保存较大的数据,而且通过此方式不仅能把数据存储在手机内存中,也能将数据保存到手机的SDcard
3.SQLite
此方式也适合游戏的保存和使用,不仅可以保存较大的数据,而且可以将自己的数据存放在文件系统或者数据库当中,如SQLite数据库,也能将数据保存到SDcard中。
4.ContentProvider
此方式不推荐用于游戏保存,虽然次方式能存储较大的数据,还支持多个程序之间的数据进行交换,但由于游戏中基本就不可能访问外部应用的数据。
1.SharedPreference
SharedPreference实例是通过Context对象得到的:
Context.getSharedPreference(String name, int mode)
作用:利用Context对象获取一个SharedPreference实例
第一个参数:生成保存记录的文件名
第二个参数:操作模式
操作模式:
·Context.MODE_PRIVATE:新内容覆盖原内容。
·Context.MODE_APPEND:新内容追加到原内容后。
·Context.MODE_WORLD_READABLE:允许其他应用程序读取。
·Context.MODE_WORLD_WRITEABLE:允许其他应用程序写入,会覆盖原数据。
常用函数:
·getFloat(String key, float defValue)
·getInt(String key, int defValue)
·getLong(String key, long defValue)
·getString(String key, String defValue)
·getBoolean(String key, Boolean defValue)
对存储文件的数据进行存入操作时,首先需要利用SharedPreference实例得到一个编辑对象:SharedPreferences.Editor edit();
得到一个编辑对象后就可以对SharedPreference中的数据进行操作。
·SharedPreferences.Editor.putFloat(arg0, arg1)
·SharedPreferences.Editor.putFInt(arg0, arg1)
·SharedPreferences.Editor.putLong(arg0, arg1)
·SharedPreferences.Editor.putString(arg0, arg1)
·SharedPreferences.Editor.putBoolean(arg0, arg1)
以上方法的作用是对存储的数据进行操作(写入、保存),其中的第一个参数是需要保存数据的Key值索引,第二个参数是需要保存的数据。
数据要真正写入到SharedPreferences生成的存储文件中,还需要提交:
SharedPreference.Editor.commit();
创建实例:SharedPreferenceProject
==>MySurfaceView.java
package com.spfp; import android.content.Context; import android.content.SharedPreferences; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.Style; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.SurfaceHolder.Callback; /** * * @author Himi * */ public class MySurfaceView extends SurfaceView implements Callback, Runnable { private SurfaceHolder sfh; private Paint paint; private Thread th; private boolean flag; private Canvas canvas; private int screenW, screenH; //记录当前圆形所在九宫格的位置下标 private int creentTileIndex; //声明一个SharedPreferences对象 private SharedPreferences sp; /** * SurfaceView初始化函数 */ public MySurfaceView(Context context) { super(context); sfh = this.getHolder(); sfh.addCallback(this); paint = new Paint(); paint.setColor(Color.BLACK); paint.setAntiAlias(true); setFocusable(true); //通过Context获取SharedPreference实例 sp = context.getSharedPreferences("SaveName", Context.MODE_PRIVATE); //每次程序运行时获取圆形的下标 int tempIndex = sp.getInt("CirCleIndex", -1); //判定如果返回-1 说明没有找到,就不对当前记录圆形的变量进行赋值 if (tempIndex != -1) { creentTileIndex = tempIndex; } } /** * SurfaceView视图创建,响应此函数 */ @Override public void surfaceCreated(SurfaceHolder holder) { screenW = this.getWidth(); screenH = this.getHeight(); flag = true; //实例线程 th = new Thread(this); //启动线程 th.start(); } /** * 游戏绘图 */ public void myDraw() { try { canvas = sfh.lockCanvas(); if (canvas != null) { canvas.drawColor(Color.WHITE); paint.setColor(Color.BLACK); paint.setStyle(Style.STROKE); //绘制九宫格(将屏幕九等份) //得到每个方格的宽高 int tileW = screenW / 3; int tileH = screenH / 3; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { canvas.drawRect(i * tileW, j * tileH, (i + 1) * tileW, (j + 1) * tileH, paint); } } //根据得到的圆形下标位置进行绘制相应的方格中 paint.setStyle(Style.FILL); canvas.drawCircle(creentTileIndex % 3 * tileW + tileW / 2, creentTileIndex / 3 * tileH + tileH / 2, 30, paint); //操作说明 canvas.drawText("上键:保存游戏", 0, 20, paint); canvas.drawText("下键:读取游戏", 110, 20, paint); canvas.drawText("左右键:移动圆形", 215, 20, paint); } } catch (Exception e) { // TODO: handle exception } finally { if (canvas != null) sfh.unlockCanvasAndPost(canvas); } } /** * 触屏事件监听 */ @Override public boolean onTouchEvent(MotionEvent event) { return true; } /** * 按键事件监听 */ @Override public boolean onKeyDown(int keyCode, KeyEvent event) { //上键保存游戏状态 if (keyCode == KeyEvent.KEYCODE_DPAD_UP) { sp.edit().putInt("CirCleIndex", creentTileIndex).commit(); //下键读取游戏状态 } else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) { int tempIndex = sp.getInt("CirCleIndex", -1); if (tempIndex != -1) { creentTileIndex = tempIndex; } //圆形的移动 } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) { if (creentTileIndex > 0) { creentTileIndex -= 1; } } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) { if (creentTileIndex < 8) { creentTileIndex += 1; } } return super.onKeyDown(keyCode, event); } /** * 游戏逻辑 */ private void logic() { } @Override public void run() { while (flag) { long start = System.currentTimeMillis(); myDraw(); logic(); long end = System.currentTimeMillis(); try { if (end - start < 50) { Thread.sleep(50 - (end - start)); } } catch (InterruptedException e) { e.printStackTrace(); } } } /** * SurfaceView视图状态发生改变,响应此函数 */ @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } /** * SurfaceView视图消亡时,响应此函数 */ @Override public void surfaceDestroyed(SurfaceHolder holder) { flag = false; } }
2.流文件存储 FileInputStream/FileOutputStream
创建实例:修改SharedPreference项目中“读取”与“保存的操作” StreamProject
代码:MySurfaceView.java
package com.stp; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.Style; import android.os.Environment; import android.util.Log; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.SurfaceHolder.Callback; /** * * @author Himi * */ public class MySurfaceView extends SurfaceView implements Callback, Runnable { private SurfaceHolder sfh; private Paint paint; private Thread th; private boolean flag; private Canvas canvas; private int screenW, screenH; //记录当前圆形所在九宫格的位置下标 private int creentTileIndex; /** * SurfaceView初始化函数 */ public MySurfaceView(Context context) { super(context); sfh = this.getHolder(); sfh.addCallback(this); paint = new Paint(); paint.setColor(Color.BLACK); paint.setAntiAlias(true); setFocusable(true); } /** * SurfaceView视图创建,响应此函数 */ @Override public void surfaceCreated(SurfaceHolder holder) { screenW = this.getWidth(); screenH = this.getHeight(); flag = true; //实例线程 th = new Thread(this); //启动线程 th.start(); } /** * 游戏绘图 */ public void myDraw() { try { canvas = sfh.lockCanvas(); if (canvas != null) { canvas.drawColor(Color.WHITE); paint.setColor(Color.BLACK); paint.setStyle(Style.STROKE); //绘制九宫格(将屏幕九等份) //得到每个方格的宽高 int tileW = screenW / 3; int tileH = screenH / 3; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { canvas.drawRect(i * tileW, j * tileH, (i + 1) * tileW, (j + 1) * tileH, paint); } } //根据得到的圆形下标位置进行绘制相应的方格中 paint.setStyle(Style.FILL); canvas.drawCircle(creentTileIndex % 3 * tileW + tileW / 2, creentTileIndex / 3 * tileH + tileH / 2, 30, paint); //操作说明 canvas.drawText("上键:保存游戏", 0, 20, paint); canvas.drawText("下键:读取游戏", 110, 20, paint); canvas.drawText("左右键:移动圆形", 215, 20, paint); } } catch (Exception e) { // TODO: handle exception } finally { if (canvas != null) sfh.unlockCanvasAndPost(canvas); } } /** * 触屏事件监听 */ @Override public boolean onTouchEvent(MotionEvent event) { return true; } /** * 按键事件监听 */ @Override public boolean onKeyDown(int keyCode, KeyEvent event) { //用到的读出、写入流 FileOutputStream fos = null; FileInputStream fis = null; DataOutputStream dos = null; DataInputStream dis = null; //上键保存游戏状态 if (keyCode == KeyEvent.KEYCODE_DPAD_UP) { try { // 从SDcard中写入数据 // 试探终端是否有sdcard! 并且探测SDCard是否处于被移除的状态 if (Environment.getExternalStorageState() != null && !Environment.getExternalStorageState().equals("removed")) { Log.v("Himi", "写入,有SD卡"); File path = new File("/sdcard/himi");// 创建目录 File f = new File("/sdcard/himi/save.himi");// 创建文件 if (!path.exists()) {// 目录存在返回true path.mkdirs();// 创建一个目录 } if (!f.exists()) {// 文件存在返回true f.createNewFile();// 创建一个文件 } fos = new FileOutputStream(f);// 将数据存入sd卡中 } else { //默认系统路径 //利用Activity实例打开流文件得到一个写入流 fos = MainActivity.instance.openFileOutput("save.himi", Context.MODE_PRIVATE); } //将写入流封装在数据写入流中 dos = new DataOutputStream(fos); //写入一个int类型(将圆形所在格子的下标写入流文件中) dos.writeInt(creentTileIndex); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { //即使保存时发生异常,也要关闭流 try { if (fos != null) fos.close(); if (dos != null) dos.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //下键读取游戏状态 } else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) { boolean isHaveSDCard = false; // 从SDcard中读取数据 // 试探终端是否有sdcard! 并且探测SDCard是否处于被移除的状态 if (Environment.getExternalStorageState() != null && !Environment.getExternalStorageState().equals("removed")) { Log.v("Himi", "读取,有SD卡"); isHaveSDCard = true; } try { if (isHaveSDCard) { File path = new File("/sdcard/himi");// 创建目录 File f = new File("/sdcard/himi/save.himi");// 创建文件 if (!path.exists()) {// 目录存在返回true return false; } else { if (!f.exists()) {// 文件存在返回true return false; } } fis = new FileInputStream(f);// 将数据存入sd卡中 } else { if (MainActivity.instance.openFileInput("save.himi") != null) { //利用Activity实例打开流文件得到一个读入流 fis = MainActivity.instance.openFileInput("save.himi"); } } //将读入流封装在数据读入流中 dis = new DataInputStream(fis); //读出一个Int类型赋值与圆形所在格子的下标 creentTileIndex = dis.readInt(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { //即使读取时发生异常,也要关闭流 try { if (fis != null) fis.close(); if (dis != null) dis.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) { if (creentTileIndex > 0) { creentTileIndex -= 1; } } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) { if (creentTileIndex < 8) { creentTileIndex += 1; } } return super.onKeyDown(keyCode, event); } /** * 游戏逻辑 */ private void logic() { } @Override public void run() { while (flag) { long start = System.currentTimeMillis(); myDraw(); logic(); long end = System.currentTimeMillis(); try { if (end - start < 50) { Thread.sleep(50 - (end - start)); } } catch (InterruptedException e) { e.printStackTrace(); } } } /** * SurfaceView视图状态发生改变,响应此函数 */ @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } /** * SurfaceView视图消亡时,响应此函数 */ @Override public void surfaceDestroyed(SurfaceHolder holder) { flag = false; } }
将流文件保存在SDcard中的步骤:
(1)声明写入权限:
<uses-permission android:name="android.premission.WRITE_EXTERNAL_STORAGE"/>
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.stp" android:versionCode="1" android:versionName="1.0"> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".MainActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
(2)创建目录和存储文件
1.首先需要创建路径:/sdcard/wwj
//声明一个路径
File path = new File("/sdcard/wwj");
if(!path.exists()){
path.mkdirs();
}
2.然后创建存储文件:/sdcard/wwj/save.wwj
//声明一个路径
File f = new File("/sdcard/wwj/save.wwj");
if(!f.exist()){//文件存在就返回true
f.createNewFile();//创建一个文件
}
(3)通过加载指定路径的存储文件获取输入输出流
·输入流:FileInputStream fis = new FileInputStream(File file);
·输出流:FileOutputSteam fos = new FileOutputSteam(File file);