Android爲我們提供了4種數據存儲方式,但由於存儲的這些數據都是某個應用程序私有的,所以它又爲我們提供了一種在不同應用程序之間共享數據的機制,即ContentProvider。
下面我們首先將分別介紹Android的4種數據存儲方式:Shared Preferences、Files、SQLite、NetWork,最後我們將詳細介紹Android的Content Provider機制。
一、Android數據存儲之SharedProviences
它是Android提供的用來存儲一些簡單配置信息的一種機制,例如:登錄用戶的用戶名與密碼。其採用了Map數據結構來存儲數據,以鍵值對的方式存儲,可以簡單的讀取與寫入,具體實例如下:
//讀取SharedPreference
void readSharedPreferences()
{
String strName,strPassword;
SharedPreferences user = getSharedPreferences(“user_info”,0);
strName = user.getString(“NAME”,””);
strPassword = user getString(“PASSWORD”,””);
}
//往SharedPreference中寫入內容
void writeSharedPreferences(String strName,String strPassword)
{
SharedPreferences user = getSharedPreferences(“user_info”,0);
//使其處於編輯狀態
uer.edit();
user.putString(“NAME”, strName);
user.putString(“PASSWORD” ,strPassword);
user.commit();
}
數據讀取與寫入的方法都非常簡單,只是在寫入的時候有些區別:先調用edit()使其處於編輯狀態,然後才能修改數據,最後使用commit()提交修改的數據。實際上SharedPreferences是採用了XML格式將數據存儲到設備中,在DDMS中的File Explorer中的/data/data/<package name>/shares_prefs下。以上面的數據存儲結果爲例,打開後可以看到一個user_info.xml的文件,打開後可以看到:<?xml version=”1.0″ encoding=”UTF-8″?>
<map>
<string name=”NAME”>moandroid</string>
<string name=” PASSWORD”>SharedPreferences</string>
</map>
使用SharedPreferences是有些限制的:只能在同一個包內使用,不能在不同的包之間使用二、Android數據存儲之Files(文件)
文件方式是一種較常用的存儲方法,在Android中讀/寫文件的方法,與Java中實現I/O的程序是完全一樣的,Android爲我們提供了openFileInput()和openFileOutput()方法來讀取設備上的文件。具體示例如下:
//讀文件
private void read() {
try {
FileInputStream inputStream = this.openFileInput("music.cfg");
byte[] bytes = new byte[1024];
ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
while (inputStream.read(bytes) != -1) {
arrayOutputStream.write(bytes, 0, bytes.length);
}
inputStream.close();
arrayOutputStream.close();
mbMusic = Boolean.getBoolean(new String(arrayOutputStream.toByteArray()));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//寫文件
private void writeFile() {
try {
/** 根據用戶提供的文件名,以及文件的應用模式,打開一個輸出流
* openFileOutput(String name, int mode);
* 第一個參數,代表文件名稱,注意這裏的文件名稱不能包括任何的/或者/這種分隔符,只能是文件名
* 該文件會被保存在/data/data/應用名稱/files/music.cfg
* 第二個參數,代表文件的操作模式
* MODE_PRIVATE 私有(只能創建它的應用訪問) 重複寫入時會文件覆蓋
* MODE_APPEND 私有 重複寫入時會在文件的末尾進行追加,而不是覆蓋掉原來的文件
* MODE_WORLD_READABLE 公用 可讀
* MODE_WORLD_WRITEABLE 公用 可讀寫
*
*/
FileOutputStream outputStream = openFileOutput("music.cfg",
Activity.MODE_PRIVATE);
outputStream.write(String.valueOf(mbMusic).getBytes());
outputStream.flush();
outputStream.close();
Toast.makeText(FilesTest.this, "保存成功", Toast.LENGTH_LONG).show();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
如果在開發一個應用時,需要通過加載一個文件的內容來初始化程序,就可以在編譯程序之前,在/res/raw/tempFile中建立一個文件,然後直接讀取內容(具體方法參見本人另一片文章:Android各種資源詳解 )。對於sd卡上的文件讀寫,可以File file = new File("/sdcard/");然後遍歷sdcard目錄,對其中文件進行相關操作,具體方法不再贅述。
三、 Android數據存儲之NetWork
通過網絡方式來獲取和保存數據資源,需要設備保持聯網狀態。將數據存儲到網絡的方法很多,如:將要保存的數據以文件方式上傳到文件服務器、發送電子郵件等等。
也可以將網絡上的資源獲取到本地。下面的例子是一個將網絡上的文件獲取到本地並顯示。
try{
URL uri = new URL("http://192.168.2.22:8080/test.txt");
URLConnection con = uri.openConnection();
InputStream is = con.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
ByteArrayBuffer baf = new ByteArrayBuffer(100);
int current = 0;
while ((current = bis.read()) != -1){
baf.append((byte)current);
}
text = new String(baf.toByteArray());
}catch (Exception e){
text = e.getMessage();
}
textView.setText(text);
再來看看如何訪問web網頁,代碼如下:public class WebViewTest extends Activity {
private WebView webView;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
WebView wView = (WebView)findViewById(R.id.webview);
WebSettings wSet = wView.getSettings();
wSet.setJavaScriptEnabled(true);
//解決亂碼問題
wSet.setDefaultTextEncodingName("utf-8");
//打開本包內asset目錄下的index.html文件
wView.loadUrl("file:///android_asset/index.html");
//打開本地sd卡內的index.html文件
//wView.loadUrl("content://com.android.htmlfileprovider/sdcard/index.html");
//打開指定url的html文件
//wView.loadUrl("http://wap.baidu.com");
}
}
佈局文件如下:<?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="@string/hello"
/>
<WebView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:id="@+id/webview"
/>
</LinearLayout>
在/assets/目錄下建一文件名爲:index.html<html>
<head>
<title><h3>my first web page</h3></title>
</head>
<body>
<form method="post">
<table>
<tr>
<td>用戶名:</td>
<td><input type="text"></td>
</tr>
<tr>
<td>密碼:</td>
<td><input type="password"></td>
</tr>
<tr>
<td><input type="button" value="重置" οnclick="alert('確認重置嗎?');"></td>
<td><input type="button" value="登錄" οnclick="alert('確認登錄嗎?');"></td>
</tr>
</form>
</body>
</html>
運行項目結果如圖所示:在Android訪問網絡時要注意:
(2)、若使用Android模擬器訪問本地機器,不能用localhost或者127.0.0.1,而要用10.0.2.2,不然會連接不上,這是因爲android模擬器(simulator)把它自己作爲了localhost,也就是說,代碼中使用localhost或者127.0.0.1來訪問,都是訪問模擬器自己;如果你想在模擬器上面訪問你的電腦,那麼就使用android內置的IP10.0.2.2吧。
四、Android數據存儲之SQLite
SQLite,是一款輕型的數據庫,是遵守ACID的關聯式數據庫管理系統,它的設計目標是嵌入式的,而且目前已經在很多嵌入式產品中使用了它,它佔用資源非常的低,在嵌入式設備中,可能只需要幾百K的內存就夠了。它能夠支持Windows/Linux/Unix等等主流的操作系統,同時能夠跟很多程序語言相結合,比如 Tcl、C#、PHP、Java等,還有ODBC接口,同樣比起Mysql、PostgreSQL這兩款開源世界著名的數據庫管理系統來講,它的處理速度比他們都快。
下面試一個例子,通過它我們來看看有關SQLite數據庫的CRUD等操作。
佈局文件main.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"
>
<ListView
android:id="@+id/listView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
佈局文件:listitem.xml<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/linearlayout"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:id="@+id/ItemTitle"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<TextView
android:id="@+id/ItemText"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
Java類:public class SqlLiteTest extends Activity {
private ListView listView;
//記錄條數
private static int count = 0;
//數據庫對象
private SQLiteDatabase sqliteDatabase;
private final static String DATABASE_NAME = "sql.db";
private final static String TABLE_NAME = "t_student";
private final static String ID = "_id";
private final static String NUM = "num";
private final static String DATA = "data";
//建表語句
private final static String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME
+ "(" + ID + " INTEGER PRIMARY KEY,"
+ NUM + " INTEGER," + DATA + " TEXT)";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
listView = (ListView)findViewById(R.id.listView);
//打開數據庫
sqliteDatabase = this.openOrCreateDatabase(DATABASE_NAME, MODE_PRIVATE, null);
deleteTable();
//創建表
sqliteDatabase.execSQL(CREATE_TABLE);
//更新ListView
updateAdapter();
}
//按鍵監聽
public boolean onKeyUp(int keyCode,KeyEvent evnet){
switch (keyCode){
case KeyEvent.KEYCODE_DPAD_UP:
addData();
break;
case KeyEvent.KEYCODE_DPAD_DOWN:
delete();
break;
case KeyEvent.KEYCODE_DPAD_LEFT:
updateData();
break;
case KeyEvent.KEYCODE_DPAD_RIGHT:
deleteTable();
break;
case KeyEvent.KEYCODE_DPAD_CENTER:
deleteDataBase();
break;
}
return true;
}
//更新listView視圖
private void updateAdapter(){
Cursor cursor = sqliteDatabase.query(TABLE_NAME, new String[]{ID,NUM,DATA}, null, null, null, null, null);
count = cursor.getCount();
if (null != cursor && count >= 0){
//ListAdapter 是ListView 和數據的橋樑
ListAdapter adapter = new SimpleCursorAdapter(this, R.layout.listitem, cursor, new String[]{NUM,DATA}, new int[]{R.id.ItemTitle,R.id.ItemText});
//將adapter添加到listView中
listView.setAdapter(adapter);
}
}
//插入數據
private void addData(){
//要更新的數據
ContentValues contentValue = new ContentValues();
contentValue.put(NUM, count);
contentValue.put(DATA,"測試數據庫數據:" + count);
//插入數據
sqliteDatabase.insert(TABLE_NAME, null, contentValue);
count++;
updateAdapter();
}
//刪除數據庫
private void deleteDataBase(){
this.deleteDatabase(DATABASE_NAME);
this.finish();
}
//刪除表
private void deleteTable(){
sqliteDatabase.execSQL("drop table if exists " + "sql." + TABLE_NAME);
//this.finish();
}
//更新一條數據
private void updateData(){
//要更新的數據
ContentValues contentValue = new ContentValues();
contentValue.put(NUM, count);
contentValue.put(DATA,"修改後的數據:" + count);
//執行更改
sqliteDatabase.update(TABLE_NAME, contentValue, NUM + "=" + Integer.toString(count - 1), null);
//更新ListView數據
updateAdapter();
}
//刪除指定的數據
private void delete(){
sqliteDatabase.execSQL("delete from " + TABLE_NAME + " where _id = " + Integer.toString(count));
count--;
if (count < 0){
count = 0;
}
updateAdapter();
}
}
運行,按上下左右鍵分別進行,增加,刪除,修改以及刪除數據庫操作。結果如下圖所示: