第一行代码学习笔记第六章——详解持久化技术

知识点目录

知识点回顾

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:适用于存储一些键值对数据

  • 数据库:适用于存储那些复杂的关系型数据

非常感谢您的耐心阅读,希望我的文章对您有帮助。欢迎点评、转发或分享给您的朋友或技术群。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章