天天看點

持久化技術---《第一行代碼Android》筆記

    • 檔案存儲
    • SharedPreferences存儲 鍵值對存儲
    • SQLite資料庫存儲
    • 開源庫 LitePal 操作資料庫

檔案存儲

package com.example.filepersistencetest;

import android.content.Context;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.widget.EditText;
import android.widget.Toast;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

/**
*啟動時加載檔案中資料,退出時儲存資料到檔案
*/
public class MainActivity extends AppCompatActivity {

    private EditText edit;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        edit = (EditText) findViewById(R.id.edit);
        String inputText = load();
        if (!TextUtils.isEmpty(inputText)) {//TextUtils.isEmpty("")判斷字元串是否為null或""
            edit.setText(inputText);
            edit.setSelection(inputText.length());
            Toast.makeText(this, "Restoring succeeded", Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        String inputText = edit.getText().toString();
        save(inputText);
    }
    /**
     * 儲存資料到檔案
     */
    public void save(String inputText) {
        FileOutputStream out = null;
        BufferedWriter writer = null;
        try {
            /**
             * Context類中提供了一個openFileOutput()方法用于将資料存儲到指定檔案,
             *     傳回一個FileOutputStream對象。
             * 第一個參數是檔案名,不可以包含路徑,所有檔案都
             *     預設儲存在/data/data/<package name>/files/目錄下
             * 第二個參數是操作模式。有兩個:
             *     MODE_PRIVATE:同名時覆寫檔案内容;
             *     MODE_APPEND:同名時追加資料,無同名檔案時建立。
             */
            out = openFileOutput("data", Context.MODE_PRIVATE);
            writer = new BufferedWriter(new OutputStreamWriter(out));
            writer.write(inputText);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (writer != null) {
                    writer.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 讀取檔案資料
     */
    public String load() {
        FileInputStream in = null;
        BufferedReader reader = null;
        StringBuilder content = new StringBuilder();
        try {
            /**
             * Context類中提供了一個openFileInput()方法用于檔案中讀取資料。
             * 隻有一個參數,檔案名,不帶路徑,系統會自動在預設路徑中加載這個檔案。
             * 該方法傳回一個FileInputStream對象。
             */        
            in = openFileInput("data");
            reader = new BufferedReader(new InputStreamReader(in));
            String line = "";
            while ((line = reader.readLine()) != null) {
                content.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return content.toString();
    }

}
           

SharedPreferences存儲 鍵值對存儲

檔案預設路徑:/data/data//shared_prefs/

想要使用SharedPreferences來存儲資料,需要先擷取SharedPreferences對象,有三種方式

  • Context類中的getSharedPreferences()方法,有兩個參數,第一個是檔案名,不帶路徑,儲存在預設路徑;第二個參數是操作模式,目前隻有一種MODE_PRIVATE,也是預設的,與傳入0效果相同,表示隻有目前應用才可以對這個檔案進行讀寫。
  • Activity類中的getSharedPreferences()方法,與Context中的getSharedPreferences()方法相識,不過隻有一個操作模式的參數,預設以這個Activity名為檔案名。
  • PreferenceManager類中的靜态方法getPreferences(),接受一個Context參數,并自動使用目前應用程式的包名作為字首來命名檔案。

儲存資料步驟:

1. 調用SharedPreferences對象的edit()方法擷取SharedPreferences.Editor對象。

2. 使用Editor對象的putString()、putBoolean()、putInt()等方法傳入要儲存的資料。

3. 調用Editor的apply()方法送出儲存資料

package com.example.sharedpreferencestest;

import android.content.SharedPreferences;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button saveData = (Button) findViewById(R.id.save_data);
        saveData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //儲存資料步驟
                SharedPreferences.Editor editor = getSharedPreferences("data", MODE_PRIVATE).edit();
                editor.putString("name", "Tom");
                editor.putInt("age", );
                editor.putBoolean("married", false);
                editor.apply();
            }
        });
        Button restoreData = (Button) findViewById(R.id.restore_data);
        restoreData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //讀取資料步驟
                SharedPreferences pref = getSharedPreferences("data", MODE_PRIVATE);
                String name = pref.getString("name", "");
                int age = pref.getInt("age", );
                boolean married = pref.getBoolean("married", false);
                Log.d("MainActivity", "name is " + name);
                Log.d("MainActivity", "age is " + age);
                Log.d("MainActivity", "married is " + married);
            }
        });
    }

}
           

SQLite資料庫存儲

