持久化

01-持久化技术

数据的持久化就是将那些在内存中的瞬间数据保存到存储设备中。

这样可以保证手机或者电脑关机的情况下,这些数据仍然不会丢失。

保存在内存中的数据随时都有可能丢失的。

但是保存在存储设备中的数据则处于持久化状态。

持久化在很多程序开发中都会用到。

Android系统主要提供三种简单地实现持久化的功能。

1 文件存储

2 SharedPreference存储

3 数据库存储。

当然除了上面三种,还可以存储到SD卡中。不过SD卡会复杂和不安全一些。

下面我们来一一讲解一下这三种主要的存储技术。

02-文件存储

这种存储方式比较简单。

它不对存储的内存进行任何格式化处理。

所有的数据原封不动保存到文件当中。

所以适合存储一些简单的文本数据或者二进制数据。

如果你想使用文件存储的方式来保存一些复杂的文本数据。就需要定义一套自己的格式规范。这样方便后面将数据从文件中重新解析出来。

Context类提供一个openFileOutput方法。用于将数据存储到指定文件中。

两个参数:

第一个是文件名。不可以指定路径,所有文件都默认存在/data/data/<packagename>/files/ 目录下面

第二个是文件的操作模式。包含:MODE_PRIVATE和MODE_APPEND

其中MODE_PRIVATE是默认模式。表示如果文件名同名则覆盖原来的文件。

而MODE_APPEND则表示如果文件存在 则追加内容,不存在则创建新文件。

openFileOutput方法返回一个FileOutputStream对象。

得到对象后就可以使用java流的方式将数据写入到文件中。

一个例子:记住文本框的内容

我们希望文本框的内容能记住上一次输入的内容。就算退出应用后也可以。

按理来说,文本框的内容 每次退出后 都是会丢失的 因为它是瞬时数据。如果想要记住 则需要我们把它持久化下来。

下面我们添加一个EditText

然后在活动的onDestroy的时候 持久化下来,在onCreate的时候 读取出来 再写回去。

创建一个新项目:DemoPersistene

03-读取持久化的文件数据

在AS3.0之前可以通过点击Android Device Monitor工具 可以查看data里面的数据的。

不过我们现在使用的不是AS3.0了 所以我们可以使用另外的方式来验证是否有写入到文件中

我们通过FileInputStream来读取文件数据

同样Context中提供了openFileInput方法,用于从文件中读取数据。

封装一个方法来读取数据

