一、使用SharedPreferences存儲(chǔ)數(shù)據(jù)
默認(rèn)存儲(chǔ)路徑:/data/data/<PackageName>/shared_prefs
SharedPreferences是一個(gè)較輕量級(jí)的存儲(chǔ)數(shù)據(jù)的方法,適用范圍:保存少量的數(shù)據(jù),且這些數(shù)據(jù)的格式非常簡(jiǎn)單:字符串型、基本類型的值。
核心原理:保存基于XML文件存儲(chǔ)的key-value鍵值對(duì)數(shù)據(jù),通常用來(lái)存儲(chǔ)一些簡(jiǎn)單的配置信息。通過(guò)DDMS的File Explorer面板,展開(kāi)文件瀏覽樹(shù),很明顯SharedPreferences數(shù)據(jù)總是存儲(chǔ)在/data/data/<package name>/shared_prefs目錄下。SharedPreferences對(duì)象本身只能獲取數(shù)據(jù)而不支持存儲(chǔ)和修改,存儲(chǔ)修改是通過(guò)SharedPreferences.edit()獲取的內(nèi)部接口Editor對(duì)象實(shí)現(xiàn)。 SharedPreferences本身是一 個(gè)接口,程序無(wú)法直接創(chuàng)建SharedPreferences實(shí)例,只能通過(guò)Context提供的getSharedPreferences(String name, int mode)方法來(lái)獲取SharedPreferences實(shí)例,
該方法中name表示要操作的xml文件名,第二個(gè)參數(shù)為設(shè)置讀寫模式,有以下三種選擇:
- Context.MODE_PRIVATE: 指定該SharedPreferences數(shù)據(jù)只能被本應(yīng)用程序讀、寫。
- Context.MODE_WORLD_READABLE: 指定該SharedPreferences數(shù)據(jù)能被其他應(yīng)用程序讀,但不能寫。
- Context.MODE_WORLD_WRITEABLE: 指定該SharedPreferences數(shù)據(jù)能被其他應(yīng)用程序讀,寫。
而編輯接口Editor有如下主要重要方法:
SharedPreferences.Editor clear():清空SharedPreferences里所有數(shù)據(jù)
** SharedPreferences.Editor putXxx(String key , xxx value):** 向SharedPreferences存入指定key對(duì)應(yīng)的數(shù)據(jù),其中xxx 可以是boolean,float,int等各種基本類型據(jù)
** SharedPreferences.Editor remove()**: 刪除SharedPreferences中指定key對(duì)應(yīng)的數(shù)據(jù)項(xiàng)
** boolean commit()**: 當(dāng)Editor編輯完成后,使用該方法提交修改
讀寫其他應(yīng)用的SharedPreferences: 步驟如下
在創(chuàng)建SharedPreferences時(shí),指定MODE_WORLD_READABLE模式,表明該SharedPreferences數(shù)據(jù)可以被其他程序讀取
-
創(chuàng)建其他應(yīng)用程序?qū)?yīng)的Context:
Context pvCount = createPackageContext("com.tony.app",
Context.CONTEXT_IGNORE_SECURITY);這里的com.tony.app就是其他程序的包名 -
使用其他程序的Context獲取對(duì)應(yīng)的SharedPreferences
SharedPreferences read = pvCount.getSharedPreferences("lock",
Context.MODE_WORLD_READABLE); 如果是寫入數(shù)據(jù),使用Editor接口即可,所有其他操作均和前面一致。
SharedPreferences對(duì)象與SQLite數(shù)據(jù)庫(kù)相比,免去了創(chuàng)建數(shù)據(jù)庫(kù),創(chuàng)建表,寫SQL語(yǔ)句等諸多操作,相對(duì)而言更加方便,簡(jiǎn)潔。但是SharedPreferences也有其自身缺陷,比如其職能存儲(chǔ)boolean,int,float,long和String五種簡(jiǎn)單的數(shù)據(jù)類型,比如其無(wú)法進(jìn)行條件查詢等。所以不論SharedPreferences的數(shù)據(jù)存儲(chǔ)操作是如何簡(jiǎn)單,它也只能是存儲(chǔ)方式的一種補(bǔ)充,而無(wú)法完全替代如SQLite數(shù)據(jù)庫(kù)這樣的其他數(shù)據(jù)存儲(chǔ)方式。另外需要注意的一點(diǎn)是sharePreference在多進(jìn)程的情況下會(huì)失效。
二、SQLite數(shù)據(jù)庫(kù)存儲(chǔ)數(shù)據(jù)
默認(rèn)存儲(chǔ)路徑:/data/data/<PackageName>/databases
SQLite是輕量級(jí)嵌入式數(shù)據(jù)庫(kù)引擎,它支持 SQL 語(yǔ)言,并且只利用很少的內(nèi)存就有很好的性能。現(xiàn)在的主流移動(dòng)設(shè)備像Android、iPhone等都使用SQLite作為復(fù)雜數(shù)據(jù)的存儲(chǔ)引擎,在我們?yōu)橐苿?dòng)設(shè)備開(kāi)發(fā)應(yīng)用程序時(shí),也許就要使用到SQLite來(lái)存儲(chǔ)我們大量的數(shù)據(jù)。
SQLiteDatabase類為我們提供了很多種方法,上面的代碼中基本上囊括了大部分的數(shù)據(jù)庫(kù)操作;對(duì)于添加、更新和刪除來(lái)說(shuō),我們都可以使用
1 db.executeSQL(String sql);
2 db.executeSQL(String sql, Object[] bindArgs);//sql語(yǔ)句中使用占位符,然后第二個(gè)參數(shù)是實(shí)際的參數(shù)集
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//打開(kāi)或創(chuàng)建test.db數(shù)據(jù)庫(kù)
SQLiteDatabase db = openOrCreateDatabase("test.db", Context.MODE_PRIVATE, null);
db.execSQL("DROP TABLE IF EXISTS person");
//創(chuàng)建person表
db.execSQL("CREATE TABLE person (_id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR, age SMALLINT)");
Person person = new Person();
person.name = "john";
person.age = 30;
//插入數(shù)據(jù)
db.execSQL("INSERT INTO person VALUES (NULL, ?, ?)", new Object[]{person.name, person.age});
person.name = "david";
person.age = 33;
//ContentValues以鍵值對(duì)的形式存放數(shù)據(jù)
ContentValues cv = new ContentValues();
cv.put("name", person.name);
cv.put("age", person.age);
//插入ContentValues中的數(shù)據(jù)
db.insert("person", null, cv);
cv = new ContentValues();
cv.put("age", 35);
//更新數(shù)據(jù)
db.update("person", cv, "name = ?", new String[]{"john"});
Cursor c = db.rawQuery("SELECT * FROM person WHERE age >= ?", new String[]{"33"});
while (c.moveToNext()) {
int _id = c.getInt(c.getColumnIndex("_id"));
String name = c.getString(c.getColumnIndex("name"));
int age = c.getInt(c.getColumnIndex("age"));
Log.i("db", "_id=>" + _id + ", name=>" + name + ", age=>" + age);
}
c.close();
//刪除數(shù)據(jù)
db.delete("person", "age < ?", new String[]{"35"});
//關(guān)閉當(dāng)前數(shù)據(jù)庫(kù)
db.close();
//刪除test.db數(shù)據(jù)庫(kù)
// deleteDatabase("test.db");
}
在執(zhí)行完上面的代碼后,系統(tǒng)就會(huì)在/data/data/[PACKAGE_NAME]/databases目錄下生成一個(gè)“test.db”的數(shù)據(jù)庫(kù)文件。
上面的代碼中基本上囊括了大部分的數(shù)據(jù)庫(kù)操作;對(duì)于添加、更新和刪除來(lái)說(shuō),我們都可以使用
db.executeSQL(String sql);
db.executeSQL(String sql, Object[] bindArgs);//sql語(yǔ)句中使用占位符,然后第二個(gè)參數(shù)是實(shí)際的參數(shù)集
來(lái)執(zhí)行sql語(yǔ)句,
除了統(tǒng)一的形式之外,他們還有各自的操作方法:
db.insert(String table, String nullColumnHack, ContentValues values);
db.update(String table, Contentvalues values, String whereClause, String whereArgs);
db.delete(String table, String whereClause, String whereArgs);
以上三個(gè)方法的第一個(gè)參數(shù)都是表示要操作的表名;insert中的第二個(gè)參數(shù)表示如果插入的數(shù)據(jù)每一列都為空的話,需要指定此行中某一列的名稱,系統(tǒng)將此列設(shè)置為NULL,不至于出現(xiàn)錯(cuò)誤;insert中的第三個(gè)參數(shù)是ContentValues類型的變量,是鍵值對(duì)組成的Map,key代表列名,value代表該列要插入的值;update的第二個(gè)參數(shù)也很類似,只不過(guò)它是更新該字段key為最新的value值,第三個(gè)參數(shù)whereClause表示W(wǎng)HERE表達(dá)式,比如“age > ? and age < ?”等,最后的whereArgs參數(shù)是占位符的實(shí)際參數(shù)值;delete方法的參數(shù)也是一樣。
下面,我們就以一個(gè)實(shí)例來(lái)講解具體的用法,我們新建一個(gè)名為db的項(xiàng)目,其中DBHelper繼承了SQLiteOpenHelper,作為維護(hù)和管理數(shù)據(jù)庫(kù)的基類,DBManager是建立在DBHelper之上,封裝了常用的業(yè)務(wù)方法,Person是我們的person表對(duì)應(yīng)的JavaBean,MainActivity就是我們顯示的界面。
public class DBHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "test.db";
private static final int DATABASE_VERSION = 1;
public DBHelper(Context context) {
//CursorFactory設(shè)置為null,使用默認(rèn)值
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
//數(shù)據(jù)庫(kù)第一次被創(chuàng)建時(shí)onCreate會(huì)被調(diào)用
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE IF NOT EXISTS person" +
"(_id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR, age INTEGER, info TEXT)");
}
//如果DATABASE_VERSION值被改為2,系統(tǒng)發(fā)現(xiàn)現(xiàn)有數(shù)據(jù)庫(kù)版本不同,即會(huì)調(diào)用onUpgrade
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("ALTER TABLE person ADD COLUMN other STRING");
}
}
數(shù)據(jù)庫(kù)第一次創(chuàng)建時(shí)onCreate方法會(huì)被調(diào)用,我們可以執(zhí)行創(chuàng)建表的語(yǔ)句,當(dāng)系統(tǒng)發(fā)現(xiàn)版本變化之后,會(huì)調(diào)用onUpgrade方法,我們可以執(zhí)行修改表結(jié)構(gòu)等語(yǔ)句。
為了方便我們面向?qū)ο蟮氖褂脭?shù)據(jù),我們建一個(gè)Person類,對(duì)應(yīng)person表中的字段,如下:
public class Person {
public int _id;
public String name;
public int age;
public String info;
public Person() {
}
public Person(String name, int age, String info) {
this.name = name;
this.age = age;
this.info = info;
}
}
然后,我們需要一個(gè)DBManager,來(lái)封裝我們所有的業(yè)務(wù)方法,代碼如下:
public class DBManager {
private DBHelper helper;
private SQLiteDatabase db;
public DBManager(Context context) {
helper = new DBHelper(context);
//因?yàn)間etWritableDatabase內(nèi)部調(diào)用了mContext.openOrCreateDatabase(mName, 0, mFactory);
//所以要確保context已初始化,我們可以把實(shí)例化DBManager的步驟放在Activity的onCreate里
db = helper.getWritableDatabase();
}
/**
* add persons
* @param persons
*/
public void add(List<Person> persons) {
db.beginTransaction(); //開(kāi)始事務(wù)
try {
for (Person person : persons) {
db.execSQL("INSERT INTO person VALUES(null, ?, ?, ?)", new Object[]{person.name, person.age, person.info});
}
db.setTransactionSuccessful(); //設(shè)置事務(wù)成功完成
} finally {
db.endTransaction(); //結(jié)束事務(wù)
}
}
/**
* update person's age
* @param person
*/
public void updateAge(Person person) {
ContentValues cv = new ContentValues();
cv.put("age", person.age);
db.update("person", cv, "name = ?", new String[]{person.name});
}
/**
* delete old person
* @param person
*/
public void deleteOldPerson(Person person) {
db.delete("person", "age >= ?", new String[]{String.valueOf(person.age)});
}
/**
* query all persons, return list
* @return List<Person>
*/
public List<Person> query() {
ArrayList<Person> persons = new ArrayList<Person>();
Cursor c = queryTheCursor();
while (c.moveToNext()) {
Person person = new Person();
person._id = c.getInt(c.getColumnIndex("_id"));
person.name = c.getString(c.getColumnIndex("name"));
person.age = c.getInt(c.getColumnIndex("age"));
person.info = c.getString(c.getColumnIndex("info"));
persons.add(person);
}
c.close();
return persons;
}
/**
* query all persons, return cursor
* @return Cursor
*/
public Cursor queryTheCursor() {
Cursor c = db.rawQuery("SELECT * FROM person", null);
return c;
}
/**
* close database
*/
public void closeDB() {
db.close();
}
}
我們?cè)贒BManager構(gòu)造方法中實(shí)例化DBHelper并獲取一個(gè)SQLiteDatabase對(duì)象,作為整個(gè)應(yīng)用的數(shù)據(jù)庫(kù)實(shí)例;在添加多個(gè)Person信息時(shí),我們采用了事務(wù)處理,確保數(shù)據(jù)完整性;最后我們提供了一個(gè)closeDB方法,釋放數(shù)據(jù)庫(kù)資源,這一個(gè)步驟在我們整個(gè)應(yīng)用關(guān)閉時(shí)執(zhí)行,這個(gè)環(huán)節(jié)容易被忘記
其他具體詳見(jiàn) 相關(guān)博客: http://blog.csdn.net/liuhe688/article/details/6715983/
現(xiàn)在Android在SQLite數(shù)據(jù)存儲(chǔ)方面出現(xiàn)了很多的ORM框架:ORMLite、greendao、ormndroid、androrm、ActiveAndroid,用于實(shí)現(xiàn)面向?qū)ο缶幊陶Z(yǔ)言里不同類型系統(tǒng)的數(shù)據(jù)之間的轉(zhuǎn)換。從效果上說(shuō),它其實(shí)是創(chuàng)建了一個(gè)可在編程語(yǔ)言里使用的“虛擬對(duì)象數(shù)據(jù)庫(kù)”。這些都極大的提高了我們的開(kāi)發(fā)數(shù)據(jù)庫(kù)的效率,也值得我們深入學(xué)習(xí)。
三、文件存儲(chǔ)數(shù)據(jù)
默認(rèn)存儲(chǔ)路徑:/data/data/<PackageName>/files
核心原理: Context提供了兩個(gè)方法來(lái)打開(kāi)數(shù)據(jù)文件里的文件IO流 FileInputStream openFileInput(String name); FileOutputStream(String name , int mode),這兩個(gè)方法第一個(gè)參數(shù) 用于指定文件名,第二個(gè)參數(shù)指定打開(kāi)文件的模式。具體有以下值可選:
MODE_PRIVATE:為默認(rèn)操作模式,代表該文件是私有數(shù)據(jù),只能被應(yīng)用本身訪問(wèn),在該模式下,寫入的內(nèi)容會(huì)覆蓋原文件的內(nèi)容,如果想把新寫入的內(nèi)容追加到原文件中。可 以使用Context.MODE_APPEND
MODE_APPEND:模式會(huì)檢查文件是否存在,存在就往文件追加內(nèi)容,否則就創(chuàng)建新文件。
MODE_WORLD_READABLE:表示當(dāng)前文件可以被其他應(yīng)用讀取;
MODE_WORLD_WRITEABLE:表示當(dāng)前文件可以被其他應(yīng)用寫入。
除此之外,Context還提供了如下幾個(gè)重要的方法:
getDir(String name , int mode):在應(yīng)用程序的數(shù)據(jù)文件夾下獲取或者創(chuàng)建name對(duì)應(yīng)的子目錄
File getFilesDir():獲取該應(yīng)用程序的數(shù)據(jù)文件夾得絕對(duì)路徑
String[] fileList():返回該應(yīng)用數(shù)據(jù)文件夾的全部文件
寫入文件:
public void save(){
String data = "save something here";
FileOutputStream out = null;
ButteredWriter writer = null;
try{
out = openFileOutput("data",Context.MODE_PRIVATE);
writer = new ButteredWriter(new OutputSreamWriter(out));
writer.write(data);
}catch(IOException e){
e.printStackTrace();
}finally{
try{
if(writer!=null){
writer.close();
}
}catch(IOException e){
e.printStackTrace();
}
}
讀取文件數(shù)據(jù):
public String load(){
FileInputStream in = null;
ButteredReader reader = null;
StringBuilder builder = new StringBuilder();
try{
in = openFileInput("data");
reader = new ButteredReader(new InputStreamReader(in));
String line= "";
while((line = reader.readline()) != null){
builder.append();
}
}catch(IOException e){
e.printStackTrace();
}finally{
if(reader != null){
try{
reader.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
}
讀寫sdcard上的文件
其中讀寫步驟按如下進(jìn)行:
1、調(diào)用Environment的getExternalStorageState()方法判斷手機(jī)上是否插了sd卡,且應(yīng)用程序具有讀寫SD卡的權(quán)限,如下代碼將返回true
Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)
2、調(diào)用Environment.getExternalStorageDirectory()方法來(lái)獲取外部存儲(chǔ)器,也就是SD卡的目錄,或者使用"/mnt/sdcard/"目錄
3、使用IO流操作SD卡上的文件
注意點(diǎn):手機(jī)應(yīng)該已插入SD卡,對(duì)于模擬器而言,可通過(guò)mksdcard命令來(lái)創(chuàng)建虛擬存儲(chǔ)卡
必須在AndroidManifest.xml上配置讀寫SD卡的權(quán)限
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
四、ContentProvider存儲(chǔ)數(shù)據(jù)
ContentProvider主要用于不同的程序之間實(shí)現(xiàn)數(shù)據(jù)共享的功能。詳見(jiàn)Android四大組件介紹的內(nèi)容
五、網(wǎng)絡(luò)存儲(chǔ)
這個(gè)很好理解,就是將數(shù)據(jù)上傳到服務(wù)器,在需要的時(shí)候再將它通過(guò)網(wǎng)絡(luò)讀取下來(lái)即可。