android内置資料庫SQLite。SQLite不僅支援标準的SQL文法,還遵循資料庫ACID事務,而且不用設定使用者名和密碼就能使用。

Android提供了一個SQLiteOpenHelper幫助類對SQLite資料庫進行操作。SQLiteOpenHelper是個抽象類,需要建立一個類繼承此類,并實作此類中方法:

- onCreate():建立資料庫

- onUpgrade():更新資料庫

package com.example.databasetest;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.widget.Toast;

public class MyDatabaseHelper extends SQLiteOpenHelper {

    public static final String CREATE_BOOK = "create table Book ("
            + "id integer primary key autoincrement, "
            + "author text, "
            + "price real, "
            + "pages integer, "
            + "name text)";

    public static final String CREATE_CATEGORY = "create table Category ("
            + "id integer primary key autoincrement, "
            + "category_name text, "
            + "category_code integer)";

    private Context mContext;

    /**
     * 構造函數
     * @param context
     * @param name 資料庫名
     * @param factory 允許我們在查詢資料的時候傳回一個自定義的Cursor,一般都是傳入null
     * @param version 資料庫的版本号,可用于對資料庫進行更新操作
     */
    public MyDatabaseHelper(Context context, String name,
                            SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
        mContext = context;
    }

    /**
     * 建立資料庫
     * 若資料庫不存在則調用本方法,若資料庫已存在,則不再調用
     * @param db
     */
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_BOOK);
        db.execSQL(CREATE_CATEGORY);
        Toast.makeText(mContext, "Create succeeded", Toast.LENGTH_SHORT).show();
    }

    /**
     * 資料庫更新
     * @param db
     * @param oldVersion
     * @param newVersion
     */
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("drop table if exists Book");
        db.execSQL("drop table if exists Category");
        onCreate(db);
    }

}

           

對資料庫進行操作。

SQLiteOpenHelper類還有兩個非常重要的執行個體方法,都是建立和打開一個現有資料庫,傳回資料庫執行個體SQLiteDatabase,但是有不同之處:

- getReadableDatabase():當資料庫不可寫入(如磁盤空間已滿)時,傳回的對象将已隻讀方式打開資料庫。

- getWritableDatabase():當資料庫不可寫入(如磁盤空間已滿)時,報異常

package com.example.databasetest;

import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    private MyDatabaseHelper dbHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, );//得到SQLiteOpenHelper執行個體
        Button createDatabase = (Button) findViewById(R.id.create_database);
        createDatabase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dbHelper.getWritableDatabase();//打開或建立資料庫
            }
        });
        //插入資料
        Button addData = (Button) findViewById(R.id.add_data);
        addData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                ContentValues values = new ContentValues();
                // 開始組裝第一條資料
                values.put("name", "The Da Vinci Code");//第一個參數是資料庫列名,第二個參數是要插入的資料
                values.put("author", "Dan Brown");
                values.put("pages", );
                values.put("price", );
                db.insert("Book", null, values); // 插入第一條資料,第一個參數是表名,第二個參數用于在未指定添加資料的情況下給某些可空的列自動指派NULL,一般傳入null即可,第三個參數是ContentValues執行個體,用以存儲資料
                values.clear();
                // 開始組裝第二條資料
                values.put("name", "The Lost Symbol");
                values.put("author", "Dan Brown");
                values.put("pages", );
                values.put("price", );
                db.insert("Book", null, values); // 插入第二條資料
            }
        });
        //更新資料庫
        Button updateData = (Button) findViewById(R.id.update_data);
        updateData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                ContentValues values = new ContentValues();
                values.put("price", );
                db.update("Book", values, "name = ?", new String[] { "The Da Vinci Code" });//第一個參數是表名,第二個參數是限制條件,第三個參數是第二個參數中的"?"中的值
            }
        });
        //删除資料
        Button deleteButton = (Button) findViewById(R.id.delete_data);
        deleteButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                db.delete("Book", "pages > ?", new String[] { "500" });
            }
        });
        //查詢資料庫
        Button queryButton = (Button) findViewById(R.id.query_data);
        queryButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                // 查詢Book表中所有的資料
                //7個參數分别代表
                //表名、要查詢的列名、where、where中具體的值、groupBy、having、orderBy
                Cursor cursor = db.query("Book", null, null, null, null, null, null);
                if (cursor.moveToFirst()) {
                    do {
                        // 周遊Cursor對象,取出資料并列印
                        String name = cursor.getString(cursor.getColumnIndex("name"));
                        String author = cursor.getString(cursor.getColumnIndex("author"));
                        int pages = cursor.getInt(cursor.getColumnIndex("pages"));
                        double price = cursor.getDouble(cursor.getColumnIndex("price"));
                        Log.d("MainActivity", "book name is " + name);
                        Log.d("MainActivity", "book author is " + author);
                        Log.d("MainActivity", "book pages is " + pages);
                        Log.d("MainActivity", "book price is " + price);
                    } while (cursor.moveToNext());
                }
                cursor.close();
            }
        });

        //直接運作sql語句
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        //插入、修改、删除都調用execSQL()方法
        db.execSQL("insert into Book(name,author)values(?,?)" , new String[]{"asdf","qwer"});
        //查詢用rawQuery()方法
        db.rawQuery("select * from Book",null);
    }

}
           

開源庫 LitePal 操作資料庫

LitePal采用對象關系映射(ORM)的模式。

1, 在app/build.gradle檔案中在dependencies閉包中添加:

compile ‘org.litepal.android:core:1.4.1’

2, 配置litepal.xml.在app/src/main目錄下建立assets目錄,在該目錄下建立litepal.xml:

<?xml version="1.0" encoding="utf-8"?>
<litepal>
    <!--資料庫名-->
    <dbname value="BookStore" ></dbname>
    <!--資料庫版本,更新資料庫時,這裡+1就行了-->
    <version value="2" ></version>
    <!--表實體類映射清單-->
    <list>
        <mapping class="com.example.litepaltest.Book"></mapping>
    </list>
</litepal>
           

3, 修改AndroidManifest.xml檔案:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.litepaltest">

    <application
        android:name="org.litepal.LitePalApplication"<!--這裡加入litePal架構-->
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
           

4,建立實體類

package com.example.litepaltest;

import org.litepal.crud.DataSupport;

//繼承DataSupport類,才能進行CRUD操作
public class Book extends DataSupport {
    private int id;
    private String author;
    private double price;
    public int getId() { return id;}
    public void setId(int id) { this.id = id;}
    public String getAuthor() { return author;}
    public void setAuthor(String author) {this.author = author;}
    public double getPrice() { return price;}
    public void setPrice(double price) {this.price = price; }
}
           

5,對資料庫的操作

package com.example.litepaltest;

import android.database.Cursor;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import org.litepal.crud.DataSupport;
import org.litepal.tablemanager.Connector;

import java.util.List;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //建立資料庫
        Button createDatabase = (Button) findViewById(R.id.create_database);
        createDatabase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Connector.getDatabase();
            }
        });
        //儲存資料
        Button addData = (Button) findViewById(R.id.add_data);
        addData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Book book = new Book();
                book.setName("The Da Vinci Code");
                book.setAuthor("Dan Brown");
                book.setPages();
                book.setPrice();
                book.setPress("Unknow");
                book.save();
            }
        });
        //更新資料
        Button updateData = (Button) findViewById(R.id.update_data);
        updateData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Book book = new Book();
                book.setPrice();
                book.setPress("Anchor");
                book.setToDefault("price");//把price字段設定為預設值
                book.updateAll("name = ? and author = ?", "The Lost Symbol", "Dan Brown");
            }
        });
        //删除資料,可直接調用執行個體的delete()方法即可,如book.delete()。
        //下面是另一種删除資料的方式
        Button deleteButton = (Button) findViewById(R.id.delete_data);
        deleteButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                DataSupport.deleteAll(Book.class, "price < ?", "15");
            }
        });
        Button queryButton = (Button) findViewById(R.id.query_data);
        queryButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                List<Book> books = DataSupport.findAll(Book.class);
                for (Book book: books) {
                    Log.d("MainActivity", "book name is " + book.getName());
                    Log.d("MainActivity", "book author is " + book.getAuthor());
                    Log.d("MainActivity", "book pages is " + book.getPages());
                    Log.d("MainActivity", "book price is " + book.getPrice());
                    Log.d("MainActivity", "book press is " + book.getPress());
                }

                //條件查詢
                List<Book> books2=DataSupport.select("name","author")//要查詢的列
                        .where("price > ? and price < ?","100","200")
                        .order("id")//排序
                        .limit()
                        .offset()//偏移量,與limit()一起實作sql中的limit功能
                        .find(Book.class);

                //SQL語句查詢
                Cursor c=DataSupport.findBySQL("select * from Book where price < ?","100");
            }
        });
    }

}