1. 程式人生 > >安卓中五種資料儲存方式

安卓中五種資料儲存方式

分別是:

--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 後,系統會根據每個應用的包名建立一個

/data/data/包名/的資料夾,預設是私有的。

注意:如果直接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());//##usernamepwd分隔開
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返回單個結果(聯絡人資訊中ID45的聯絡人記錄)

這種查詢字串格式有點令人迷惑。為此,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" />

程式碼略。