安卓中五種資料儲存方式
分別是:
--SharedPreferences儲存;
--檔案儲存;
--SQLite資料庫儲存;
--ContentProvider儲存;
--網路儲存;
1.1. SharedPreferences儲存:
應用場景:
適用於儲存一些鍵值對,一般用來儲存配置資訊。
儲存位置:
/data/data/包名/shared_prefs 目錄下,以xml格式進行儲存。
可儲存的資料型別:
boolean float int long string
儲存步驟:
1.根據上下文獲取SharedPreferences物件。
2.利用edit()方法獲取Editor物件。
3.通過Editor物件來儲存key-value
4.通過commit()方法提交資料。
好處:
SharedPreferences物件與SQLite資料庫相比,免去了建立資料庫,建立表,寫SQL語句等諸多操作,相對而言更加方便,簡潔。
弊端:
1.只能儲存五種簡單的資料型別
2.無法進行條件查詢
示例程式碼:
sp儲存資料:
//引數1:檔名,沒有則建立。引數2:檔案許可權
SharedPreferences sp = getSharedPreferences("info", MODE_PRIVATE);
//獲取編輯器
Editor editor = sp.edit();
//存入姓名與密碼
editor.putString("name", name);
editor.putString("pwd", pwd);
//提交
editor.commit();
這段程式碼執行後,會在/data/data/<包名>/shared_prefs目錄下生成了一個info.xml檔案,一個應用可以建立多個這樣的xml檔案。
從sp中獲取資料:
String name = sp.getString("name", "");
String pwd = sp.getString("pwd", "");
1.2. 檔案儲存:
應用場景:
儲存一些簡單的文字資料或者二進位制資料
儲存在記憶體:
當應用安裝到 Android 後,系統會根據每個應用的包名建立一個
注意:如果直接File file = new File(“info.txt”);
這樣就報檔案找不到的異常,因為這樣寫會被建立到手機內部儲存的根目錄裡面,但是內部儲存根目錄是隻讀不可寫的。
優化:File file = new File(getFileDir,”info.txt”);
目錄:
/data/data/<包名>/files/info.txt--->getFileDir()+”info.txt”
許可權:
訪問自己包名下的目錄是不需要許可權
方便api:
getCacheDir(); //方法用於獲取/data/data/cache目錄,快取目錄,當儲存空間不足,系統會自動將之清除。
getFilesDir(); //方法用於獲取/data/data/files目錄,儲存重要的資料資訊
儲存
File file = new File("/data/data/com.qq.file/info.txt");
FileOutputStream fos = new FileOutputStream(file);
fos.write((username+"##"+pwd).getBytes());//用##將username和pwd分隔開
fos.close();
Toast.makeText(MainActivity.this,"資料儲存成功",Toast.LENGTH_SHORT).show();
回顯
//File file = new File("/data/data/com.qq.file/info.txt");
File file = new File(getFileDir,”info.txt”);
if(file.exists()&&file.length()>0){
try {
FileInputStream fis = new FileInputStream(file);
BufferedReader br = new BufferedReader(new InputStreamReader(fis));
String info = br.readLine();
String username = info.split(info)[0];
String pwd = info.split(info)[1];
etUsername.setText(username);
etPwd.setText(pwd);
} catch (Exception e) {
e.printStackTrace();
}
}
儲存在sd卡:
目錄:
mnt/sdcard/info.txt--->Envitonment.getExternalStorageState()+”info.txt”
許可權:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
方便api:
獲取SD卡根目錄
Environment.getExternalStorageDirectory()
獲取SD卡的掛載狀態
Environment.getExternalStorageState()
獲取SD卡可用空間大小
Environment.getExternalStorageDirectory().getFreeSpace()
儲存:
String qq = et_qq.getText().toString().trim();
String pwd = et_password.getText().toString().trim();
if (cb_remember.isChecked()) {// 記住密碼
Log.i(TAG, "記住密碼");
try {
// 檢查sd是否存在,是否可用.
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
Toast.makeText(this, "sd卡不可用,請檢查sd卡的狀態", 0).show();
return;
}
// 檢查sd卡的可用空間.
long size = Environment.getExternalStorageDirectory().getFreeSpace();
String info = Formatter.formatFileSize(this, size);
Toast.makeText(this, "可用空間:" + info, 0).show();
//將檔案儲存在sd卡
File file = new File(Environment.getExternalStorageDirectory(),"info.txt");
FileOutputStream fos = new FileOutputStream(file);
// 10000##abc
fos.write((qq + "##" + pwd).getBytes());
fos.close();
Toast.makeText(this, "資料儲存成功", 0).show();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "資料儲存失敗", 0).show();
}
} else {// 不需要記住密碼
Log.i(TAG, "不需要記住密碼");
}
回顯:
File file = new File(Environment.getExternalStorageDirectory(),"info.txt");
if(file.exists()&&file.length()>0){
try{
FileInputStream fis=new FileInputStream(file);
BufferedReader br=new BufferedReader(new InputStreamReader(fis));
// 10000##abc
String info=br.readLine();
String qq=info.split("##")[0];
String pwd=info.split("##")[1];
et_qq.setText(qq);
et_password.setText(pwd);
}catch(Exception e){
e.printStackTrace();
}
}
檔案的許可權
應用程式在data/data/<自己包名>/目錄下建立的檔案預設都是私有的,別的程式是不能訪問的
在模擬器中我們能再看這個目錄並導到桌面上開啟,但是注意真實手機沒有root許可權,所以你根本打不開這個目錄。
建立有許可權的檔案:
openFileOutput(“info.txt”,mode);
mode是檔案訪問許可權:
Context.MODE_PRIVATE=0:預設為私有資料,只能被應用本身訪問,在該模式下,寫入的內容會覆蓋原檔案的內容。
Context.MODE_APPEND=32768:模式會檢查檔案是否存在,存在就往檔案追加內容,否則就建立新檔案。
MODE_WORLD_READABLE=1:表示當前檔案可以被其他應用讀取;
MODE_WORLD_WRITEABLE=2:表示當前檔案可以被其他應用寫入。
如果想建立可讀可寫的檔案:
FileOutputStream fos =openFileOutput(“info.txt”,Context.MODE_WORLD_READBLE+Context.MODE_WORLD_WRITEBLE)
在cmd視窗下修改檔案的許可權
chmod 666 private.txt--->這樣就將private.txt檔案的許可權修改成了可讀可寫的檔案了
600:私有
662:可讀
664:可寫
666:可讀可寫
777:可讀可寫可執行
1.3. SQLite資料庫儲存
定義:
SQLiteOpenHelper 是 Android 提供的一個抽象工具類,負責管理資料庫的建立、開啟、升級工作。如果我們想建立資料庫,就需要自定義一個類繼承 SQLiteOpenHelper,然後重寫其中的抽象方法
應用場景:
適用於儲存一些複雜的關係型資料。
儲存位置:
data/<專案資料夾 >/databases/下。
好處:
支援 SQL 語言
效率高,利用很少的記憶體就有很好的效能
十分適合儲存結構化資料
方便在不同的Activity,甚至不同的應用之間傳遞資料
示例程式碼
1.3.1. 建立資料庫
1.繼承SQLiteOpenHelper
public class mSQLiteOpenHelper extends SQLiteOpenHelper {
Public mSQLiteOpenHelper (Context context){
//上下文,資料庫名稱,預設遊標工廠,資料庫版本號
Super(context,”test.db”,null,1);
}
2.在onCreate()裡適合建立表結構
@Override
public void onCreate(SQLiteDatabase db) {
System.out.println("資料庫oncreate");
db.execSQL("create table student (_id integer primary key autoincrement, name varchar(20), phone varchar(30))");
}
//3.升級資料庫
當手機中資料庫版本低於資料庫中配置的版本時,會自動呼叫onUpdate()方法進行資料庫升級
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
System.out.println("資料庫要被更新了,onupgrade");
//db.execSQL("alter table student add account varchar(20)");
}
}
4.建立資料庫例項
//這一句程式碼執行完,資料庫是不會被建立的
mSQLiteOpenHelper helper = new mSQLiteOpenHelper(this);
//執行這兩句中其中一句,資料庫才被建立
helper.getWritableDatabase();
helper.getReadableDatabase();
1.3.2. 對資料庫增刪改查
1.sql語句
增
insert into student (name, phone) values (‘張三’, ‘110’)
刪
delete from student where name=‘張三’
改
update student set phone=‘119’ where name=‘張三’
查
select * from student where name=‘張三’
對於熟悉 SQL 的開發人員來時,在Android 開發中使用SQLite 相當簡單。但是,由於JDBC 會消耗太多的系統資源,所以JDBC 對於手機這種記憶體受限裝置來說並不合適。因此,Android提供了一些新的 API來使用 SQLite資料庫,Android開發中,程式設計師需要學使用這些 API。
2.用api
public class StudentDao {
private StudentDBOpenHelper helper;
public StudentDao(Context context) { //在構造方法中傳入helper
helper = new StudentDBOpenHelper(context);
}
//增
public long add(String name,String sex){
SQLiteDatabase db = helper.getWritableDatabase();
//db.execSQL("insert into student (name,sex) values (?,?)", new
Object[]{name,sex});
ContentValues values =new ContentValues();
values.put("name", name);
values.put("sex", sex);
long result = db.insert("student", null, values); //組拼sql語句實現的.帶返回值
db.close(); //釋放資源
return result; //新增到哪一行,-1新增失敗
}
//刪
public int delete(String name){
SQLiteDatabase db = helper.getWritableDatabase();
//db.execSQL("delete from student where name=?",new Object[]{name});
int result = db.delete("student", "name=?", new String[]{name});
db.close(); //釋放資源
return result; //result是刪除了幾行,0代表刪除失敗
}
//改
public int update(String name,String newsex){
SQLiteDatabase db = helper.getWritableDatabase();
//db.execSQL("update student set sex =? where name=?",new
Object[]{newsex,name});
ContentValues values = new ContentValues();
values.put("sex", newsex);
int result = db.update("student", values, "name=?", new String[]{name});
db.close(); //釋放資源
return result; //result是更新了幾行,0代表更新失敗
//查
public String find(String name){
String sex = null;
SQLiteDatabase db = helper.getReadableDatabase();
//結果集 遊標
//Cursor cursor = db.rawQuery("select sex from student where name=?", new
String[]{name});
Cursor cursor = db.query("student", new String[]{"sex"}, "name=?", new
String[]{name}, null, null, null);
boolean result = cursor.moveToNext();
if(result){
sex = cursor.getString(0);
}
cursor.close(); //釋放資源
db.close();
return sex; //學生性別,null代表學生不存在
}
//獲取學生全部資訊
public List<Student> findAll(){
List<Student> students =new ArrayList<Student>();
SQLiteDatabase db = helper.getReadableDatabase();
//Cursor cursor = db.rawQuery("select name, sex from student", null);
Cursor cursor = db.query("student", new String[]{"name","sex"}, null, null, null,
null, null);
while(cursor.moveToNext()){
String name = cursor.getString(0);
String sex = cursor.getString(1);
Student student = new Student();
student.setName(name);
student.setSex(sex);
students.add(student);
}
cursor.close();
db.close();
return students;
}
}
在MainActivity中修改增加、刪除功能
1)修改增加功能
// 判斷是否有重複的資料
long rowid = dao.add(name, sex);
if (rowid != -1) {
Toast.makeText(this, "資料新增成功,在資料庫的" + rowd + "行", 0).show();
refreshData();
} else {
Toast.makeText(this, "資料新增失敗", 0).show();
}
2)修改刪除功能
// 從資料庫刪除資料.
int count = dao.delete(name);
if (count > 0) {
Toast.makeText(MainActivity.this, "資料被刪除了" + count + "個", 0).show();
// 更新ui介面.
refreshData();
} else {
Toast.makeText(MainActivity.this, "資料刪除失敗", 0).show();
}
1.3.3. 資料庫的事務
private String s;
BankDBOpenHelper helper = new BankDBOpenHelper(this);
SQLiteDatabase db = helper.getWritableDatabase();
db.beginTransaction();//1.開啟事務
try {
// 模擬轉賬的操作
db.execSQL("update account set money=money-100 where name='zhangsan'");
s.endsWith("haha");
db.execSQL("update account set money=money+100 where name='lisi'");
db.setTransactionSuccessful();//2.設定事務執行成功
} finally {
db.endTransaction(); //3.結束事務
}
db.close();
1.4. ContentProvider儲存
理解:
一個程式可以通過實現一個ContentProvider的抽象介面將自己的資料完全暴露出去,而且ContentProviders是以類似資料庫中表的方式將資料暴露,也就是說ContentProvider就像一個“資料庫”。那麼外界獲取其提供的資料,也就應該與從資料庫中獲取資料的操作基本一樣,只不過是採用URI來表示外界需要訪問的“資料庫”。
Android提供了一些已經在系統中實現的標準Content Provider,比如聯絡人資訊,圖片庫等等,你可以用這些Content Provider來訪問裝置上儲存的聯絡人資訊,圖片等等。
示例Uri:
content://media/internal/images 這個URI將返回裝置上儲存的所有圖片
content://contacts/people/ 這個URI將返回裝置上的所有聯絡人資訊
content://contacts/people/45 這個URI返回單個結果(聯絡人資訊中ID為45的聯絡人記錄)
這種查詢字串格式有點令人迷惑。為此,Android提供一系列的幫助類(在android.provider包下),裡面包含了很多以類變數形式給出的查詢字串,這種方式更容易讓我們理解一點,參見下例:
MediaStore.Images.Media.INTERNAL_CONTENT_URI
Contacts.People.CONTENT_URI
因此,如上面content://contacts/people/45這個URI就可以寫成如下形式:
Uri person = ContentUris.withAppendedId(People.CONTENT_URI, 45);
然後執行資料查詢: Cursor cur = managedQuery(person, null, null, null);
應用場景:
增刪改查其他應用程式中私有資料。
Android系統中能實現所有應用程式共享的一種資料儲存方式,由於資料通常在各應用間的是互相私密的,所以此儲存方式較少使用,但是其又是必不可少的一種儲存方式。例如音訊,視訊,圖片和通訊錄,一般都可以採用此種方式進行儲存。
建立內容提供者編寫的流程:
1.寫一個類繼承ContentProvider,實現增刪改查的方法,宣告uriMatcher匹配規則,來檢查uri路徑是否正確
2.清單檔案配置:
<provider
android:name="com.bank.BankDBBackdoor"
android:authorities="com.bank.db"
android:exported="true" />
3.在另一個程式裡面通過contentResolver增刪改查
1.4.1. 示例程式碼:銀行行長從銀行資料庫搞錢:
一、銀行資料庫:
1.MyDBOpenHelper extends SQLiteOpenHelper
2.在activity裡面創建出資料庫例項
MyDBOpenHelper helper = new MyDBOpenHelper(this);
helper.getWritableDatabase();
二、內容提供者
1.在清單檔案中配置內容提供者
<provider
android:name="bank_provider.BankDBBackDoor"
android:authorities="com.bank.db" //主機名,別的應用程式找到內容提供者靠主機名
android:exported="true"/>
2.設定uri檢查的規則:
制定Uri規則:
//過濾請求,檢查uri的規則,如果uri匹配失敗就返回-1。一般寫UriMatcher.NO_MATCH,表示預設返回-1
static UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
private static final int SUCCESS = 1;
static {//靜態程式碼塊的好處:建立這個類必定會執行裡面的程式碼一次
//三個引數:主機名,自己設定的暗號,返回碼
uriMatcher.addURI("com.bank.db","account",SUCCESS);
}
檢查Uri規則:
在內容提供者增刪改查的方法裡面檢查傳遞過來的uri是否正確
public Uri insert(Uri uri, ContentValues contentValues) {
int code = uriMatcher.match(uri);//檢查uri規則是否正確
if (code == SUCCESS) {//uri規則正確
Log.e(TAG, "增加了一條資料");
} else {
//就丟擲一個異常
throw new IllegalArgumentException("uri規則不符合");
}
3.在內容提供者程式碼裡面提供增刪改查方法
public class BankDbBackdoor
extends ContentProvider {
private static final String TAG = "BankDbBackdoor";
private static final int SUCCESS = 1;
//過濾請求,檢查uri的規則是否正確,如果uri匹配失敗就返回-1
//一般寫UriMatcher.NO_MATCH 表示預設返回-1
static UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//靜態程式碼塊的好處就是程式必須走一遍靜態程式碼塊裡面的內容
static {
//三個引數:主機名,自己設定的暗號,返回碼
uriMatcher.addURI("com.bank.db", "account", SUCCESS);
}
@Override
public boolean onCreate() {
return false;
}
@Nullable
@Override
public String getType(Uri uri) {
return null;
}
@Nullable
@Override
public Uri insert(Uri uri, ContentValues contentValues) {//增
int code = uriMatcher.match(uri); //檢查uri規則是否正確
if (code == SUCCESS) { //uri規則正確
Log.e(TAG, "增加了一條資料");
MyDBOpenHelper helper = new MyDBOpenHelper(getContext());
SQLiteDatabase db = helper.getWritableDatabase();
db.insert("account", null, contentValues);
//利用內容提供者的解析器通知內容觀察者資料發生了變化
getContext().getContentResolver().notifyChange(uri,null);
} else {
//就丟擲一個異常
throw new IllegalArgumentException("uri規則不符合");
}
return null;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {//刪
int code = uriMatcher.match(uri);//檢查uri規則是否正確
if (code == SUCCESS) {//uri規則正確
Log.e(TAG, "刪除了一條資料");
MyDBOpenHelper helper = new MyDBOpenHelper(getContext());
SQLiteDatabase db = helper.getWritableDatabase();
//引數:表名,刪除的條件,
db.delete("account", selection, selectionArgs);
} else {
//就丟擲一個異常
throw new IllegalArgumentException("uri規則不符合");
}
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] strings) {//改
int code = uriMatcher.match(uri);
if (code == SUCCESS) {
Log.e(TAG, "改變了一條資料");
MyDBOpenHelper helper = new MyDBOpenHelper(getContext());
SQLiteDatabase db = helper.getWritableDatabase();
db.update("account", values, selection, strings);
} else {
throw new IllegalArgumentException("uri規則不符合");
}
return 0;
}
@Nullable
@Override
public Cursor query(Uri uri, String[] colums, String selection, String[] selectionArgs,
String sortOrder) {
//查
int code = uriMatcher.match(uri);
if (code == SUCCESS) {
Log.e(TAG, "查詢了一條資料");
MyDBOpenHelper helper = new MyDBOpenHelper(getContext());
SQLiteDatabase db = helper.getReadableDatabase();
//引數:表名,查詢哪一列的內容,選擇的條件語句,語句的引數,null,null,以什麼樣的規則排序
return db.query("account", colums, selection, selectionArgs, null, null, sortOrder);//返回查詢的結果
} else {
throw new IllegalArgumentException("uri規則不符合");
}
}
}
三、其他程式:
6.另外一個程式通過contentResolver對銀行資料庫進行增刪改查
@OnClick(R.id.insert)
public void insert(View view) {//增
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse("content://com.bank.db/account");
ContentValues values = new ContentValues();
values.put("name", "zhangsan");
values.put("money", "100");
resolver.insert(uri, values);
}
@OnClick(R.id.delete)
public void delete(View view) {//刪
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse("content://com.bank.db/account");
resolver.delete(uri, "name=?", new String[]{"zhangsan"});
}
@OnClick(R.id.update)
public void update(View view) {//改
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse("content://com.bank.db/account");
ContentValues values = new ContentValues();
values.put("money", 200);
//修改zhangsan的money為200
resolver.update(uri, values, "name=?", new String[]{"zhangsan"});
}
@OnClick(R.id.query)
public void query(View view) {//查
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse("content://com.bank.db/account");
//查詢name和money這兩列的內容
Cursor cursor = resolver.query(uri, new String[]{"name", "money"}, null, null, null);
while (cursor.moveToNext()) {
Log.e(TAG, "進入了corsor迴圈");
String name = cursor.getString(0);
float money = cursor.getFloat(1);
Log.e(TAG, "name" + name + "---------" + "money" + money);
}
cursor.close();//釋放資源
}
1.5. 網路儲存
應用場景:
儲存比較重要的資料,比如支付寶賬號密碼等等
可以呼叫WebService返回的資料或是解析HTTP協議實現網路資料互動。
許可權:
<uses-permission android:name="android.permission.INTERNET" />
程式碼略。