對於數據的存儲,Android 提供了4種保存方式。
(1)SharedPreference
此方法適用於簡單數據的保持,文如其名,屬於配置性質的保存,不適合比較大的情況,默認存放在手機內存里
(2)FileInputStream/FileOutputStream
此方式比較適合游戲的保存和使用,流文件數據存儲可以保持較大的數據,而且通過此方式不僅能把數據存儲在手機內存中,也能將數據保存到手機額SDcard中。
(3)SQLite
此方式也適合游戲的保存和使用,不僅可以保存較大的數據,而且可以將自己的數據存儲到文件系統或者數據庫當中,如SQLite數據庫,也能將數據保存到SDcard 中。
(4)ContentProvider
此方式不推薦用於游戲保存,雖然此方式能存儲較大數據,還支持多個程序之間的數據進行交換,但游戲中基本就不可能去訪問外部應用程序的數據。
1.SharedPreference
SharedPreference 實例是通過Context 對象得到的:
Context.getSharePreference(String name,int mode)
作用:利用Context 對象獲取一個SharedPreference 實例
參數1:生成保持記錄的文件名
參數2:操作模式
SharedPreference 實例的操作模式一共有四種:
Context.MODE_PRIVATE:新內容覆蓋原內容。
Context.MODE_APPEND:新內容追加到原內容后。
Context.MODE_WORLD_READABLE:允許其他應用程序讀取。
Context.MODE_WORLD_WRITEABLE:允許其他應用程序寫入,會覆蓋原數據。
SharedPreference 常用函數:
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 常用函數的作用是獲取存儲文件中的值,根據方法不同獲取不同對應的類型值,一般第一個參數為索引Key值,第二個參數為在存儲文件中找不到對應 value 值時,默認的返回值。
對應的,在對存儲文件的數據進行存入操作時,首先需要利用 SharedPreference 實例得到一個編輯對象:
SharedPreference.Editor edit;
得到編輯對象后就可以對 SharedPreference 中的數據進行操作。
SharedPreference.Editor.putFloat(arg0,arg1)
SharedPreference.Editor.putInt(arg0,arg1)
SharedPreference.Editor.putLong(arg0,arg1)
SharedPreference.Editor.putString(arg0,arg1)
SharedPreference.Editor.putBoolean(arg0,arg1)
以上方法的作用是對存儲的數據進行操作(寫入、保存),其中第一個參數是需要保存數據額Key值索引,第二個參數是需要保存的數據。
到此進行了保存和修改,還需要將其編輯的數據進行提交方可完成存入和修改:
SharedPreference.Editor.commit()
如果想刪除存儲文件中的一條數據,可以使用以下函數:
SharedPreference.Editor.clear()
下面用一個簡單小游戲進行說明,先看下效果圖:
新建項目,游戲框架為 SurfaceView 游戲框架,修改 MySurfaceView 類如下:

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; 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.流文件存儲
利用前面 SharedPreference 的例子,去除 SharedPreference 存儲部分,改用流文件形式進行保存,只需要修改其中“保存”和“讀取”操作,也就是修改“按鍵事件”:
/** * 按鍵事件監聽 */ @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 { // 利用Activity 實例打開流文件得到一個寫入流 fos = MainActivity.instance.openFileOutput("save.yc", Context.MODE_PRIVATE); // 將寫入流封裝在數據寫入流中 dos = new DataOutputStream(fos); //寫入一個int 類型(將圓形所在格子的下表寫入流文件中) dos.writeInt(creentTileIndex); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); }finally{ //即使保存時發生異常也要關閉流 try { if(fos!=null) fos.close(); if(dos!=null)dos.close(); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } // 下鍵讀取游戲狀態 } else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) { try { if(MainActivity.instance.openFileInput("save.yc")!=null) { try { //利用Activity 實例打開流文件得到一個讀出流 fis = MainActivity.instance.openFileInput("save.yc"); //將讀出流封裝在數據讀入流中 dis = new DataInputStream(fis); //讀出一個int 類型賦值與圓形所在格子的下標 creentTileIndex =dis.readInt(); } catch (Exception e) { // TODO: handle exception }finally{ if(fis!=null)fis.close(); if(dis!=null)dis.close(); } } } catch (Exception e) { // TODO: handle exception } // 圓形的移動 } 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); }
不管是讀入還是寫入,都是通過Activity 打開流文件得到輸入輸出流。當需要寫入流文件時,如果打開的流文件不存在,那么Android 會自動生成對應的流文件;而當需要讀入流文件時,首先應判斷流文件是否存在,一旦流文件不存在,就會拋出異常。
這里的流形式的保存操作比較簡單,需要注意的是:
● 讀流時,一定要記得判斷是否存在需要操作的流文件;
● 寫入和讀入的數據類型要配對,順序也不能錯;例如:寫入時,先寫入了一個 Int值,然后又寫入了一個String 值;那么讀入時,也應該先讀 Int 類型,然后再讀 String 類型;
● 流一旦打開一定要關閉,為了避免流操作出現異常,需確保正常關閉流,應該將關閉操作寫在finally 語句中;
● file 流使用 Data 流進行了封裝,這樣做的原因是可以獲得更多的操作方式,便於對數據的處理。
以上是使用流文件的保存方式,但是也只是將保存后的流文件默認放在了系統內存里。一般游戲的數據可能會有很多,所以不應該放在手機內存中,而是放在 SDCard 中,這樣就不要擔心系統因游戲保存的數據過多導致內存不足等問題。
將流文件保存在 SDCard 中的詳細步驟如下:
(1)聲明讀取權限:
Android 中的一些操作,比如:讀取通訊錄信息、發送信息、使用聯網、GPRS等功能都需要在項目 AndroidManifest.xml 中聲明使用權限,然后才可以正常使用其功能。
當然在很多時候,是不知道是否需要聲明添加權限的,其實這個也不用知道,因為如果用到這些需要聲明權限的功能,且恰好沒有聲明的情況下,在LogCat 中是會報異常的,其異常則提醒需要添加對應的權限。
寫入權限如下:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
(2)創建目錄和存儲文件
使用 SDCard 的方式進行存儲數據,寫入的時候 Android 不會跟存儲系統默認路徑那樣默認生成存儲文件,所以必須自己來創建;如果存儲的文件有自定義路徑的話,那么這個路徑也需要手動添加。
假定存儲文件在 SDCard 的路徑為 /sdcard/yc/save.yc 。
① 首先需要創建路徑 /sdcard/yc
File path = new File(" /sdcard/yc");// 創建目錄 if(!path.exists())// 目錄存在返回true { path.mkdirs();// 創建一個目錄 }
boolean File.exists()
作用:判斷是否存在當前目錄
返回值:當前目錄存在返回true
boolean File.mkdirs()
作用:創建一個目錄
返回值:當創建成功返回true
②然后創建存儲文件:/sdcard/yc/save.yc
File path_File = new File(" /sdcard/yc/save.yc");// 創建文件 if(!path_File.exists())// 文件存在返回true { path_File.createNewFile();// 創建一個文件 }
boolean File.createNewFile()
作用:創建一個文件
返回值:創建成功返回true
(3)通過加載指定路徑的存儲文件獲取輸入輸出流
● 輸入流:FileInputStream fis = new FileInputStream(File file);
● 輸出流:FileOutputStream fos = new FileOutputStream(File file);
除此之外還需要知道一點,因為有時手機並沒有安裝 SDCard ,或者當前SDCard 處於被移除的狀態時,為了避免這兩種情況帶來的異常,需要通過下面方法獲取當前手機設備SDCard 的狀態:
String Environment.getExternalStorageStorageState()
作用:獲取當前SDCard的狀態
返回值:當前 SDCard 不存在時,返回null ;當 SDCard 處於移除狀態時,返回“removed”;
所以當默認手機設備存在 SDCard 時,保存在 SDCard 中 ;當 SDCard 不存在或者正處於被移除的狀態時,默認將數據保存在手機內存中。上面的“按鍵事件”修改如下:

/** * 按鍵事件監聽 */ @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("yc", "寫入,有SD卡"); File path = new File("/sdcard/yc");// 創建目錄 File f = new File("/sdcard/yc/save.yc");// 創建文件 if (!path.exists()) {// 目錄存在返回true path.mkdirs();// 創建一個目錄 } if (!f.exists()) {// 文件存在返回true f.createNewFile();// 創建一個文件 } fos = new FileOutputStream(f);// 將數據存入sd卡中 } else { //默認系統路徑 //利用Activity實例打開流文件得到一個寫入流 fos = MainActivity.instance.openFileOutput("save.yc", 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("yc", "讀取,有SD卡"); isHaveSDCard = true; } try { if (isHaveSDCard) { File path = new File("/sdcard/yc");// 創建目錄 File f = new File("/sdcard/yc/save.yc");// 創建文件 if (!path.exists()) {// 目錄存在返回true return false; } else { if (!f.exists()) {// 文件存在返回true return false; } } fis = new FileInputStream(f);// 將數據存入sd卡中 } else { if (MainActivity.instance.openFileInput("save.yc") != null) { //利用Activity實例打開流文件得到一個讀入流 fis = MainActivity.instance.openFileInput("save.yc"); } } //將讀入流封裝在數據讀入流中 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); }
3.SQLite 輕量級數據庫
此方式也適合游戲的保存和使用,不僅可以保存較大的數據,而且可以將自己的數據存儲到文件系統或者數據庫當中,如SQLite數據庫,也能將數據保存到SDcard 中。
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 我們可以對從數據庫查詢出來的結果集進行隨機的讀寫訪問。
同樣利用前面 SharedPreference 的例子,去除 SharedPreference 存儲部分,改用SQLite進行保存。
① 首先新建一個類MySQLiteOpenHelper繼承SQLiteOpenHelper;寫一個構造,重寫兩個函數:

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 = "INDEXINFO";// 表名 public final static String Param1 = "ID";// 后面ContentProvider使用 public final static String Param2 = "TITLEINDEX"; public final static String DATABASE_NAME = "yc.db"; public MySQLiteOpenHelper(Context context) { // 在Android 中創建和打開一個數據庫都可以使用openOrCreateDatabase 方法來實現, // 因為它會自動去檢測是否存在這個數據庫,如果存在則打開,不過不存在則創建一個數據庫; // 創建成功則返回一個 SQLiteDatabase對象,否則拋出異常FileNotFoundException。 // 下面是來創建一個名為"DATABASE_NAME"的數據庫,並返回一個SQLiteDatabase對象 super(context, DATABASE_NAME, null, VERSION); } /** * 在數據庫第一次生成的時候會調用這個方法,一般我們在這個方法里邊生成數據庫表; */ @Override public void onCreate(SQLiteDatabase db) { // SQL語句,這里是創建一個表明為yc的表,有2個參數ID和TITLEINDEX,其中ID為主鍵,自增。具體說明如下: // CREATE TABLE 創建一張表 然后后面是表名 // 然后表的列,第一個是id 方便操作數據,int類型 // PRIMARY KEY 是指主鍵 這是一個int型,用於唯一的標識一行; // AUTOINCREMENT 表示數據庫會為每條記錄的key加一,確保記錄的唯一性; // 最后加入一列文本 int類型參數TITLEINDEX String str_sql = "CREATE TABLE " + TABLE_NAME + "(" + Param1 + " INTEGER PRIMARY KEY AUTOINCREMENT," + Param2 + " INTEGER );"; // execSQL()方法是執行一句sql語句 db.execSQL(str_sql); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // 一般默認情況下,當我們插入 數據庫就立即更新 // 當數據庫需要升級的時候,Android 系統會主動的調用這個方法。 // 一般我們在這個方法里邊刪除數據表,並建立新的數據表, // 當然是否還需要做其他的操作,完全取決於游戲需求。 Log.v("y_Hint", "onUpgrade"); } }
② 在MySurfaceView類中創建對應的實例
private MySQLiteOpenHelper myOpenHelper;// 創建一個繼承SQLiteOpenHelper類實例 private SQLiteDatabase db;
③ 在SurfaceView初始化函數中實例一個數據庫輔助器
// 實例一個數據庫輔助器 myOpenHelper = new MySQLiteOpenHelper(MainActivity.instance);
④ 最后修改按鍵監聽事件,其實只需要修改其中“保存”和“讀取”操作,代碼如下:
/** * 按鍵事件監聽 */ @Override public boolean onKeyDown(int keyCode, KeyEvent event) { db = myOpenHelper.getWritableDatabase(); // 實例數據庫 // 上鍵保存游戲狀態 if (keyCode == KeyEvent.KEYCODE_DPAD_UP) { // ---------------------- SQL語句刪除-------------- String DELETE_DATA = "DELETE FROM " + MySQLiteOpenHelper.TABLE_NAME; db.execSQL(DELETE_DATA); // ---------------------- SQL語句插入-------------- String INSERT_DATA = "INSERT INTO " + MySQLiteOpenHelper.TABLE_NAME + "(" + MySQLiteOpenHelper.Param2 + ") values (" + creentTileIndex + ")"; db.execSQL(INSERT_DATA); // 下鍵讀取游戲狀態 } else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) { // 數據查詢 Cursor cur = db.rawQuery("SELECT * FROM " + MySQLiteOpenHelper.TABLE_NAME, null); if (cur != null) { cur.moveToNext(); creentTileIndex = cur.getInt(1); } } 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); }
說明:
在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 返回當前行中指定的索引數據
本文地址:http://www.cnblogs.com/yc-755909659/p/4223999.html
PS:本文由J灬葉小超原創,如有轉載請注明出處,謝謝!