package com.foxdevelop.www.demopersistene;

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

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 editText;

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

        String inputText = loadText();//从data中读取文本
        if(!TextUtils.isEmpty(inputText)){ //判断如果不为空则写文本到edittext中
            editText.setText(inputText);
            editText.setSelection(inputText.length());
        }
    }

    //读取文件中的数据
    private String loadText() {
        FileInputStream fileInputStream = null;
        BufferedReader bufferedReader = null;
        StringBuilder stringBuilder = new StringBuilder();
        try{
            fileInputStream = openFileInput("edittextdata");
            bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream));
            String line = "";
            while((line = bufferedReader.readLine())!=null){
                stringBuilder.append(line);
            }
        } catch (IOException e){
            e.printStackTrace();
        } finally {
            if(bufferedReader!=null){
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return stringBuilder.toString();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        String input = editText.getText().toString();
        saveTextToFile(input); //在destroy方法里面 持久化数据到文件里面
    }

    //写入文本到文件中 里面写死了文件名edittextdata
    private void saveTextToFile(String input) {
        FileOutputStream fileOutputStream = null;
        BufferedWriter bufferedWriter = null;
        try
        {
            fileOutputStream = openFileOutput("edittextdata", Context.MODE_PRIVATE);
            bufferedWriter = new BufferedWriter(new OutputStreamWriter(fileOutputStream));
            bufferedWriter.write(input);
        } catch (IOException e)
        {
            e.printStackTrace();
        }finally {
            try {
                if (bufferedWriter !=null)
                    bufferedWriter.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}Code language: JavaScript (javascript)

04-SharedPreferences存储数据

SharedPreferences是以键值对的方式存储数据。

保存数据的时候需要键,读取数据的时候也需要键。

而且它还支持多种不同的数据类型存储。

如果存储的是整型那么读取的时候也是整型。

使用SharedPreferences 我们需要new一个对象

有三种方法创建SharedPreferences对象。

1 Context中的getSharedPreferences方法。

两个参数 1是SharedPreferences文件名 如果文件名不存在则自动创建。它是存放在/data/data/<package name>/shared_prefs/目录下面的。

第二个是指定操作模式。目前只有一种模式可选

MODE_PRIVATE模式。

2 使用Activity中的getPreferences方法

和1类似 不过这种模式默认使用当前活动的类名作为SharedPreferences的文件名

3 PreferenceManager类的getDefaultSharedPreferences方法

这是一个静态方法,接收一个Context参数。

存储数据,分为三步实现

1 调用SharedPreferences对象的edit方法 来获取SharedPreferences.Editor对象

2 向SharedPreferences.Editor对象添加数据。 比如添加一个boolean数据 则调用putBoolean方法。字符串则是putString。

3 调用apply方法将添加的数据提交。这样就完成数据存储操作。

下面我们来试一下。

我们把上节课的文件存储方式改为SharedPreferences存储

private void saveTextToPreference(String input) {
    SharedPreferences.Editor editor =
            getSharedPreferences("MainActivity_Data",MODE_PRIVATE).edit();
    editor.putString("edit_text",input);
    editor.putInt("age",12);
    editor.apply();//提交数据
}Code language: JavaScript (javascript)

05-从SharedPreferences读取数据

我们可以直接使用SharedPreferences对象来读取内容的。

不需要使用Editor对象了。

package com.foxdevelop.www.demopersistene;

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

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 editText;

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

        String inputText = loadText();//从data中读取文本
        if(!TextUtils.isEmpty(inputText)){ //判断如果不为空则写文本到edittext中
            editText.setText(inputText);
            editText.setSelection(inputText.length());
        }
    }

    //读取SharedPreferences中的数据
    private String loadText() {
        SharedPreferences sharedPreferences = getSharedPreferences("MainActivity_Data",MODE_PRIVATE);
        return sharedPreferences.getString("edit_text","");//后面的是读取不到的时候的默认值
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        String input = editText.getText().toString();
        saveTextToPreference(input); //在destroy方法里面 持久化数据到SharedPreferences里面
    }

    private void saveTextToPreference(String input) {
        SharedPreferences.Editor editor =
                getSharedPreferences("MainActivity_Data",MODE_PRIVATE).edit();
        editor.putString("edit_text",input);
        editor.putInt("age",12);
        editor.apply();//提交数据
    }

}Code language: JavaScript (javascript)

06-SQLite数据库存在

SQLite是android内置的数据库。

它是一种轻量级的关系型数据库。

运行速度非常快,占用资源小,通常只需要几百KB内存就足够了。

因而适合在移动设备上使用,

它不仅支持标准的SQL语法,还遵循了数据库的ACID事务。

1 创建数据库。

Android为了方便地管理数据库,专门提供了一个SQLiteOpenHelper帮助类,借助这个类,可以很简单创建和升级数据库。

SQLiteOpenHelper是一个抽象类。 所以需要我们创建一个自己的帮助类去继承它。 SQLiteOpenHelper中有两个抽象方法。

分别是onCreate和onUpgrade,我们必须在自己的帮助类中重写这两个方法。然后分别在这两个方法中去实现创建和升级数据库的逻辑。

SQLiteOpenHelper中有两个非常重要的实例方法:

getReadableDatabase和getWriteableDatabase

这两个方法可以创建或者打开一个现有的数据库。(存在则打开,否则则创建)

并返回一个队数据库进行读写操作的对象。

不过如果数据库不可以写入的时候(比如磁盘满了),这个时候getReadableDatabase方法返回对象将以只读的方式打开数据库,而getWritableDatabase则出现异常。

SQLiteOpenHelper有两个构造方法提供重写。不过我们一般使用参数少一点的构造方法即可。

这个构造方法接收4个参数。

第一个是Context

第二个是数据库名。

第三个是允许我们查询数据时候返回一个自定义的Cursor,一般为null

第四个是当前数据库的版本号。可用于对数据库进行升级操作。

构建出SQLiteOpenHelper实例后,再调用getReadableDatabase或者getWritableDatabase方法就能够创建数据库了。

数据库文件存储在

/data/data/<package name>/databases/目录下面。

下一节 我们来尝试一下。创建一个数据库 并且新建一张表

07-使用SQLite创建数据库和新增表

我们添加一个新项目叫SQLiteDemo

sqlite添加数据库的sql语法是

create table book(
	id integer primary key autoincrement,
	author text,
	price real,
	pages integer,
	name text
)

有sql基础的话应该理解这sql语句不难。

sqlite其实比其他的数据库也要简单些。 因为它的数据类型简单些。

integer表示整数

real表示浮点数

text表示文本类型

blob表示二进制类型。

另外 primary key表示id设为主键 autoincrement表示id是自增长。

如果想要创建表。我们还要在代码中去执行这条sql语句。

我们新建一个类MyDatabaseHelper 让它继承SQLiteOpenHelper

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    <Button
        android:id="@+id/createdb_btn"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:text="创建数据库"
        />
</LinearLayout>Code language: HTML, XML (xml)

添加一个我们自己的帮助类

package com.foxdevelop.www.sqlitedemo;

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

public class MyDatabaseHelper extends SQLiteOpenHelper {

    private static final  String SQL_CREATE_BOOK = "create table book(\n" +
            "\tid integer primary key autoincrement,\n" +
            "\tauthor text,\n" +
            "\tprice real,\n" +
            "\tpages integer,\n" +
            "            name text\n" +
            ")\n";

    private  Context myContext;

    public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory,
                            int version) {
        super(context, name, factory, version);
        myContext = context;
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        sqLiteDatabase.execSQL(SQL_CREATE_BOOK);
        Toast.makeText(myContext,"创建表成功",Toast.LENGTH_LONG).show();
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

    }
}Code language: JavaScript (javascript)

