Android数据存储之Litepal数据库存储

本文目录:

1. 配置Litepal

2. 创建数据库

3. 升级数据库

4. 添加数据

5. 更新数据

6. 删除数据

7. 查询数据


分割线


(内容来自《Android第一行代码(第二版)》)

介绍:
作为一款开源的Android数据库框架,它采用对象关系映射(ORM)的模式,并将我们平时开发最常用的一些数据库功能进行了封装,使得不用编写一行SQL语句就能完成各种数据库操作。

1. 配置Litepal

  • 添加此开源库的引用声明
    app/build.gradle文件中的dependencies闭包中添加内容compile 'org.litepal.android:core:1.3.2'
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:24.2.1'
    compile 'org.litepal.android:core:1.3.2'
    }
  • 配置litepal.xml文件
    在main目录下新建assets目录,并在其下新建一个litepal.xml文件
<!--litepal.xml文件-->
<?xml version="1.0" encoding="utf-8"?>
<litepal>
    <dbname value="BookStore" ></dbname>
    <version value="1" ></version>

    <list></list>
</litepal>

<dbname>标签用于指定数据库名
<version>标签用于指定数据库版本号
<list>标签用于指定所有映射模型

  • 修改AndroidMainfest.xml文件
    application配置为 android:name="org.litepal.LitePalApplication
<?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"
        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>

2. 创建数据库

开始之前:关于activity_main.xml文件,我们这里直接复用上一篇文章里的activity_main.xml文件代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/create_database"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Create database"/>

    <Button
        android:id="@+id/add_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Add data"/>

    <Button
        android:id="@+id/update_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Update data" />

     <Button
        android:id="@+id/delete_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Delete data"/>

    <Button
        android:id="@+id/query_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Query data" />
</LinearLayout>

对象关系映射模式使我们可以利用面向对象思维来操作数据库,这里为了定义一张Book表,我们定义一个Book类

  • 定义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 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;
    }
}

Book类中每个字段对应了表中的每一个列

  • 修改litepal.xml文件
    加入<mapping class="com.example.litepaltest.Book"></mapping>
    <mapping>标签用来声明我们要配置的映射模型类
<?xml version="1.0" encoding="utf-8"?>
<litepal>
    <dbname value="BookStore" ></dbname>

    <version value="1" ></version>

    <list>
        <mapping class="com.example.litepaltest.Book"></mapping>
    </list>
</litepal>
  • 修改MainActivity代码
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();
            }
        });
    }
}

Connector.getDatabase()方法就是一次最简单的数据库操作,点击一下按钮,数据库就会自动创建完成。

3. 升级数据库

利用SQLite升级数据库时,需要先将之前的表drop掉,这样会造成数据的丢失。
接下来我们看看Litepal怎样升级数据库避免这些问题的。

例如:我们想在Book表中添加一个press(出版社)列,并想新建一张Category表

  • 添加press列
    直接修改Book类代码,添加一个press字段和set、get函数。
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 void setId(int id) {
        this.id = id;
    }

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

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

}
  • 修改litepal.xml文件
    改完之后,将litepal.xml文件中version版本号加1,并加入新建的模型类Category。
<?xml version="1.0" encoding="utf-8"?>
<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>

重运行程序,点击创建数据库按钮,更新操作就完成了。

4. 添加数据

  • 继承DataSupport 类

对数据进行增删查改操作时模型类需要继承自DataSupport类才行

import org.litepal.crud.DataSupport;

public class Book extends DataSupport {

}

这里我们增加以上语句让Book类继承自DataSupport 类

  • 修改MainActivity代码
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();
      }
});

onCreate()中添加以上代码实现添加数据功能。
这里内容很简单,创建出Book类之后调用各种set方法对数据进行设置,最后调用save()方法就完成了数据的添加。

5. 更新数据

这里介绍几种常用的更新方式

1.对已存储的对象重新设值

对于LitePal来说,对象是否已存储是根据调用model. isSaved()方法的结果来判断的

  • 返回true就表示已存储
  • 返回false就表示未存储

那么接下来的问题就是,什么情况下会返回true,什么情况下会返回false呢?

实际上只有在两种情况下model. isSaved()方法才会返回true

  • 一种情况是已经调用过model. save()方法去添加数据了,此时model会被认为是已存储的对象。
  • 另一种情况是model对象是通过LitePal提供的查询API查出来的,由于是从数据库中查到的对象,因此也会被认为是已存储的对象。
    (这里我们先通过第一种情况来进行验证。)
  • 修改MainActivity代码
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();
     }
});

在更新按钮点击事件里,首先添加了一条Book数据,然后调用 setPrice()方法将这本书的价格进行了修改,之后再次调用了save()方法。此时LitePal会发现当前的Book对象是已存储的,因此不会再向数据库中去添加一条新数据,而是会直接更新当前的数据。

2.更灵活的更新方式
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");
      }
});

这里new出Book实例后,直接调用setPrice()和setPress()方法设置更新的数据,然后调用updateAll()方法执行更新操作。

updateAll()方法中可以指定一个条件约束,不指定的话表示更新所有数据
这里我们将书名为The Lost Symbol且作者是Dan Brown的书价格更新为14.95,出版社更新为Anchor

6. 删除数据

1.对已存储的对象删除

直接调用已存储对象的delete()方法就可以了。
也就是说,调用过save()方法的对象,或者是通过LitePal提供的查询API查出来的对象,都可以直接使用delete()方法来删除数据。

2.deleteAll()方法
  • 修改MainActivity代码
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");
     }
});

这里调用deleteAll()方法来删除数据,这行代码的意思是删除Book表中price小于15的书

7. 查询数据

  • 修改MainActivity代码
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> books = DataSupport.findAll(Book.class);,就得到一个Book类型的List集合

运行程序可以看到logcat打印的内容


图片.png

除了findAll()方法外,还有其他一些其他的方法用于查询:

查询第一条数据:
Book firstbook = DataSupport.findFirst(Book.class);

查询最后一条数据:
Book lastbook = DataSupport.findLast(Book.class);

连缀查询:

select():用于指定查询哪几列
List<Book> books = DataSupport.select("name","author").find(Book.class);

where():用于指定查询条件
List<Book> books = DataSupport.where("pages > ?","400").find(Book.class);

order():用于指定结果排序
List<Book> books = DataSupport.order("price desc").find(Book.class);

limit():用于指定查询结果数量
List<Book> books = DataSupport.limit(3).find(Book.class);
(查询表中前三条数据)

offset():用于指定查询结果的偏移量
List<Book> books = DataSupport.limit(3).offset(1).find(Book.class);
(查询表中第2条、第3条和第4条数据,相对前面有了一个位置的偏移)

连缀组合完成复杂查询:

查询表中第11~20条页数大于400的name和author这两列数据,并将结果按照页数升序排列

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

另:LitePal也支持原生SQL查询

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

最后通过以前学习的方法将数据一一取出即可。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,133评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,682评论 3 390
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,784评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,508评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,603评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,607评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,604评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,359评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,805评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,121评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,280评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,959评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,588评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,206评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,442评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,193评论 2 367
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,144评论 2 352