1、概述
Android提供了5種方式來讓用戶保存持久化應用程序數據。根據自己的需求來做選擇,比如數據是否是應用程序私有的,是否能被其他程序訪問,需要多少數據存儲空間等,分別是:
① 使用SharedPreferences存儲數據
② 文件存儲數據
③ SQLite數據庫存儲數據
④ 使用ContentProvider存儲數據
⑤ 網絡存儲數據
Android提供了一種方式來暴露你的數據(甚至是私有數據)給其他應用程序 - ContentProvider。它是一個可選組件,可公開讀寫你應用程序數據。
2、SharedPreferences存儲
SharedPreference類提供了一個總體框架,使您可以保存和檢索的任何基本數據類型( boolean, float, int, long, string)的持久鍵-值對(基於XML文件存儲的“key-value”鍵值對數據)。
通常用來存儲程序的一些配置信息。其存儲在“data/data/程序包名/shared_prefs目錄下。
xml 處理時Dalvik會通過自帶底層的本地XML Parser解析,比如XMLpull方式,這樣對於內存資源占用比較好。
2.1 我們可以通過以下兩種方法獲取SharedPreferences對象(通過Context):
① getSharedPreferences (String name, int mode)
當我們有多個SharedPreferences的時候,根據第一個參數name獲得相應的SharedPreferences對象。
② getPreferences (int mode)
如果你的Activity中只需要一個SharedPreferences的時候使用。
這里的mode有四個選項:
Context.MODE_PRIVATE
該SharedPreferences數據只能被本應用程序讀、寫。
Context.MODE_WORLD_READABLE
該SharedPreferences數據能被其他應用程序讀,但不能寫。
Context.MODE_WORLD_WRITEABLE
該SharedPreferences數據能被其他應用程序讀和寫。
Context.MODE_MULTI_PROCESS
sdk2.3后添加的選項,當多個進程同時讀寫同一個SharedPreferences時它會檢查文件是否修改。
2.2 向Shared Preferences中寫入值
首先要通過 SharedPreferences.Editor獲取到Editor對象;
然后通過Editor的putBoolean() 或 putString()等方法存入值;
最后調用Editor的commit()方法提交;
//Use 0 or MODE_PRIVATE for the default operation SharedPreferences settings = getSharedPreferences("fanrunqi", 0); SharedPreferences.Editor editor = settings.edit(); editor.putBoolean("isAmazing", true); // 提交本次編輯 editor.commit();
同時Edit還有兩個常用的方法:
editor.remove(String key) :下一次commit的時候會移除key對應的鍵值對
editor.clear():移除所有鍵值對
2.3 從Shared Preferences中讀取值
讀取值使用 SharedPreference對象的getBoolean()或getString()等方法就行了(沒Editor 啥子事)。
SharedPreferences settings = getSharedPreferences("fanrunqi", 0); boolean isAmazing= settings.getBoolean("isAmazing",true);
2.4 Shared Preferences的優缺點
可以看出來Preferences是很輕量級的應用,使用起來也很方便,簡潔。但存儲數據類型比較單一(只有基本數據類型),無法進行條件查詢,只能在不復雜的存儲需求下使用,比如保存配置信息等。
3、文件數據存儲
3.1 使用內部存儲
當文件被保存在內部存儲中時,默認情況下,文件是應用程序私有的,其他應用不能訪問。當用戶卸載應用程序時這些文件也跟着被刪除。
文件默認存儲位置:/data/data/包名/files/文件名。
3.1.1 創建和寫入一個內部存儲的私有文件:
① 調用Context的openFileOutput()函數,填入文件名和操作模式,它會返回一個FileOutputStream對象。
② 通過FileOutputStream對象的write()函數寫入數據。
③ FileOutputStream對象的close ()函數關閉流。
例如:
String FILENAME = "a.txt"; String string = "fanrunqi"; try { FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE); fos.write(string.getBytes()); fos.close(); } catch (Exception e) { e.printStackTrace(); }
在 openFileOutput(String name, int mode)方法中
-
name參數: 用於指定文件名稱,不能包含路徑分隔符“/” ,如果文件不存在,Android 會自動創建它。
-
mode參數:用於指定操作模式,分為四種:
Context.MODE_PRIVATE = 0
為默認操作模式,代表該文件是私有數據,只能被應用本身訪問,在該模式下,寫入的內容會覆蓋原文件的內容。
Context.MODE_APPEND = 32768
該模式會檢查文件是否存在,存在就往文件追加內容,否則就創建新文件。
Context.MODE_WORLD_READABLE = 1
表示當前文件可以被其他應用讀取。
MODE_WORLD_WRITEABLE
表示當前文件可以被其他應用寫入。
3.1.2 讀取一個內部存儲的私有文件:
① 調用openFileInput( ),參數中填入文件名,會返回一個FileInputStream對象。
② 使用流對象的 read()方法讀取字節
③ 調用流的close()方法關閉流
例如:
String FILENAME = "a.txt"; try { FileInputStream inStream = openFileInput(FILENAME); int len = 0; byte[] buf = new byte[1024]; StringBuilder sb = new StringBuilder(); while ((len = inStream.read(buf)) != -1) { sb.append(new String(buf, 0, len)); } inStream.close(); } catch (Exception e) { e.printStackTrace(); }
其他一些經常用到的方法:
-
getFilesDir(): 得到內存儲文件的絕對路徑
-
getDir(): 在內存儲空間中創建或打開一個已經存在的目錄
-
deleteFile(): 刪除保存在內部存儲的文件。
-
fileList(): 返回當前由應用程序保存的文件的數組(內存儲目錄下的全部文件)。
3.1.3 保存編譯時的靜態文件
如果你想在應用編譯時保存靜態文件,應該把文件保存在項目的 res/raw/ 目錄下,你可以通過 openRawResource()方法去打開它(傳入參數R.raw.filename),這個方法返回一個 InputStream流對象你可以讀取文件但是不能修改原始文件。
InputStream is = this.getResources().openRawResource(R.raw.filename);
3.1.4 保存內存緩存文件
有時候我們只想緩存一些數據而不是持久化保存,可以使用getCacheDir()去打開一個文件,文件的存儲目錄( /data/data/包名/cache )是一個應用專門來保存臨時緩存文件的內存目錄。
當設備的內部存儲空間比較低的時候,Android可能會刪除這些緩存文件來恢復空間,但是你不應該依賴系統來回收,要自己維護這些緩存文件把它們的大小限制在一個合理的范圍內,比如1MB.當你卸載應用的時候這些緩存文件也會被移除
3.2 使用外部存儲(sdcard)
因為內部存儲容量限制,有時候需要存儲數據比較大的時候需要用到外部存儲,使用外部存儲分為以下幾個步驟:
3.2.1 添加外部存儲訪問限權
首先,要在AndroidManifest.xml中加入訪問SDCard的權限,如下:
<!-- 在SDCard中創建與刪除文件權限 --> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> <!-- 往SDCard寫入數據權限 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
3.2.2 檢測外部存儲的可用性
在使用外部存儲時我們需要檢測其狀態,它可能被連接到計算機、丟失或者只讀等。下面代碼將說明如何檢查狀態:
//獲取外存儲的狀態 String state = Environment.getExternalStorageState(); if (Environment.MEDIA_MOUNTED.equals(state)) { // 可讀可寫 mExternalStorageAvailable = mExternalStorageWriteable = true; } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { // 可讀 } else { // 可能有很多其他的狀態,但是我們只需要知道,不能讀也不能寫 }
3.2.3 訪問外部存儲器中的文件
1、如果 API 版本大於或等於8,使用
getExternalFilesDir (String type)
該方法打開一個外存儲目錄,此方法需要一個類型,指定你想要的子目錄,如類型參數DIRECTORY_MUSIC和 DIRECTORY_RINGTONES(傳null就是你應用程序的文件目錄的根目錄)。通過指定目錄的類型,確保Android的媒體掃描儀將掃描分類系統中的文件(例如,鈴聲被確定為鈴聲)。如果用戶卸載應用程序,這個目錄及其所有內容將被刪除。
例如:
File file = new File(getExternalFilesDir(null), "fanrunqi.jpg");
2、如果API 版本小於 8 (7或者更低)
getExternalStorageDirectory ()
通過該方法打開外存儲的根目錄,你應該在以下目錄下寫入你的應用數據,這樣當卸載應用程序時該目錄及其所有內容也將被刪除
/Android/data/<package_name>/files/
讀寫數據:
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ File sdCardDir = Environment.getExternalStorageDirectory();//獲取SDCard目錄 "/sdcard" File saveFile = new File(sdCardDir,"a.txt"); //寫數據 try { FileOutputStream fos= new FileOutputStream(saveFile); fos.write("fanrunqi".getBytes()); fos.close(); } catch (Exception e) { e.printStackTrace(); } //讀數據 try { FileInputStream fis= new FileInputStream(saveFile); int len =0; byte[] buf = new byte[1024]; StringBuffer sb = new StringBuffer(); while((len=fis.read(buf))!=-1){ sb.append(new String(buf, 0, len)); } fis.close(); } catch (Exception e) { e.printStackTrace(); } }
我們也可以在 /Android/data/package_name/cache/目錄下做外部緩存。
4、 網絡存儲數據
HttpUrlConnection
HttpUrlConnection是Java.NET包中提供的API,我們知道Android SDK是基於Java的,所以當然優先考慮HttpUrlConnection這種最原始最基本的API,其實大多數開源的聯網框架基本上也是基於JDK的HttpUrlConnection進行的封裝罷了,掌握HttpUrlConnection需要以下幾個步驟:
1、將訪問的路徑轉換成URL。
URL url = new URL(path);
2、通過URL獲取連接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
3、設置請求方式。
conn.setRequestMethod(GET);
4、設置連接超時時間。
conn.setConnectTimeout(5000);
5、設置請求頭的信息。
conn.setRequestProperty(User-Agent, Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0));
7、針對不同的響應碼,做不同的操作(請求碼200,表明請求成功,獲取返回內容的輸入流)
工具類:
public class StreamTools { /** * 將輸入流轉換成字符串 * * @param is * 從網絡獲取的輸入流 * @return */ public static String streamToString(InputStream is) { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = 0; while ((len = is.read(buffer)) != -1) { baos.write(buffer, 0, len); } baos.close(); is.close(); byte[] byteArray = baos.toByteArray(); return new String(byteArray); } catch (Exception e) { Log.e(tag, e.toString()); return null; } } }
HttpUrlConnection發送GET請求
public static String loginByGet(String username, String password) { String path = http://192.168.0.107:8080/WebTest/LoginServerlet?username= + username + &password= + password; try { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(5000); conn.setRequestMethod(GET); int code = conn.getResponseCode(); if (code == 200) { InputStream is = conn.getInputStream(); // 字節流轉換成字符串 return StreamTools.streamToString(is); } else { return 網絡訪問失敗; } } catch (Exception e) { e.printStackTrace(); return 網絡訪問失敗; } }
HttpUrlConnection發送POST請求
public static String loginByPost(String username, String password) { String path = http://192.168.0.107:8080/WebTest/LoginServerlet; try { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(5000); conn.setRequestMethod(POST); conn.setRequestProperty(Content-Type, application/x-www-form-urlencoded); String data = username= + username + &password= + password; conn.setRequestProperty(Content-Length, data.length() + ); // POST方式,其實就是瀏覽器把數據寫給服務器 conn.setDoOutput(true); // 設置可輸出流 OutputStream os = conn.getOutputStream(); // 獲取輸出流 os.write(data.getBytes()); // 將數據寫給服務器 int code = conn.getResponseCode(); if (code == 200) { InputStream is = conn.getInputStream(); return StreamTools.streamToString(is); } else { return 網絡訪問失敗; } } catch (Exception e) { e.printStackTrace(); return 網絡訪問失敗; } }
HttpClient
HttpClient是開源組織Apache提供的Java請求網絡框架,其最早是為了方便Java服務器開發而誕生的,是對JDK中的HttpUrlConnection各API進行了封裝和簡化,提高了性能並且降低了調用API的繁瑣,Android因此也引進了這個聯網框架,我們再不需要導入任何jar或者類庫就可以直接使用,值得注意的是Android官方已經宣布不建議使用HttpClient了。
HttpClient發送GET請求
1、 創建HttpClient對象
2、創建HttpGet對象,指定請求地址(帶參數)
3、使用HttpClient的execute(),方法執行HttpGet請求,得到HttpResponse對象
4、調用HttpResponse的getStatusLine().getStatusCode()方法得到響應碼
5、調用的HttpResponse的getEntity().getContent()得到輸入流,獲取服務端寫回的數據
public static String loginByHttpClientGet(String username, String password) { String path = http://192.168.0.107:8080/WebTest/LoginServerlet?username= + username + &password= + password; HttpClient client = new DefaultHttpClient(); // 開啟網絡訪問客戶端 HttpGet httpGet = new HttpGet(path); // 包裝一個GET請求 try { HttpResponse response = client.execute(httpGet); // 客戶端執行請求 int code = response.getStatusLine().getStatusCode(); // 獲取響應碼 if (code == 200) { InputStream is = response.getEntity().getContent(); // 獲取實體內容 String result = StreamTools.streamToString(is); // 字節流轉字符串 return result; } else { return 網絡訪問失敗; } } catch (Exception e) { e.printStackTrace(); return 網絡訪問失敗; } }
HttpClient發送POST請求
1,創建HttpClient對象
2,創建HttpPost對象,指定請求地址
3,創建List,用來裝載參數
4,調用HttpPost對象的setEntity()方法,裝入一個UrlEncodedFormEntity對象,攜帶之前封裝好的參數
5,使用HttpClient的execute()方法執行HttpPost請求,得到HttpResponse對象
6, 調用HttpResponse的getStatusLine().getStatusCode()方法得到響應碼
7, 調用的HttpResponse的getEntity().getContent()得到輸入流,獲取服務端寫回的數據
public static String loginByHttpClientPOST(String username, String password) { String path = http://192.168.0.107:8080/WebTest/LoginServerlet; try { HttpClient client = new DefaultHttpClient(); // 建立一個客戶端 HttpPost httpPost = new HttpPost(path); // 包裝POST請求 // 設置發送的實體參數 List parameters = new ArrayList(); parameters.add(new BasicNameValuePair(username, username)); parameters.add(new BasicNameValuePair(password, password)); httpPost.setEntity(new UrlEncodedFormEntity(parameters, UTF-8)); HttpResponse response = client.execute(httpPost); // 執行POST請求 int code = response.getStatusLine().getStatusCode(); if (code == 200) { InputStream is = response.getEntity().getContent(); String result = StreamTools.streamToString(is); return result; } else { return 網絡訪問失敗; } } catch (Exception e) { e.printStackTrace(); return 訪問網絡失敗; } }
參考:
Android提供的其他網絡訪問框架
HttpClient和HttpUrlConnection的兩種網絡訪問方式編寫網絡代碼,需要自己考慮很多,獲取數據或許可以,但是如果要將手機本地數據上傳至網絡,根據不同的web端接口,需要組織不同的數據內容上傳,給手機端造成了很大的工作量。
目前有幾種快捷的網絡開發開源框架,給我們提供了非常大的便利。下面是這些項目Github地址,有文檔和Api說明。
android-async-http
5、 SQLite數據庫存儲數據
Assets保存:用來存儲一些只讀數據,Assets是指那些在assets目錄下的文件,這些文件在你將你的應用編譯打包之前就要存在,並且可以在應用程序運行的時候被訪問到。
但有時候我們需要對保存的數據進行一些復雜的操作,或者數據量很大,超出了文本文件和Preference的性能能的范圍,所以需要一些更加高效的方法來管理,從Android1.5開始,Android就自帶SQLite數據庫了。
SQLite它是一個獨立的,無需服務進程,支持事務處理,可以使用SQL語言的數據庫。
SQLite的特性
1、 ACID事務
ACID: 指數據庫事務正確執行的四個基本要素的縮寫。包含:原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、持久性(Durability)。
一個支持事務(Transaction)的數據庫,必需要具有這四種特性,否則在事務過程(Transaction processing)當中無法保證數據的正確性,交易過程極可能達不到交易方的要求。
2、 零配置 – 無需安裝和管理配置
3、儲存在單一磁盤文件中的一個完整的數據庫
4、數據庫文件可以在不同字節順序的機器間自由的共享
5、支持數據庫大小至2TB
6、 足夠小, 大致3萬行C代碼, 250K
7、比一些流行的數據庫在大部分普通數據庫操作要快
8、簡單, 輕松的API
9、 包含TCL綁定, 同時通過Wrapper支持其他語言的綁定
http://www.sqlite.org/tclsqlite.html
10、良好注釋的源代碼, 並且有着90%以上的測試覆蓋率
11、 獨立: 沒有額外依賴
12、 Source完全的Open, 你可以用於任何用途, 包括出售它
13、支持多種開發語言,C,PHP,Perl,Java,ASP.NET,Python
Android 中使用 SQLite
Activites 可以通過 Content Provider 或者 Service 訪問一個數據庫。
創建數據庫
Android 不自動提供數據庫。在 Android 應用程序中使用 SQLite,必須自己創建數據庫,然后創建表、索引,填充數據。Android 提供了 SQLiteOpenHelper 幫助你創建一個數據庫,你只要繼承 SQLiteOpenHelper 類根據開發應用程序的需要,封裝創建和更新數據庫使用的邏輯就行了。
SQLiteOpenHelper 的子類,至少需要實現三個方法:
public class DatabaseHelper extends SQLiteOpenHelper { /** * @param context 上下文環境(例如,一個 Activity) * @param name 數據庫名字 * @param factory 一個可選的游標工廠(通常是 Null) * @param version 數據庫模型版本的整數 * * 會調用父類 SQLiteOpenHelper的構造函數 */ public DatabaseHelper(Context context, String name, CursorFactory factory, int version) { super(context, name, factory, version); } /** * 在數據庫第一次創建的時候會調用這個方法 * *根據需要對傳入的SQLiteDatabase 對象填充表和初始化數據。 */ @Override public void onCreate(SQLiteDatabase db) { } /** * 當數據庫需要修改的時候(兩個數據庫版本不同),Android系統會主動的調用這個方法。 * 一般我們在這個方法里邊刪除數據庫表,並建立新的數據庫表. */ @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { //三個參數,一個 SQLiteDatabase 對象,一個舊的版本號和一個新的版本號 } @Override public void onOpen(SQLiteDatabase db) { // 每次成功打開數據庫后首先被執行 super.onOpen(db); } }
繼承SQLiteOpenHelper之后就擁有了以下兩個方法:
-
getReadableDatabase() 創建或者打開一個查詢數據庫
-
getWritableDatabase() 創建或者打開一個可寫數據庫
DatabaseHelper database = new DatabaseHelper(context);//傳入一個上下文參數 SQLiteDatabase db = null; db = database.getWritableDatabase();
上面這段代碼會返回一個 SQLiteDatabase 類的實例,使用這個對象,你就可以查詢或者修改數據庫。
SQLiteDatabase類為我們提供了很多種方法,而較常用的方法如下:
(int) delete(String table,String whereClause,String[] whereArgs)
刪除數據行
(long) insert(String table,String nullColumnHack,ContentValues values)
添加數據行
(int) update(String table, ContentValues values, String whereClause, String[] whereArgs)
更新數據行
(void) execSQL(String sql)
執行一個SQL語句,可以是一個select或其他的sql語句
(void) close()
關閉數據庫
(Cursor) query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit)
查詢指定的數據表返回一個帶游標的數據集。
各參數說明:
table:表名稱
colums:列名稱數組
selection:條件子句,相當於where
selectionArgs:條件語句的參數數組
groupBy:分組
having:分組條件
orderBy:排序類
limit:分頁查詢的限制
Cursor:返回值,相當於結果集ResultSet
(Cursor) rawQuery(String sql, String[] selectionArgs)
運行一個預置的SQL語句,返回帶游標的數據集(與上面的語句最大的區別就是防止SQL注入)
當你完成了對數據庫的操作(例如你的 Activity 已經關閉),需要調用 SQLiteDatabase 的 Close() 方法來釋放掉數據庫連接。
創建表和索引
為了創建表和索引,需要調用 SQLiteDatabase 的 execSQL() 方法來執行 DDL 語句。如果沒有異常,這個方法沒有返回值。
例如,你可以執行如下代碼:
db.execSQL("CREATE TABLE user(_id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT, password TEXT);");
這條語句會創建一個名為 user的表,表有一個列名為 _id,並且是主鍵,這列的值是會自動增長的整數。另外還有兩列:username( 字符 ) 和 password( 字符 )。 SQLite 會自動為主鍵列創建索引。
通常情況下,第一次創建數據庫時創建了表和索引。要 刪除表和索引,需要使用 execSQL() 方法調用 DROP INDEX 和 DROP TABLE 語句。
添加數據
有兩種方法可以給表添加數據。
①可以使用 execSQL() 方法執行 INSERT, UPDATE, DELETE 等語句來更新表的數據。execSQL() 方法適用於所有不返回結果的 SQL 語句。例如:
String sql = "insert into user(username,password) values ('finch','123456');//插入操作的SQL語句 db.execSQL(sql);//執行SQL語句
②使用 SQLiteDatabase 對象的 insert()。
ContentValues cv = new ContentValues(); cv.put("username","finch");//添加用戶名 cv.put("password","123456"); //添加密碼 db.insert("user",null,cv);//執行插入操作
更新數據(修改)
①使用SQLiteDatabase 對象的 update()方法。
ContentValues cv = new ContentValues(); cv.put("password","654321");//添加要更改的字段及內容 String whereClause = "username=?";//修改條件 String[] whereArgs = {"finch"};//修改條件的參數 db.update("user",cv,whereClause,whereArgs);//執行修改
該方法有四個參數:
表名;
列名和值的 ContentValues 對象;
可選的 WHERE 條件;
可選的填充 WHERE 語句的字符串,這些字符串會替換 WHERE 條件中的“?”標記,update() 根據條件,更新指定列的值.
②使用execSQL方式的實現
String sql = "update [user] set password = '654321' where username="finch";//修改的SQL語句 db.execSQL(sql);//執行修改
刪除數據
①使用SQLiteDatabase 對象的delete()方法。
String whereClause = "username=?";//刪除的條件 String[] whereArgs = {"finch"};//刪除的條件參數 db.delete("user",whereClause,whereArgs);//執行刪除
②使用execSQL方式的實現
String sql = "delete from user where username="finch";//刪除操作的SQL語句 db.execSQL(sql);//執行刪除操作
查詢數據
①使用 rawQuery() 直接調用 SELECT 語句
Cursor c = db.rawQuery("select * from user where username=?",new Stirng[]{"finch"}); if(cursor.moveToFirst()) { String password = c.getString(c.getColumnIndex("password")); }
返回值是一個 cursor 對象,這個對象的方法可以迭代查詢結果。
如果查詢是動態的,使用這個方法就會非常復雜。例如,當你需要查詢的列在程序編譯的時候不能確定,這時候使用 query() 方法會方便很多。
②通過query實現查詢
query() 方法用 SELECT 語句段構建查詢。
SELECT 語句內容作為 query() 方法的參數,比如:要查詢的表名,要獲取的字段名,WHERE 條件,包含可選的位置參數,去替代 WHERE 條件中位置參數的值,GROUP BY 條件,HAVING 條件。
除了表名,其他參數可以是 null。所以代碼可寫成:
Cursor c = db.query("user",null,null,null,null,null,null);//查詢並獲得游標 if(c.moveToFirst()){//判斷游標是否為空 for(int i=0;i<c.getCount();i++){ c.move(i);//移動到指定記錄 String username = c.getString(c.getColumnIndex("username"); String password = c.getString(c.getColumnIndex("password")); } }
使用游標
不管你如何執行查詢,都會返回一個 Cursor,這是 Android 的 SQLite 數據庫游標,使用游標,你可以:
-
通過使用 getCount() 方法得到結果集中有多少記錄;
-
通過 moveToFirst(), moveToNext(), 和 isAfterLast() 方法遍歷所有記錄;
-
通過 getColumnNames() 得到字段名;
-
通過 getColumnIndex() 轉換成字段號;
-
通過 getString(),getInt() 等方法得到給定字段當前記錄的值;
-
通過 requery() 方法重新執行查詢得到游標;
-
通過 close() 方法釋放游標資源;
例如,下面代碼遍歷 user表:
Cursor result=db.rawQuery("SELECT _id, username, password FROM user"); result.moveToFirst(); while (!result.isAfterLast()) { int id=result.getInt(0); String name=result.getString(1); String password =result.getString(2); // do something useful with these result.moveToNext(); } result.close();