美文网首页Android开发技巧
【Android】LitePal安装和使用

【Android】LitePal安装和使用

作者: 孙朗斌 | 来源:发表于2017-08-18 15:54 被阅读77次

    【Android】LitePal安装和使用

    本文基本上为整理稿。感谢LitePal的作者和郭霖大神。

    参考文献:

    Github — https://github.com/LitePalFramework/LitePal

    《LitePal 1.6.0版本来袭,数据加解密功能保障你的应用数据安全》— https://mp.weixin.qq.com/s?__biz=MzA5MzI3NjE2MA%3D%3D&mid=2650240766&idx=1&sn=096f029aa531d5d99191c3d4c9126fc1#wechat_redirect

    Tag:ORMAndroidLitePal

    [TOC]

    关于LitePal

    LitePal是一个可以让开发者更简单操作SQLite的开源Android库。你不用写SQL命令就可以完成大部分诸如创建或更新表、CRUD操作和聚合函数等数据库操作。LitePal的安装也十分简单,不用5分钟就可以集成到你的项目中。

    特性

    • 使用对象关系映射(ORM)设计模式;
    • 几乎零配置(仅仅配置一个很少属性的配置文件);
    • 自动维护所有的表(比如:创建表、修改表和删除表);
    • 多数据库支持;
    • 为避免写SQL语句而封装了APIs;
    • 极为流畅的查询API;
    • 仍然还可以选择使用SQL,但APIs要比原生的更好更容易。

    安装

    导入库

    在AndroidStudio中,编辑build.gradle文件,加入以下:

    dependencies {
        compile 'org.litepal.android:core:1.6.0'
    }
    

    配置litepal.xml

    在项目中的assets文件下,创建并命名一个litepal.xml文件,并编辑修改为以下代码:

    <?xml version="1.0" encoding="utf-8"?>
    <litepal>
        <!--
            Define the database name of your application. 
            By default each database name should be end with .db. 
            If you didn't name your database end with .db, 
            LitePal would plus the suffix automatically for you.
            For example:    
            <dbname value="demo" />
        -->
        <dbname value="demo" />
    
        <!--
            Define the version of your database. Each time you want 
            to upgrade your database, the version tag would helps.
            Modify the models you defined in the mapping tag, and just 
            make the version value plus one, the upgrade of database
            will be processed automatically without concern.
                For example:    
            <version value="1" />
        -->
        <version value="1" />
    
        <!--
            Define your models in the list with mapping tag, LitePal will
            create tables for each mapping class. The supported fields
            defined in models will be mapped into columns.
            For example:    
            <list>
                <mapping class="com.test.model.Reader" />
                <mapping class="com.test.model.Magazine" />
            </list>
        -->
        <list>
        </list>
        
        <!--
            Define where the .db file should be. "internal" means the .db file
            will be stored in the database folder of internal storage which no
            one can access. "external" means the .db file will be stored in the
            path to the directory on the primary external storage device where
            the application can place persistent files it owns which everyone
            can access. "internal" will act as default.
            For example:
            <storage value="external" />
            <storage value="wolf/database" />
        -->
        
    </litepal>
    

    将加密数据库存储在SD卡

    如果需要将加密后的数据库保存到SD卡上,则需要修改litepal.xml中的配置。代码如下:

    <litepal>
        
        <storage value="wolf/database" />
    
    </litepal>
    

    注意:不需要填写SD卡的完成路径,需要配置相对路径即可。

    由于LitePal中既没有Activity也没有Fragment,所以LitePal是不会去帮你申请运行时的SD卡访问读写权限。如果选择将数据库文件存储在SD卡上,请一定要确保你的应用程序已经对访问SD卡权限进行了运行时权限处理,否则LitePal的所有操作都将会失败。

    配置LitePalApplication

    配置AndroidManifest.xml如下:

    <manifest>
        <application
            android:name="org.litepal.LitePalApplication">
    
        </application>
    </manifest>
    

    当然,还有一种配置方法。

    <manifest>
        <application
            android:name="com.example.MyOwnApplication">
        </application>
    </manifest>
    
    public class MyOwnApplication extends xxxApplication {
    
        @Override
        public void onCreate() {
            super.onCreate();
            LitePal.initialize(this);
        }
        
    }
    

    注意:最好是在onCreate()方法中进行初始化LitePal.initialize(this)

    使用

    创建表

    比如,有两个模型类:【专辑】和【歌曲】。定义模型如下:

    public class Album extends DataSupport {
        
        @Column(unique = true, defaultValue = "unknown")
        private String name;
        
        private float price;
        
        private byte[] cover;
        
        private List<Song> songs = new ArrayList<Song>();
    
        // generated getters and setters.
       
    }
    
    public class Song extends DataSupport {
        
        @Column(nullable = false)
        private String name;
        
        private int duration;
        
        @Column(ignore = true)
        private String uselessField;
        
        private Album album;
    
        // generated getters and setters.
        
    }
    

    然后,在litepal.xml文件中添加这两个模型的映射列表。

    <list>
        <mapping class="org.litepal.litepalsample.model.Album" />
        <mapping class="org.litepal.litepalsample.model.Song" />
    </list>
    

    这样,当进行数据库操作的时候,会自动生成表。例如:

    SQLiteDatabase db = LitePal.getDatabase();
    

    自动生成的表,等价于以下SQLs:

    CREATE TABLE album (
        id integer primary key autoincrement,
        name text unique default 'unknown',
        price real,
        cover blob
    );
    
    CREATE TABLE song (
        id integer primary key autoincrement,
        name text not null,
        duration integer,
        album_id integer
    );
    

    更新表

    例如添加一个发布时间字段并注释掉【售价】字段:

    public class Album extends DataSupport {
        
        @Column(unique = true, defaultValue = "unknown")
        private String name;
        
        @Column(ignore = true)
        private float price;
        
        private byte[] cover;
        
        private Date releaseDate;
        
        private List<Song> songs = new ArrayList<Song>();
    
        // generated getters and setters.
        
    }
    

    litepal.xml文件中的数据库版本会自动进行更新。

    <!--
        Define the version of your database. Each time you want 
        to upgrade your database, the version tag would helps.
        Modify the models you defined in the mapping tag, and just 
        make the version value plus one, the upgrade of database
        will be processed automatically without concern.
        For example:    
        <version value="1" ></version>
    -->
    <version value="2" ></version>
    

    保存数据

    保存操作的API是面向对象的。每个继承于DataSupport的模型都有save()方法。例如:

    Album album = new Album();
    album.setName("album");
    album.setPrice(10.99f);
    album.setCover(getCoverImageBytes());
    album.save();
    Song song1 = new Song();
    song1.setName("song1");
    song1.setDuration(320);
    song1.setAlbum(album);
    song1.save();
    Song song2 = new Song();
    song2.setName("song2");
    song2.setDuration(356);
    song2.setAlbum(album);
    song2.save();
    

    更新数据

    最简单的方法,通过find()找到记录,并使用save()方法更新记录。

    Album albumToUpdate = DataSupport.find(Album.class, 1);
    albumToUpdate.setPrice(20.99f); // raise the price
    albumToUpdate.save();
    

    每个继承于DataSupport的模型,都有update()updateAll()方法。

    Album albumToUpdate = new Album();
    albumToUpdate.setPrice(20.99f); // raise the price
    albumToUpdate.update(id);
    

    或者带有where条件的更新多条记录。

    Album albumToUpdate = new Album();
    albumToUpdate.setPrice(20.99f); // raise the price
    albumToUpdate.updateAll("name = ?", "album");
    

    删除数据

    使用DataSupport中静态方法delete()删除一条记录。

    DataSupport.delete(Song.class, id);
    

    或者使用DataSupport中静态方法deleteAll()删除多条记录。

    DataSupport.deleteAll(Song.class, "duration > ?" , "350");
    

    查询数据

    从【歌曲】表中通过id查找单一条记录。

    Song song = DataSupport.find(Song.class, id);
    

    从【歌曲】表中查找多条记录。

    List<Song> allSongs = DataSupport.findAll(Song.class);
    

    通过fluent query构建复杂查询。

    List<Song> songs = DataSupport.where("name like ?", "song%").order("duration").find(Song.class);
    

    异步操作

    默认每个数据库操作都是在主线程上。如果操作可能花费很长的时间,例如保存或者查询大量的记录,可能需要使用异动操作。

    LitePal的所有CRUD方法都支持异步操作。例如,在后台线程从【歌曲】表中查找多条记录,代码如下:

    DataSupport.findAllAsync(Song.class).listen(new FindMultiCallback() {
        @Override
        public <T> void onFinish(List<T> t) {
            List<Song> allSongs = (List<Song>) t;
        }
    });
    

    使用findAllAsync()代替findAll(),并且拓展一个listen()方法,当异步操作完成时,通过回调onFinish()方法返回查询结果。

    相同地,异步存储代码如下:

    Album album = new Album();
    album.setName("album");
    album.setPrice(10.99f);
    album.setCover(getCoverImageBytes());
    album.saveAsync().listen(new SaveCallback() {
        @Override
        public void onFinish(boolean success) {
    
        }
    });
    

    使用saveAsync()代替save(),并且拓展一个listen()方法,当在后台将【专辑】存储到数据库后,通过回调onFinish()方法返回存储结果。

    多数据库

    如果App需要多个数据库,LitePal也是完全支持的。在运行时你可以创建多个想要的数据库。例如:

    LitePalDB litePalDB = new LitePalDB("demo2", 1);
    litePalDB.addClassName(Singer.class.getName());
    litePalDB.addClassName(Album.class.getName());
    litePalDB.addClassName(Song.class.getName());
    LitePal.use(litePalDB);
    

    上面这段代码是创建一个demo2的数据库,里面有【歌手】、【专辑】和【歌曲】三张表。

    如果你只是想创建一个新的数据库,而不想配置litepal.xml,你可以参照如下:

    LitePalDB litePalDB = LitePalDB.fromDefault("newdb");
    LitePal.use(litePalDB);
    

    你可以通过下面的操作切换回默认数据库。

    LitePal.useDefault();
    

    你也可以通过表名删除任何数据库。

    LitePal.deleteDatabase("newdb");
    

    字符串加密

    从1.6.0版本LitePal内置了对数据(字符串)进行AES或者MD5加解密的功能。

    AES:全称是Advanced Encryption Standard,中文名叫高级加密标准,同时它也是美国联邦政府采用的一种区块加密标准。

    MD5:全称是Message Digest Algorithm 5,中文名叫信息摘要算法第五版。要说到MD5加密算法的特点其实有很多很多,但是它最为突出的一个特点就是,使用这种加密算法计算出来的结果是不可逆的。通俗点来说,就是MD5算法只能进行加密但不能进行解密。

    AES

    一个书本类,类中有一个【书名】属性和一个【页数】属性,现在将【书名】属性的值进行加密,只需要在【书名】属性的上方加上@Encrypt(algorithm = AES)这样一行注解即可代码如下:

    public class Book extends DataSupport {
        @Encrypt(algorithm = AES)
        private String name;
        private int page;
        
        // getter and setter
    }
    

    对于开发者而言,加解密操作是完全透明化的。也就是说,作为开发者并不用考虑某个字段有没有被加密,然后要不要进行解密等等,我们只需要仍然使用标准的LitePal API来查询数据即可。

    比如从书本表中查询这条数据,并打印。

    Book book = DataSupport.findFirst(Book.class);
    String name = book.getName();
    int page = book.getPage();
    Log.d(TAG, "book name is " + name);
    Log.d(TAG, "book page is " + page);
    

    细节

    • 可以自定义AES算法的密钥。如果没有指定密钥,LitePal会使用默认的密钥进行加解密。使用LitePal.Key()方法来自定义密钥;

    • AES算法和MD5算法都只对String类型的字段有效,如果你尝试给其他类型的字段(比如说int字段)指定@Encrypt注解,LitePal并不会执行任何加密操作;

    • 加密后的数据字段不能再通过where语句来进行查询、修改或删除。

      也就是说,执行类似于 where("name = ?", "第一行代码") 这样的语句将无法查到任何数据,因为在数据库中存储的真实值已经不是"第一行代码"了。

    MD5

    与AES类似,加密基本是一模一样的用法,我们只需要将@Encrypt中指定的加密算法改成MD5即可。

    public class User extends DataSupport {
        @Encrypt(algorithm = MD5)
        private String password;
        private String username;
        
        // getter and setter
    }
    

    代码混淆

    如果你需要使用Proguard,可能需要添加以下代码到项目文件中。

    -keep class org.litepal.** {
        *;
    }
    
    -keep class * extends org.litepal.crud.DataSupport {
        *;
    }
    

    ProGuard是一个压缩、优化和混淆Java字节码文件的免费的工具,它可以删除无用的类、字段、方法和属性。可以删除没用的注释,最大限度地优化字节码文件。它还可以使用简短的无意义的名称来重命名已经存在的类、字段、方法和属性。常常用于Android开发用于混淆最终的项目,增加项目被反编译的难度。

    相关文章

      网友评论

        本文标题:【Android】LitePal安装和使用

        本文链接:https://www.haomeiwen.com/subject/isyarxtx.html