第一行代碼學習筆記第六章——詳解持久化技術

知識點目錄

知識點回顧

6.1 持久化技術簡介

保存在內存中的數據是處於瞬時狀態的,而持久化技術就是將內存中的瞬時數據保存到存儲設備中,保證即使手機或者電腦關機的情況下,這些數據仍然不會丟失。持久化技術提供了一種機制可以讓數據在瞬時狀態和持久狀態之間進行轉換。

Android主要提供了3種方式用於實現數據持久化功能:

  • 文件存儲

  • SharedPreferences存儲

  • 數據庫存儲

當然也可以存儲到手機SD卡中,但使用上面的三種來保存數據會相對簡單一些,也比存儲在SD卡中更加安全。

6.2 文件存儲

文件存儲是Android中最基本的一種數據存儲方式,有如下特點:

  1. 不會對存儲的內容進行任何格式化處理,所有數據都是原封不動地保存到文件中

  2. 適合存儲一些簡單的文本數據或二進制數據

  3. 如果來保存一些較爲複雜的文本數據,就需要定義一套自己的格式規範

6.2.1 將數據存儲到文件中

Context類中提供了一個openFileOutput()方法,可以用於將數據存儲到指定的文件中。該方法接收兩個參數:

參數一:文件名。文件不可包含路徑,因爲所有的文件都是默認存儲到/data/data//files/目錄下。

參數二:文件的操作模式。有MODE_PRIVATE和MODE_APPEND兩種

MODE_PRIVATE

默認的操作模式,表示當指定同樣文件名的時候,所寫入的內容將會覆蓋原文件中的內容。

MODE_APPEND

如果文件已經存在,則直接在文件中追加內容,不存在就創建新的文件。

代碼示例:

public class MainActivity extends AppCompatActivity {

    private EditText mEditText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mEditText = (EditText) findViewById(R.id.edit);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        String inputText = mEditText.getText().toString();
        //保存數據
        save(inputText);
    }

    private void save(String inputText) {
        FileOutputStream out = null;
        BufferedWriter writer = null;
        try {
            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 (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

在onDestroy()方法中獲取EditText中輸入的內容,並調用save()方法把輸入的內容存儲到文件中,文件名爲data。

運行效果:

查看文件

我們可以藉助Android Device Monitor工具來查看。

打開Android Device Monitor後,進入File Explorer標籤頁,找到/data/data/com.example.filepersistencetest/files/目錄即可看到data文件。

通過右上角的導出按鈕,可以將文件導出到電腦上查看剛纔保存的文件內容。

6.2.2 從文件中讀取數據

Context類中提供了一個openFileInput()方法,用於從文件中讀取數據。該方法只接收一個參數,即要讀取的文件名。

代碼示例:

public class MainActivity extends AppCompatActivity {

    private EditText mEditText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mEditText = (EditText) findViewById(R.id.edit);
        String inputText = load();//加載數據
        if (!TextUtils.isEmpty(inputText)) {
            mEditText.setText(inputText);
            mEditText.setSelection(inputText.length());
            Toast.makeText(this, "Restoring succeeded", Toast.LENGTH_SHORT).show();
        }
    }

    private String load() {
        FileInputStream in = null;
        BufferedReader reader = null;
        StringBuilder content = new StringBuilder();
        try {
            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 {
            try {
                if (reader != null) {
                    reader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return content.toString();
    }
}

劃重點:

  • setSelection()方法將輸入光標移動到文本的末尾位置以便於繼續輸入。

  • TextUtils.isEmpty()方法可以一次性進行兩種判空(傳入的字符串等於null或者等於空字符串)。

運行效果:

6.3 SharedPreferences存儲

SharedPreferences是使用鍵值對的方式來存儲數據的。

6.3.1 將數據存儲到SharedPreferences中

要使用SharedPreferences來存儲數據,首先需要獲取到SharedPreferences對象。Android中主要提供了3種方法用於得到SharedPreferences對象。

1. Context類中的getSharedPreferences()方法

該方法接收兩個參數:

參數一:SharedPreferences文件名稱,如果文件名不存在就會創建一個。

SharedPreferences文件都是存放在/data/data//shared_prefs/目錄下。

參數二:指定操作模式。

目前只有MODE_PRIVATE這一種模式可選,也是默認的操作模式,和直接傳入0的效果相同。

2. Activity類中的getPreferences()方法

這個方法跟Context類中的getSharedPreferences()方法很相似,但只接收一個操作模式參數,因爲使用這個方法時會自動將當前活動的類名作爲SharedPreferences的文件名。

3. PreferenceManager類中的getDefaultSharedPreferences()方法

該方法是一個靜態方法,它接收一個Context參數,並自動使用當前應用程序的包名作爲前綴來命名SharedPreferences文件。

代碼示例:

public class MainActivity extends AppCompatActivity {

    private EditText mEditText;

    @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", Context.MODE_PRIVATE).edit();
                editor.putString("name", "salmonzhang");
                editor.putInt("age", 28);
                editor.putBoolean("married", false);
                editor.apply();
            }
        });
    }
}

通過getSharedPreferences得到SharedPreferences對象,然後通過SharedPreferences.Editor得到Editor對象,接着向這個對象中添加3條不同類型的數據,最後調用apply()方法進行提交。

效果圖:

運行程序後,打開Android Device Monitor,並點擊File Explorer標籤頁,然後進入到/data/data/com.example.sharedpreferencestest/shared_prefs/目錄下,可以看到生成了一個data.xml文件。

6.3.2 從SharedPreferences中讀取數據

SharedPreferences對象中提供了一系列get方法,用於對存儲的數據進行讀取,每種get方法對應SharedPreferences.Editor中的一種put方法。這些get方法都接收兩個參數:

參數一:鍵。傳入存儲數據時使用的鍵就可以得到相應的值。

參數二:默認值。當傳入的鍵找不到對應的值時就會以默認值返回。

代碼示例:

public class MainActivity extends AppCompatActivity {
    private EditText mEditText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button restoreData = (Button) findViewById(R.id.restore_data);
        restoreData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SharedPreferences pref = getSharedPreferences("data", Context.MODE_PRIVATE);
                String name = pref.getString("name", "");
                int age = pref.getInt("age", 0);
                boolean married = pref.getBoolean("married", false);
                Log.d("MainActivity", "name is " + name);
                Log.d("MainActivity", "age is " + age);
                Log.d("MainActivity", "married is " + married);
            }
        });
    }
}