调用帮助类创建数据库和数据表

package com.foxdevelop.www.sqlitedemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    private  MyDatabaseHelper myDatabaseHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myDatabaseHelper = new MyDatabaseHelper(this,"books.db",null,1);
        Button btn = (Button) findViewById(R.id.createdb_btn);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                myDatabaseHelper.getWritableDatabase();
            }
        });
    }
}Code language: JavaScript (javascript)
//活动中点击按钮 会调用getWritableDatabase这个方法 然后这个方法追触发这个回调方法 然后会检查有没有books.db
//这个数据库 如果没有则创建 有则不会创建。 最后会执行这个sql建表语句。
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
    sqLiteDatabase.execSQL(SQL_CREATE_BOOK);
    Toast.makeText(myContext,"创建表成功",Toast.LENGTH_LONG).show();
}Code language: JavaScript (javascript)

我们把sql语句放在一个字符串常量里面。

然后在onCreate方法中 调用execSQL方法去执行这条建表语句。

我们在主活动里面添加一个按钮。然后在按钮事件中 我们调用我们的helper对象去创建数据库。

调用getWritableDatabase方法。

在构造函数里面 我们制定数据库名称 books.db

当我们点击按钮 会检测是否有books.db的数据库 如果没有则创建 否则不会再创建。

08-adb调试工具的使用

adb是android sdk中自带的一个调试工具。

使用这个工具可以直接对连接在电脑上的手机或者模拟器进行调试操作。

它是在sdk的platform-tools目录下面。

我们可以把它在环境变量中的。把platform-tools目录配置环境变量中。

我们这台电脑的sdk是在

D:\Users\YY\AppData\Local\Android\sdk\platform-tools

下面

配置好环境变量后,我们打开cmd 输入adb shell 就会进入到设备的控制台。

然后输入cd命令进入到

/data/data/com.foxdevelop.http://www.sqlitedemo/databases/目录下。

使用ls命令 列出这个目录下面的文件。

然后我们借助sqlite命令 可以打开数据库

输入sqlite3 books.db

如果要查看有哪些表 则键入 .table命令

C:\Users\YY>adb shell
root@generic_x86:/ # cd /data/data/com.foxdevelop.www.sqlitedemo/databases/
root@generic_x86:/data/data/com.foxdevelop.www.sqlitedemo/databases # ls
books.db
books.db-journal
qlite3 books.db                                                               <
SQLite version 3.8.6.1 2015-05-21 17:24:32
Enter ".help" for usage hints.
sqlite> .table
android_metadata  book
sqlite>Code language: PHP (php)

如果想要退出数据库 可以输入.exit 或者.quit

09-升级数据库

在我们的Hlper中 还有一个onUpgrade方法,用于对数据库进行升级。

如果我们想在往数据库books.db中添加一张表Category用于记录书籍的分类。那要怎么做呢?

建表语句

create table Category(
	id integer primary key autoincrement,
	category_name text,
	category_code integer
)

我们把上面的语句添加到helper类里面的一个字符串常量。

注意我们如果再在onCreate里面 执行ecexSQL是不会执行的。

因为onCreate是在数据库不存在的情况下面才会执行的。

那么怎么解决呢?

我们知道helper中的onUpgrade方法 它是什么时候执行的

它是在我们创建new对象的时候 我们还记得 我们的自定义的helper类 第四个参数 这个参数是用来控制数据库的版本的。如果这个参数比现在的数据库的版本要大的话,则会触发helper里面的onUpgrade方法的。

为了让他顺利执行我们可以修改onUpgrade方法的

myDatabaseHelper = new MyDatabaseHelper(this,"books.db",null,2);Code language: JavaScript (javascript)

这个2是用来修改数据库的版本的 如果现在数据库是1版本 那么执行上面的代码 则会把数据库变成了2的版本,并且会触发 onUpgrade方法的执行。

package com.foxdevelop.www.sqlitedemo;

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

public class MyDatabaseHelper extends SQLiteOpenHelper {

    private static final  String SQL_CREATE_BOOK = "create table book(\n" +
            "\tid integer primary key autoincrement,\n" +
            "\tauthor text,\n" +
            "\tprice real,\n" +
            "\tpages integer,\n" +
            "            name text\n" +
            ")\n";

    private  static final  String  SQL_CREATE_CATEGORY = "create table Category(\n" +
            "\tid integer primary key autoincrement,\n" +
            "            category_name text,\n" +
            " \tcategory_code integer\n" +
            ")\n";

    private  Context myContext;

    public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory,
                            int version) {
        super(context, name, factory, version);
        myContext = context;
    }

    //活动中点击按钮 会调用getWritableDatabase这个方法 然后这个方法追触发这个回调方法 然后会检查有没有books.db
    //这个数据库 如果没有则创建 有则不会创建。 最后会执行这个sql建表语句。
    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        sqLiteDatabase.execSQL(SQL_CREATE_BOOK);
        sqLiteDatabase.execSQL(SQL_CREATE_CATEGORY);
        Toast.makeText(myContext,"创建表成功",Toast.LENGTH_LONG).show();
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
        //这个方法是在数据库升级的时候 会执行的
        Toast.makeText(myContext,"升级表成功",Toast.LENGTH_LONG).show();
        //在upgrade里面 删除数据表
        sqLiteDatabase.execSQL("drop table if exists book");
        sqLiteDatabase.execSQL("drop table if exists category");
        onCreate(sqLiteDatabase);
    }
}Code language: JavaScript (javascript)

10-使用SQLite添加数据

我们对数据库的操作无非就是四种增删改查(CRUD)

每一种都有对应的SQL命令。

增加用inset

查询用select

删除用delete

更新用update

不过android提供了一系列的辅助方法,使得开发人员不用sql就可以轻松完成CRUD操作

前面我们说到SQLiteOpenHelper类提供两个方法

getReadableDatabase和getWritableDatabase 用来进行创建和升级数据库。

这两个方法都会返回一个SQLiteDatabase对象。

借助这个对象 我们可以对数据进行CRUD

下面我们添加一个按钮

在按钮事件里面 完成增加两本书

Button btn_add = (Button) findViewById(R.id.addbookbtn);
btn_add.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
       SQLiteDatabase sqLiteDatabase = myDatabaseHelper.getWritableDatabase();
        ContentValues contentValues = new ContentValues();
        //增加一条数据 除了id列 其他列增加数据 按照原来的数据类型
        contentValues.put("author","比尔盖茨");
        contentValues.put("name","从新定义公司");
        contentValues.put("pages",567);
        contentValues.put("price",67.95);
        //调用 sqLiteDatabase来插入记录
        sqLiteDatabase.insert("book",null,contentValues);

        //如果想要继续增加第二本书的话 则需要先清空contentValues
        contentValues.clear();
        contentValues.put("author","谢尔盖");
        contentValues.put("name","微软的诞生");
        contentValues.put("pages",986);
        contentValues.put("price",79.6);
        sqLiteDatabase.insert("book",null,contentValues);
    }
});Code language: JavaScript (javascript)

在cmd里面 执行sql

sqlite> select * from book;
1|姣斿皵鐩栬尐|67.95|567|浠庢柊瀹氫箟鍏徃
2|璋㈠皵鐩東79.6|986|寰蒋鐨勮癁鐢?Code language: JavaScript (javascript)

11-更新数据

在android中更新数据也是非常方便的。

下面我们添加一个按钮 把书本的名称改为英文。

sqLiteDatabase对象提供update方法。它需要四个参数

前面两个参数和insert方法一样。

第三个参数 是sql的where部分 使用?来表示占位符

然后第四个参数 是一个字符串数组 每一个元素来替换第三个字符串中的?号 按顺序来的

下面我们来演示一下 把书本的名称改为英文

Button btn_update = (Button) findViewById(R.id.updatebookbtn);
btn_update.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        SQLiteDatabase sqLiteDatabase = myDatabaseHelper.getWritableDatabase();
        ContentValues contentValues = new ContentValues();
        contentValues.put("name","window microsoft book name");//这个是要修改的列
        sqLiteDatabase.update("book",contentValues,"id = ? ",
                new String[]{"1"}
                );
        contentValues.put("name","google company build ");//这个是要修改的列
        sqLiteDatabase.update("book",contentValues,"id = ? ",
                new String[]{"2"}
        );
    }
});Code language: JavaScript (javascript)
sqlite> select * from book;
1|姣斿皵鐩栬尐|67.95|567|window microsoft book name
2|璋㈠皵鐩東79.6|986|google company buildCode language: JavaScript (javascript)

12-删除数据

删除数据是使用sqLiteDatabase对象提供delete方法。

它是专门用来删除数据的。

它接收三个参数。

第一个是表名

第二个也是where条件

第三个是字符串数组 用来替换第二个中的占位符。

下面我们来试试 把第id为1的记录删除。

Button btn_del = (Button) findViewById(R.id.deletebookbtn);
btn_del.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        SQLiteDatabase sqLiteDatabase = myDatabaseHelper.getWritableDatabase();
        sqLiteDatabase.delete("book","id = ? ",
                new String[]{"1"}
        );
    }
});Code language: JavaScript (javascript)

13-查询数据

sql中大部分功能都集中在”查”这个操作这里。而”增删改”只是占其中一小部分。

由于sql查找实在太多了。

这里也不可能全部都讲。所以我们这里把基本功能用法完成。

感兴趣的同学 应该去学习sql的复杂的查询语句。

sqLiteDatabase提供query方法来进行查询。

它最短的方法需要传入7个参数。

执行query后 返回Cursor对象。

查询出来的数据,我们都可以从这个对象里面取出。

下面我们来试一下。

Button btn_sel = (Button) findViewById(R.id.selectbookbtn);
btn_sel.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        SQLiteDatabase sqLiteDatabase = myDatabaseHelper.getWritableDatabase();
        Cursor cursor = sqLiteDatabase.query("book",null,null,null,null,null,null);
        if (cursor.moveToFirst())//从查找出来的第一条记录开始读取 如果一条记录都没有 则返回false
        {
            do {
                String name = cursor.getString(cursor.getColumnIndex("name"));
                Toast.makeText(view.getContext(),name, Toast.LENGTH_LONG).show();

                int pages = cursor.getInt(cursor.getColumnIndex("pages"));
                Toast.makeText(view.getContext(),""+pages, Toast.LENGTH_LONG).show();
            } while(cursor.moveToNext());
        }
        cursor.close();
    }
});Code language: JavaScript (javascript)

14-直接执行sql语句

我们前面使用是sqlitedabase对象来进行CRUD操作。

比如查找用query 插入用insert

但是其实我们可以直接使用myDatabaseHelper的execSQL方法 执行CRUD操作的

Button btn_exec = (Button) findViewById(R.id.execbookbtn);
btn_exec.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        SQLiteDatabase sqLiteDatabase = myDatabaseHelper.getWritableDatabase();
        //插入数据
        sqLiteDatabase.execSQL("insert into book(author,price,pages,name) values (? ,?,?,?)",
                new String[]{"www.foxdevelop.com","19.3","232","好好学习"}
                );

        //删除 和更新数据和插入一样 都是使用execSQL方法
        //但是查询数据 则使用rawQuery 原生态的查找
       Cursor cursor =  sqLiteDatabase.rawQuery("select * from book",null);

    }
});Code language: JavaScript (javascript)

15-LitePal库的配置和使用

我们接触的第一个开源库-LitePal

采用关系型映射模式ORM