效果圖:

6.3.3 實現記住密碼功能

在第五章中的BroadcastBestPractice項目的基礎上實現記住密碼功能。

效果圖:

實現代碼已上傳到我的gitHub上。

點擊進入查看實現記住密碼功能

備註:實際項目中密碼不能直接用SharedPreferences存儲,要用加密算法對密碼進行保護。

6.4 SQLite數據庫存儲

Android嵌入了SQLite這一款輕量級的關係型數據庫,它具有如下優點:

  • 支持標準的SQL語法

  • 遵循數據庫的ACID事務

  • 運算速度非常快

  • 佔用資源很少,通常只需要幾百KB的內存

6.4.1 創建數據庫

Android提供了一個SQLiteOpenHelper幫助類,方便我們去管理數據庫。

SQLiteOpenHelper是一個抽象類,在使用的時候我們需要新建一個類去繼承它,並重寫SQLiteOpenHelper中的onCreate()和onUpgrade()方法去實現創建、升級數據庫的邏輯。

SQLiteOpenHelper中有兩個很重要的實例方法:getReadableDatabase()和getWriteDatabase(),都可以創建或者打開現有的數據庫(如果數據庫已存在則直接打開,否則創建一個新的數據庫),並返回一個可對數據庫進行讀寫操作的對象。但當數據庫不可寫入的時候(如磁盤空間已滿),getReadableDatabase()方法返回的對象將已只讀的方式去打開數據庫,而getWriteDatabase()方法則將出現異常。

SQLiteOpenHelper中有兩個構造方法可供重寫,一般使用參數少的那個構造方法即可。共4個參數:

參數一:Context

參數二:數據庫名

參數三:允許查詢數據時返回一個自定義的Cursor,一般傳入null即可

參數四:表示當前數據庫的版本號,可用於對數據庫進行升級操作

數據庫存放路徑在/data/data//databases/目錄下。

創建數據庫的步驟:

  1. 新建一個類去繼承QLiteOpenHelper

     public class MyDatabaseHelper extends SQLiteOpenHelper {
     
         public static final String CREATE_BOOK = "create table Book ("
                 + "id integer primary key autoincrement, " //將id設爲主鍵,並自動增長
                 + "author text,"   //文本類型
                 + "price real,"    //浮點類型
                 + "pages integer," //整型
                 + "name text)";     //blob表示二進制類型
         private Context mContext;
     
         public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
             super(context, name, factory, version);
             mContext = context;
         }
     
         @Override
         public void onCreate(SQLiteDatabase db) {
             db.execSQL(CREATE_BOOK); //創建表
             Toast.makeText(mContext, "Create succeeded", Toast.LENGTH_SHORT).show();
         }
     
         @Override
         public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
     
         }
     }
    
  2. 在一個觸發點去創建數據庫

     public class MainActivity extends AppCompatActivity {
     
         private MyDatabaseHelper mDbHelper;
     
         @Override
         protected void onCreate(Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);
             setContentView(R.layout.activity_main);
             mDbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 1);
             Button createDatabase = (Button) findViewById(R.id.create_database);
             createDatabase.setOnClickListener(new View.OnClickListener() {
                 @Override
                 public void onClick(View v) {
                     mDbHelper.getWritableDatabase();//創建或打開數據庫
                 }
             });
         }
     }
    
  3. 查看創建的數據庫

方法一:在Android Device Monitor的File Explorer裏查看

方法二:adb命令查看

備註:BookStore.db-journal是爲了讓數據庫能夠支持事務而產生的臨時日誌文件。

6.4.2 升級數據庫

MyDatabaseHelper中的onUpgrade()方法用於對數據庫進行升級。如果我們要對上面的BookStore數據庫中再添加一張表,則需要藉助onUpgrade()方法。

  • 在MyDatabaseHelper中添加創CREATE_CATEGORY表語句並執行

      public class MyDatabaseHelper extends SQLiteOpenHelper {
      
          public static final String CREATE_BOOK = "create table Book ("
                  + "id integer primary key autoincrement, " //將id設爲主鍵,並自動增長
                  + "author text,"   //文本類型
                  + "price real,"    //浮點類型
                  + "pages integer," //整型
                  + "name text)";     //blob表示二進制類型
      
          public static final String CREATE_CATEGORY = "create table Category ("
                  + "id integer primary key autoincrement, " //將id設爲主鍵,並自動增長
                  + "category_name text,"     //文本類型
                  + "category_code integer)"; //整型
          private Context mContext;
      
          public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
              super(context, name, factory, version);
              mContext = context;
          }
      
          @Override
          public void onCreate(SQLiteDatabase db) {
              db.execSQL(CREATE_BOOK); //創建Book表
              db.execSQL(CREATE_CATEGORY); //創建Category表
              Toast.makeText(mContext, "Create succeeded", Toast.LENGTH_SHORT).show();
          }
      
          @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);
          }
      }
    
  • 數據庫版本號+1

      public class MainActivity extends AppCompatActivity {
      
          private MyDatabaseHelper mDbHelper;
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
      		//數據庫版本號+1(1--->2)
              mDbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 2);
              Button createDatabase = (Button) findViewById(R.id.create_database);
              createDatabase.setOnClickListener(new View.OnClickListener() {
                  @Override
                  public void onClick(View v) {
                      mDbHelper.getWritableDatabase();
                  }
              });
          }
      }
    
6.4.3 添加數據

上面調用SQLiteOpenHelper的getWritableDatabase()或getReadableDatabase()方法後,會返回一個SQLiteDatabase對象,這個對象可以對數據庫進行CRUD操作。

SQLiteDatabase對象的insert()方法,專門用於添加數據。共接收三個參數:

參數一:表名。表明向哪個表中插入數據。

參數二:在未指定添加數據的情況下給某些可爲空的列自動複製NULL,一般用不到這個功能,直接傳入null即可。

參數三:ContentValues對象,它提供了一系列的put方法重載,用於向ContentValues中添加數據。

代碼示例:

//添加數據
Button addData = (Button) findViewById(R.id.add_data);
addData.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        SQLiteDatabase db = mDbHelper.getWritableDatabase();
        ContentValues values = new ContentValues();
        //插入第一組數據
        values.put("name", "The Da Vinci Code");
        values.put("author", "Dan Brown");
        values.put("pages", 454);
        values.put("price", 16.96);
        db.insert("Book", null, values);
        values.clear();
        //插入第二組數據
        values.put("name", "The Lost Symbol");
        values.put("author", "Dan Brown");
        values.put("pages", 510);
        values.put("price", 19.95);
        db.insert("Book", null, values);
    }
});

可以通過SQL查詢語句看看錶中的數據:

6.4.4 更新數據

SQLiteDatabase對象的update()方法,用於對數據進行更新。共接收4個參數:

參數一:表名

參數二:ContentValues對象,把更新數據組裝進去

參數三和參數四:用於約束更新某一行或某幾行中的數據,不指定的話默認更新所有行

代碼示例:

//更新數據
Button updateData = (Button) findViewById(R.id.update_data);
updateData.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        SQLiteDatabase db = mDbHelper.getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put("price",10.99);
        db.update("Book", values, "name = ?", new String[]{"The Da Vinci Code"});
    }
});
6.4.5 刪除數據

SQLiteDatabase對象的delete()方法,用於刪除數據。共接收3個參數:

參數一:表名

參數二和參數三:用於約束刪除某一行或某幾行的數據,不指定的話默認刪除所有行

代碼示例:

//刪除數據
Button deleteData = (Button) findViewById(R.id.delete_data);
deleteData.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        SQLiteDatabase db = mDbHelper.getWritableDatabase();
        db.delete("Book","pages >?",new String[]{"500"});
    }
});
6.4.6 查詢數據

SQLiteDatabase對象的query()方法,用於查詢數據。參數非常複雜,最短的一個方法重載也需要傳入7個參數:

參數一:表名

參數二:指定去查詢哪幾列,不指定則默認所有列

參數三和參數四:約束查詢某一行或某幾行的數據,不指定則默認所有行

參數五:指定需要去group by的列,不指定則表示不對查詢結果進行group by操作

參數六:用於對group by之後的數據進一步過濾,不指定則表示不過濾

參數七:指定查詢結果的排序方式,不指定則表示使用默認的排序方式

代碼示例:

//查詢數據
Button queryData = (Button) findViewById(R.id.query_data);
queryData.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        SQLiteDatabase db = mDbHelper.getWritableDatabase();
        Cursor cursor = db.query("Book", null, null, null, null, null, null);
        if (cursor.moveToFirst()) {
            do {
                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();
    }
});
  • 查詢後得到的是一個Cursor對象

  • 調用cursor的moveToFirst()方法將數據的指針移動到第一行的位置

  • 使用do-while去循環獲取數據庫中的數據

  • 調用close()方法關閉Cursor

6.4.7 使用SQL操作數據庫

有些SQL大牛不喜歡用Android給我們提供的API,而是喜歡用原生的SQL語句去操作。

添加數據的方法:

db.execSQL("insert into Book (name,author,pages,price) values(?,?,?,?)", new String[]{"The Da Vinci Code","Dan Brown","454","16.96"});
db.execSQL("insert into Book (name,author,pages,price) values(?,?,?,?)", new String[]{"The Lost Symbol","Dan Brown","510","19.95"});

更新數據的方法:

db.execSQL("update Book set price = ? where name = ?" ,new String[]{"10.99","The Da Vinci Code"});

刪除數據的方法:

db.execSQL("delete from Book where pages > ?",new String[]{"500"});

查詢數據的方法:

Cursor cursor = db.rawQuery("select * from Book", null);

6.5 使用LitePal操作數據庫

6.5.1 LitePal簡介

LitePal是一款開源的Android數據庫框架,它採用了對象關係映射(ORM)的模式,對我們最常用的一些數據庫功能進行了封裝。

LitePal的詳細使用文檔可以到gitHub上查看:

點擊進入LitePal詳細文檔

6.5.2 配置LitePal

大多數的開源項目都會將版本提交到jcenter上,我們只需要在app/build.gradle文件中聲明引用就可以用。

配置LitePal的步驟如下:

第一步:.將LitePal引用添加到app/build.gradle的dependencies閉包中

dependencies {
    implementation 'org.litepal.android:java:3.0.0'
}

第二步: 配置litepal.xml文件

在app/src/main目錄下新建一個assets目錄,然後在assets目錄下新建一個litepal.xml文件,並編輯如下內容:

<?xml version="1.0" encoding="utf-8"?>
<litepal>
    <dbname value="BookStore"></dbname>
    <version value="1"></version>
    <list></list>
</litepal>

其中:

  • dbname 標籤用於指定數據庫名

  • version 指定數據庫版本號

  • list 指定所有的映射模型

第三步:配置LitePalApplication

在AndroidManifest.xml中將application配置爲org.litepal.LitePalApplication

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.litepaltest">

    <application
        android:name="org.litepal.LitePalApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

    </application>

</manifest>
6.5.3 創建和升級數據庫

對象關係映射就是將面向對象的語言和麪向關係的數據之間建立一種映射關係。

創建數據庫的步驟

1. 新建Book類

public class Book {
    private int id;
    private String author;
    private double price;
    private int pages;
    private String name;

    public int getId() {
        return id;
    }

    public String getAuthor() {
        return author;
    }

    public double getPrice() {
        return price;
    }

    public int getPages() {
        return pages;
    }

    public String getName() {
        return name;
    }

    public void setId(int id) {
        this.id = id;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public void setPages(int pages) {
        this.pages = pages;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Book類中的每一個字段分別對應了表中的每一個列。

2. 將Book類添加到映射模型列表中

<litepal>
    <dbname value="BookStore"></dbname>
    <version value="1"></version>
    <list>
        <mapping class="com.example.litepaltest.Book"></mapping>
    </list>
</litepal>

使用標籤來聲明要配置的映射模型類,注意一定要使用完整的類名。

所有的模型類需要映射時,都要使用同樣的方式配置在標籤中。

3. 創建數據庫

//創建數據庫
Button createDatabase = (Button) findViewById(R.id.create_database);
createDatabase.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        LitePal.getDatabase();
    }
});

升級數據庫

在SQLiteOpenHelper在升級數據庫的時候需要先把之前的表drop掉,然後重新創建纔行,這是一個很危險的動作。LitePal升級數據庫就比較簡單,只要修改你想改的內容,然後將版本號加1就行了。

例如,我們在Book類中增加一個press字段:

private String press;

public String getPress() {
    return press;
}

public void setPress(String press) {
    this.press = press;
}

添加一張Category表:

新建Category類:

public class Category {
    private int id;
    private String categoryName;
    private int categoryCode;

    public int getId() {
        return id;
    }

    public String getCategoryName() {
        return categoryName;
    }

    public int getCategoryCode() {
        return categoryCode;
    }

    public void setId(int id) {
        this.id = id;
    }

    public void setCategoryName(String categoryName) {
        this.categoryName = categoryName;
    }

    public void setCategoryCode(int categoryCode) {
        this.categoryCode = categoryCode;
    }
}

添加到映射模型:

<litepal>
    <dbname value="BookStore"></dbname>
    <version value="2"></version>
    <list>
        <mapping class="com.example.litepaltest.Book"></mapping>
        <mapping class="com.example.litepaltest.Category"></mapping>
    </list>
</litepal>

記得將版本號+1(1—>2)。

運行程序,重新點擊Create database按鈕。

6.5.4 使用LitePal添加數據

對模型類中的數據進行CRUD操作,模型類必要要繼承LitePalSupport類。

第一步:模型類繼承LitePalSupport類

public class Book extends LitePalSupport{
	......
}

第二步:獲取模型類實例,進行添加數據操作

//添加數據
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(454);
        book.setPrice(16.96);
        book.setPress("Unknow");
        book.save();//完成添加數據操作
    }
});
6.5.5 使用LitePal更新數據

LitePal更新數據的API接口比較多,這裏主要介紹常用的兩種方式:

1. 對已經存儲的對象重新設值

已經存儲對象的定義:根據model.isSaved()方法返回結果來判斷,true表示已存儲,false表示未存儲。

model.isSaved()方法返回true的情況有如下兩種:

第一種:已經調用過model.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.setName("The Lost Symbol");
        book.setAuthor("Dan Brown");
        book.setPages(510);
        book.setPrice(19.95);
        book.setPress("Unknow");
        book.save();
        //更新數據
        book.setPrice(10.99);
        book.save();
    }
});

這種更新方式只能對已存儲的對象進行操作,有一定的限制性。

2. 調用updateAll()方法去更新

這種方法更加靈活、方便。

示例代碼:

//更新數據
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(14.95);
        book.setPress("Anchor");
        book.updateAll("name = ? and author = ?", "The Lost Symbol", "Dan Brown");
    }
});

備註:

當想把某個字段更新爲默認值時,不能用上面的方式來set數據,需要使用LitePal統一提供的setToDefault()方法,例如:

Book book = new Book();
book.setToDefault("pages");
book.updateAll();

意思是將書的頁數都更新爲0,因爲updateAll()方法中沒有指定約束條件,因此更新操作對所有數據都生效。

6.5.6 使用LitePal刪除數據

LitePal刪除數據的方法主要有兩種:

1. 直接調用已存儲對象的delete()方法

//刪除數據
Button deleteData = (Button) findViewById(R.id.delete_data);
deleteData.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Book book = new Book();
        book.delete();
        book.save();
    }
});

2. 調用LitePal.deleteAll()方法

//刪除數據
Button deleteData = (Button) findViewById(R.id.delete_data);
deleteData.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        LitePal.deleteAll(Book.class, "price < ?", "15");
    }
});

LitePal.deleteAll()方法參數說明。

參數一:表名

參數二:約束條件

6.5.7 使用LitePal查詢數據

LitePal查詢最簡單是調用findAll()方法。

示例代碼:

//查詢數據
Button queryData = (Button) findViewById(R.id.query_data);
queryData.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        List<Book> books = LitePal.findAll(Book.class);
        for (Book book : books) {
            Log.d(TAG, "book name is " + book.getName());
            Log.d(TAG, "book author is " + book.getAuthor());
            Log.d(TAG, "book pages is " + book.getPages());
            Log.d(TAG, "book price is " + book.getPrice());
            Log.d(TAG, "book press is " + book.getPress());
        }
    }
});

LitePal.findAll返回的是模型類,不是Cursor對象。

除了findAll()方法外,LitePal還提供了很多其他非常常用的查詢API:

查詢Book表中的第一條數據

Book firstBook = LitePal.findFirst(Book.class);

查詢Book表中的最後一條數據

Book lastBook = LitePal.findLast(Book.class);

select()方法用於指定查詢哪幾列的數據

List<Book> books = LitePal.select("name", "author").find(Book.class);

where()方法用於指定查詢的約束條件

List<Book> books1 = LitePal.where("pages > ?", "400").find(Book.class);

order()方法用於指定結果的排序方式

List<Book> books2 = LitePal.order("price desc").find(Book.class);

desc表示降序排列,asc或者不寫表示升序排列

limit()方法用於指定查詢結果的數量,比如只查表中的前3條數據

List<Book> books3 = LitePal.limit(3).find(Book.class);

offset()方法用於指定查詢結果的偏移量,比如查詢表中的第2條、第3條、第4條數據

List<Book> books4 = LitePal.limit(3).offset(1).find(Book.class);

連綴組合

List<Book> books5 = LitePal.select("name", "author", "pages")
        .where("pages > ?", "400")
        .order("pages")
        .limit(10)
        .offset(1)
        .find(Book.class);

LitePal不僅爲了封裝了很多實用的API,還支持使用原生的SQL來進行查詢:

Cursor cursor = LitePal.findBySQL("select * from Book where pages > ? and price < ?", "400", "20");

6.6 小結與點評

本章主要學習了Android常用的數據持久化技術:

  • 文件存儲:適用於存儲一些簡單的文本數據或二進制數據

  • SharedPreferences:適用於存儲一些鍵值對數據

  • 數據庫:適用於存儲那些複雜的關係型數據

非常感謝您的耐心閱讀,希望我的文章對您有幫助。歡迎點評、轉發或分享給您的朋友或技術羣。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章