把我们平常开发最常用的数据库功能进行了封装。

可以不用编写一行sql 完成各种建表和增删改查操作。

官方地址

https://github.com/LitePalFramework/LitePal

配置LitePal

因为litepal已经将版本提交到jcenter了

所以我们如果使用只需要在app/build.gradle中引用就可以了。

我们创建一个LitePalDemo的项目

dependencies {
compile 'org.litepal.android:core:1.6.1'
}Code language: JavaScript (javascript)

配置litepal.xml文件

右击app/src/main 然后新建一个assets目录

在目录下面添加一个litepal.xml文件

然后内容如下

<?xml version="1.0" encoding="utf-8"?>
<litepal>
    <dbname value="demo" />
    <version value="1" />
    <list>
    </list>
</litepal>Code language: HTML, XML (xml)

这是唯一的配置文件,属性很简单。

dbname配置项目的数据库名称。

version 配置数据库的版本。每次你想升级数据库,加上这里的值。

list配置映射类。

storage 配置数据库文件应该存储的位置。

internal 和 external是唯一有效的选择。

添加进去后 可能<litepal> 标签会是红色的

这个时候 点击snyc now (右上角会出现这个 点击后 会异步下载jar)

配置LitePalApplication 修改AndroidManifest.xml代码

<application
    android:name="org.litepal.LitePalApplication"
    android:allowBackup="true"Code language: HTML, XML (xml)

16-使用LitePal来创建数据库和表映射

前面我们是使用SQLiteOpenHelper类来创建数据库的。现在我们有了LitePal 就不用这么麻烦了。

刚才我们说过LitePal是关系型映射模式的。那么什么是关系映射呢?

简单点来说,就是变成语言是面向对象的。而使用的数据库则是关系型数据库。那么将面向对象的语言和面向关系的数据库之间建立一种映射关系。这就是对象关系映射了。

这样,我们就可以使用面向对象的思维来操作数据库了。

下面我们来试一下

创建一张book表

以前我们需要编写sql建表语句的。

现在我们使用LitePal 则只需要创建一个book类

package com.foxdevelop.www.litepaldemo;

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

    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;
    }

    public int getPages() {
        return pages;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}Code language: JavaScript (javascript)

然后需要去litepal.xml里面添加book类的映射关系

<?xml version="1.0" encoding="utf-8"?>
<LitePal>
    <dbname value="demo" />
    <version value="1" />
    <list>
        <mapping class="com.foxdevelop.www.litepaldemo.Book"></mapping>
    </list>
</LitePal>Code language: HTML, XML (xml)
root@generic_x86:/ # cd /data/data/com.foxdevelop.www.litepaldemo/databases/
root@generic_x86:/data/data/com.foxdevelop.www.litepaldemo/databases # ls
demo.db
demo.db-journal
qlite3 demo.db                                                                <
SQLite version 3.8.6.1 2015-05-21 17:24:32
Enter ".help" for usage hints.
sqlite> .table
android_metadata  book              table_schema
sqlite>Code language: PHP (php)

17-使用LitePal来升级数据库

以前我们使用SQLiteOpenHelper来升级数据库的时候,我们需要先把数据库删除了,然后再新增。其实这样是很不好的。当然我们可以通过编程来实现这个问题。但是这样需要花更多的精力。

但是在LitePal中,我们升级数据库变得很简单了。

你完全不用考虑任何的逻辑。只需要改你想改的内容。然后版本后+1就可以了。

下面我们来book表添加一个String press字段 用来记录出版社

同时我们添加一哥Category表。

package com.foxdevelop.www.litepaldemo;

public class Category {
    private  int id;
    private String name;
    private  int code;

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }
}Code language: PHP (php)

添加litepal.xml list映射

<?xml version="1.0" encoding="utf-8"?>
<LitePal>
    <dbname value="demo" />
    <version value="2" />
    <list>
        <mapping class="com.foxdevelop.www.litepaldemo.Book"></mapping>
        <mapping class="com.foxdevelop.www.litepaldemo.Category"></mapping>
    </list>
</LitePal>Code language: HTML, XML (xml)

在litepal中 只需要执行Connector.getDatabase(); 这句代码也就可以完成更新了。

18-使用LitePal来添加数据

使用LitePal增加数据的话。非常非常简单。

只需要创建模型类的实例。然后再将要存储的数据设置好。然后调用save方法就可以了。

下面我们来试一下。

不过要进行数据操作。还需要我们的实体类 继承DataSupport类

所以 我们给book和category类 添加添加父类的实现。

package com.foxdevelop.www.litepaldemo;

import org.litepal.crud.DataSupport;

public class Book extends DataSupport {Code language: CSS (css)
//使用litepal 增加数据
Button btnAdd = (Button) findViewById(R.id.addbookbtn);
btnAdd.setOnClickListener(new View.OnClickListener(){
    @Override
    public void onClick(View view) {
        Book book = new Book();
        book.setName("www.foxdevelop.com how to learn");
        book.setAuthor("Mr Huang");
        book.setPages(120);
        book.setPress("beijing press");
        book.setPrice(19.0);
        book.save();//调用它的基类DataSupport的save方法 就可以完成数据的添加了
    }
});Code language: JavaScript (javascript)
sqlite> select * from book;
1|Mr Huang|www.foxdevelop.com how to learn|120|19.0|beijing pressCode language: JavaScript (javascript)

19-使用LitePal来更新数据

更新数据,其实就是对已经存储的数据重写设置它的属性值。然后再调用save方法保存。

那么什么是已存储呢?

判断一个对象是否已存储?

1 通过isSaved方法 返回true 则表示已经存储了。

2 另外 可以通过save保存后 这个时候认为它已经是已存储了的对象。

3 通过查询出来的对象 则认为也是已存储的。

由于查询我们还没有学。所以下面我们就通过第一次保存save后 然后对他进行修改。

Book book = new Book();
book.setName("www.foxdevelop.com how to learn");
book.setAuthor("Mr Huang");
book.setPages(120);
book.setPress("beijing press");
book.setPrice(19.0);
if(!book.isSaved())
{
    Toast.makeText(view.getContext(),"没更新",Toast.LENGTH_LONG).show();
}
book.save();//调用它的基类DataSupport的save方法 就可以完成数据的添加了
if(book.isSaved())
{
    Toast.makeText(view.getContext(),"已经更新了"+book.getName(),Toast.LENGTH_LONG).show();
}
book.setAuthor("Miss Pan");//保证已经存储过的数据 然后设置它值
book.save();//这次保存 就是更新数据基类了Code language: JavaScript (javascript)

20-模糊更新updateAll

可以通过updateAll 来批量模糊更新数据的。

下面我们来演示一下 把id大于2的记录的作者更新为Miss pan

//更新id大于2的记录 比如吧id大于2的数据 都改为潘小姐
Book book2 = new Book();
book2.setAuthor("pan xiao jie");
book2.updateAll(" id > ? and id >? ","2","2");Code language: JavaScript (javascript)
sqlite> select * from book;
1|Mr Huang|www.foxdevelop.com how to learn|120|19.0|beijing press
2|Mr Huang|www.foxdevelop.com how to learn|120|19.0|beijing press
3|pan xiao jie|www.foxdevelop.com how to learn|120|19.0|beijing press
4|pan xiao jie|www.foxdevelop.com how to learn|120|19.0|beijing press
5|pan xiao jie|www.foxdevelop.com how to learn|120|19.0|beijing press
6|pan xiao jie|www.foxdevelop.com how to learn|120|19.0|beijing pressCode language: JavaScript (javascript)

21-设置为字段的默认值

当我们把实例的字段改为默认值的时候。litepal是不会更新的

如果想把它设为默认值。可以使用setToDeault方法的

什么是默认值?

在java中 每一种数据类型 都有自己的默认值

比如int类型是0 字符串类型是null boolean是false

//更新id大于2的记录 比如吧id大于2的数据 都改为潘小姐
Book book2 = new Book();
book2.setPages(0);//把页码改成0 但是不会成功
book2.updateAll(" id > ? and id >? ","2","2");Code language: JavaScript (javascript)

如果真的要改为默认值 则需要调用它的setToDefault方法

Book book2 = new Book();
book2.setToDefault("pages");//把这一列改为默认值
book2.updateAll(" id > ? and id >? ","2","2");Code language: JavaScript (javascript)
sqlite> select * from book;
1|Mr Huang|www.foxdevelop.com how to learn|120|19.0|beijing press
2|Mr Huang|www.foxdevelop.com how to learn|120|19.0|beijing press
3|pan xiao jie|www.foxdevelop.com how to learn|0|19.0|beijing press
4|pan xiao jie|www.foxdevelop.com how to learn|0|19.0|beijing press
5|pan xiao jie|www.foxdevelop.com how to learn|0|19.0|beijing press
6|pan xiao jie|www.foxdevelop.com how to learn|0|19.0|beijing press
7|Miss Pan|www.foxdevelop.com how to learn|0|19.0|beijing press
8|Miss Pan|www.foxdevelop.com how to learn|0|19.0|beijing pressCode language: JavaScript (javascript)

22-使用LitePal删除数据

删除数据也比较简单。

有两种方式。

一种是对已存储的数据直接调用delete方法

这里的已存储 我们一般是查找出来的。

不过我们这里 还是把刚刚新增的数据 删除了演示一下。

Book book = new Book();
book.setName("bilibili.com");
book.setAuthor("Mr Chen");
book.setPages(120);
book.setPress("tianjing  press");
book.setPrice(19.0);
book.save();//新增一条
book.delete();//把刚才新增的删除掉Code language: JavaScript (javascript)

另外一种是 通过DataSupport类的静态方法deleteAll 来删除

这样说一种模糊删除的。

下面我们来演示一下

public void onClick(View view) {
    DataSupport.deleteAll(Book.class,"id>?","5");//删除id大于5的所有记录
}Code language: JavaScript (javascript)

23-使用LitePal查询数据

LitePal查询比之前的helper方便太多太多了

非常的人性化。

比如我们要获取所有的基类可以这样

List<Book> books = DataSupport.findAll(Book.class);Code language: PHP (php)

返回来就是一个list集合。 想想我们之前是通过Cursor对象的。

然后我们就可以使用foreach方法 使用list的数据了

除了findAll 之外 还提供其他的方法

比如 findFirst 获取第一条数据

findLast 获取最后一条数据

可以只查某些列的数据

DataSupport.select("name","author").find(Book.class);Code language: CSS (css)

或者进行调节的帅选

DataSupport.where("id > ?","6").find(Book.class);Code language: CSS (css)

使用order 进行排序

DataSupprot.order("price desc").find(Book.class);Code language: CSS (css)

只查前几条数据

DataSupprot.limit(3).find(Book.class);Code language: CSS (css)

还可以使用offest 进行对查询结果进行偏移

比如查找2 3 4条

可以

DataSupprot.limit(3).offset(1).find(Book.class);Code language: CSS (css)

通过limit和offset 可以实现分页

所有的这些语句 都可以连着写的

比如

DataSupprot.select("id","name")
.where("pages > ?","100")
.order("pages")
.limit(10)
.offset(10)
.find(Book.class);Code language: CSS (css)

LitePal还可以直接进行sql执行

Cursor c = DataSupport.findBySQL("select * from book where page>? and id <?","100","60");Code language: JavaScript (javascript)
List<Book> books = DataSupport.findAll(Book.class);//获取所有的基类
    for(Book book : books)
    {
        Log.d("MainActivity",book.getName());
    }
    Book book = DataSupport.findFirst(Book.class);
    Book bookLast = DataSupport.findLast(Book.class);
    Book bookColumn = DataSupport.select("id","name").findLast(Book.class);
    //只取id和name这两列的数据 然后其他的则为默认值
    List<Book> booksWhere = DataSupport.where("pages > ?","100").find(Book.class);//where条件
    //对结果进行排序
    List<Book> booksOrder = DataSupport.where("pages > ?","100").order("pages desc").find(Book.class);
    //取顶部N条
    List<Book> booksLimit = DataSupport.where("pages > ?","100").order("pages desc").limit(10).find(Book.class);
    //进行偏移获取 比如取10到20条
    List<Book> booksOffset = DataSupport.where("pages > ?","100").order("pages desc").limit(10).offset(10).find(Book.class);
    List<Book> booksOffset2 = DataSupport.where("pages > ?","100").order("pages desc").offset(10).limit(10).find(Book.class);
    //这些API可以连写
    List<Book> booksLink = DataSupport.select("id","name").where("pages > ?","100").order("pages desc").offset(10).limit(10).find(Book.class);
    for(Book book3 : booksLink)
    {
        Log.d("MainActivity",book3.getName());
    }
    //还可以直接执行sql语句
    Cursor cursor = DataSupport.findBySQL("select * from book where pages > ? and price < ?  order by pages desc", "5","12")Code language: JavaScript (javascript)

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注