Android SqlDelight和SqlBrite无缝结合使用的Demo例子

Android SqlDelight详解和Demo例子: 点我

Android SqlBrite使用介绍和官方demo详解: 点我

Android AutoValue使用和扩展库: 点我

在说到SqlBrite的时候有介绍到它的官方的例子,官方的栗子是没有用到SqlDelight的。这里我在这个例子的基础上添加SqlDelight,实现SqlBrite和SqlDelight的无缝连接。

这里我偷个懒,fork了SqlBrite的源码,然后添加了Sqldelight的栗子的module,然后把Sqldelight和SqlBrite的代码都加了中文注释; 然后再写了了一个Module,在SqlBrite的sample的基础上无缝结合SqlDelight。

sqlbrite_sqldelight_sample的Github地址: https://github.com/tpnet/sqlbrite

结合前和结合后的对比

这里以sqlbrite_sqldelight_sample 和 sqlbrite_sample作为例子:

1. bean类对比

SqlBrite没有结合SqlDelight:

@AutoValue
public abstract class TodoList implements Parcelable {

    public static final String TABLE = "todo_list";

    public static final String ID = "_id";
    public static final String NAME = "name";
    public static final String ARCHIVED = "archived";

    public abstract long id();

    public abstract String name();

    public abstract boolean archived();

    //利用RXjava进行数据的获取,返回bean列表
    public static Func1<Cursor, List<TodoList>> MAP = new Func1<Cursor, List<TodoList>>() {
        @Override
        public List<TodoList> call(final Cursor cursor) {
            try {
                List<TodoList> values = new ArrayList<>(cursor.getCount());

                while (cursor.moveToNext()) {
                    long id = Db.getLong(cursor, ID);
                    String name = Db.getString(cursor, NAME);
                    boolean archived = Db.getBoolean(cursor, ARCHIVED);
                    values.add(new AutoValue_TodoList(id, name, archived));
                }
                return values;
            } finally {
                cursor.close();
            }
        }
    };

    //构建器,用来生成ContentValues
    public static final class Builder {
        private final ContentValues values = new ContentValues();

        public Builder id(long id) {
            values.put(ID, id);
            return this;
        }

        public Builder name(String name) {
            values.put(NAME, name);
            return this;
        }

        public Builder archived(boolean archived) {
            values.put(ARCHIVED, archived);
            return this;
        }

        public ContentValues build() {
            return values; // TODO defensive copy?
        }
    }
}

SqlBrite结合了SqlDelight之后:

@AutoValue
public abstract class TodoList implements TodoListModel,Parcelable {

public abstract class TodoList implements TodoListModel,Parcelable {

    public final static Factory<TodoList> FACTORY = new Factory<>(new  TodoListModel.Creator<TodoList>() {
        @Override
        public TodoList create(long _id, @NonNull String name, @Nullable String archived) {
            return new AutoValue_TodoList(_id, name, archived);

        }

    });

    @AutoValue
    public abstract static class ListsItem implements Parcelable, List_queryModel {

    }

    public static Func1<Cursor, ListsItem> LIST_ITEM_FUNC = new Func1<Cursor, ListsItem>() {
        @Override
        public ListsItem call(Cursor cursor) {
            return LIST_ITEM_MAPPER.map(cursor);
        }
    };

    //查询title映射
    public final static RowMapper<String> ROW_TITLE_MAPPER = FACTORY.title_queryMapper();

    public final static RowMapper<ListsItem> LIST_ITEM_MAPPER = FACTORY.list_queryMapper(new List_queryCreator<ListsItem>() {
        @Override
        public ListsItem create(long _id, @NonNull String name, long item_count) {
            return new AutoValue_TodoList_ListsItem(_id, name, item_count);
        }
    });

}

}

可以看到: 结合后的bean我们写的代码量少了,组合ContentValues这些事情不用我们手动做了,解析cursor不用我们手动做了,各种操作对象可以放在这里。

2. SQLiteOpenHelper类对比

结合前:

final class DbOpenHelper extends SQLiteOpenHelper {
    private static final int VERSION = 1;

    //创建todo_list表的语句
    private static final String CREATE_LIST = ""
            + "CREATE TABLE " + TodoList.TABLE + "("
            + TodoList.ID + " INTEGER NOT NULL PRIMARY KEY,"
            + TodoList.NAME + " TEXT NOT NULL,"
            + TodoList.ARCHIVED + " INTEGER NOT NULL DEFAULT 0"
            + ")";

    //创建todo_item表的语句
    private static final String CREATE_ITEM = ""
            + "CREATE TABLE " + TodoItem.TABLE + "("
            + TodoItem.ID + " INTEGER NOT NULL PRIMARY KEY,"
            + TodoItem.LIST_ID + " INTEGER NOT NULL REFERENCES " + TodoList.TABLE + "(" + TodoList.ID + "),"
            + TodoItem.DESCRIPTION + " TEXT NOT NULL,"
            + TodoItem.COMPLETE + " INTEGER NOT NULL DEFAULT 0"
            + ")";

    //创建 单列索引,加速查询
    private static final String CREATE_ITEM_LIST_ID_INDEX =
            "CREATE INDEX item_list_id ON " + TodoItem.TABLE + " (" + TodoItem.LIST_ID + ")";

    //构造器,创建数据库
    public DbOpenHelper(Context context) {
        super(context, "todo.db", null /* factory */, VERSION);
    }

    //创建数据库的时候回调
    @Override
    public void onCreate(SQLiteDatabase db) {
        //创建对应的表和索引
        db.execSQL(CREATE_LIST);
        db.execSQL(CREATE_ITEM);
        db.execSQL(CREATE_ITEM_LIST_ID_INDEX);

        //插入数据到todo_list表,返回id
        long groceryListId = db.insert(TodoList.TABLE, null, new TodoList.Builder()
                .name("Grocery List")
                .build());

        //根据todo_list表的id,插入数据到todo_item表,
        db.insert(TodoItem.TABLE, null, new TodoItem.Builder()
                .listId(groceryListId)
                .description("Beer")
                .build());
        db.insert(TodoItem.TABLE, null, new TodoItem.Builder()
                .listId(groceryListId)
                .description("Point Break on DVD")
                .build());
        db.insert(TodoItem.TABLE, null, new TodoItem.Builder()
                .listId(groceryListId)
                .description("Bad Boys 2 on DVD")
                .build());

        ....(和上面的套路一样这里省略了)

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }
}

结合后:

final class DbOpenHelper extends SQLiteOpenHelper {
    private static final int VERSION = 1;

    //构造器,创建数据库
    public DbOpenHelper(Context context) {
        super(context, "todo.db", null /* factory */, VERSION);
    }

    //创建数据库的时候回调
    @Override
    public void onCreate(SQLiteDatabase db) {
        //创建对应的表和索引
        db.execSQL(TodoList.CREATE_TABLE);
        db.execSQL(TodoItem.CREATE_TABLE);
        db.execSQL(CREATE_ITEM_LIST_ID_INDEX);

        //初始化插入实体
        TodoList.Insert_list insertList = new TodoListModel.Insert_list(db);
        TodoItem.Insert_item insertItem = new TodoItemModel.Insert_item(db);

        //插入数据到todo_list表,返回id
        insertList.bind("Grocery List", "0");
        long groceryListId = insertList.program.executeInsert();

        //根据todo_list表的id,插入数据到todo_item
        insertItem.bind(groceryListId, "Beer", false);
        insertItem.program.executeInsert();

        insertItem.bind(groceryListId, "Point Break on DVD", false);
        insertItem.program.executeInsert();

        insertItem.bind(groceryListId, "Bad Boys 2 on DVD", false);
        insertItem.program.executeInsert();

        ...(和上面的套路一样,这里省略)

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }
}

可以看到: 结合后的SQLiteOpenHelper sql语句不用组合放在这里,清晰多了; 创表语句放在sq文件中,在自动生成的model,也可以得到创表的语句; 插增删改查利用bind来实现,更方便了,不用自己组合ContentValue,逻辑清晰,代码简介。

3. 查询对比

结合前:

subscription = db.createQuery(ListsItem.TABLES, ListsItem.QUERY)
                .mapToList(ListsItem.MAPPER)   //映射到ListItem的MAPPER
                .observeOn(AndroidSchedulers.mainThread()) //设置订阅者在主线程进行
                .subscribe(adapter);

static Func1<Cursor, ListsItem> MAPPER = new Func1<Cursor, ListsItem>() {
        @Override
        public ListsItem call(Cursor cursor) {
            long id = Db.getLong(cursor, TodoList.ID);
            String name = Db.getString(cursor, TodoList.NAME);
            int itemCount = Db.getInt(cursor, ITEM_COUNT);
            return new AutoValue_ListsItem(id, name, itemCount);
        }
    };

结合后:

//创建查询
SqlDelightStatement sqLiteStatement = TodoList.FACTORY.list_query();

subscription = db.createQuery(TodoList.TABLE_NAME, sqLiteStatement.statement, sqLiteStatement.args)
        .mapToList(TodoList.LIST_ITEM_FUNC)   //映射到ListItem的MAPPER
        .observeOn(AndroidSchedulers.mainThread()) //设置订阅者在主线程进行
        .subscribe(adapter);

public static Func1<Cursor, ListsItem> MAPPER = new Func1<Cursor, ListsItem>() {
        @Override
        public ListsItem call(Cursor cursor) {
            return LIST_ITEM_MAPPER.map(cursor);
        }
    };

可以看到结合后的Curor解析不用我们手动解析,对应的查询语句和参数可以在SqlDelightStatement获取。

4. 更新添加对比

结合前:

Observable.combineLatest(createClicked, RxTextView.textChanges(name),
                new Func2<String, CharSequence, String>() {
                    @Override
                    public String call(String ignored, CharSequence text) {
                        return text.toString();
                    }
                }) //
                .observeOn(Schedulers.io())
                .subscribe(new Action1<String>() {
                    @Override
                    public void call(String description) {
                        db.insert(TodoItem.TABLE,
                                new TodoItem.Builder().listId(getListId()).description(description).build());
                    }
                });

结合后:

Observable.combineLatest(createClicked, RxTextView.textChanges(name),
                new Func2<String, CharSequence, String>() {
                    @Override
                    public String call(String ignored, CharSequence text) {
                        return text.toString();
                    }
                }) //
                .observeOn(Schedulers.io())
                .subscribe(new Action1<String>() {
                    @Override
                    public void call(String description) {

                        //初始化插入对象
                        TodoItemModel.Insert_item insertItem = new TodoItemModel.Insert_item(db.getWritableDatabase());

                        //填入数据
                        insertItem.bind(getListId(), description, false);
                        //开始插入,这里会Rxjava会异步回调,进行更新列表
                        db.executeInsert(insertItem.table, insertItem.program);

                        //注意这里不要使用下面的插入代码,会导致Rxjava不能异步回调发送数据
                        //insertItem.program.executeInsert();

                    }
                });

可以看到结合后:利用了SqlDelight生成的对应的Model类进行更新插入,不需要自己编写ContentValue,更方便的插入。

当然还有其他的变化。大家可以看看源码。

时间: 2024-10-11 11:14:28

Android SqlDelight和SqlBrite无缝结合使用的Demo例子的相关文章

Android SqlDelight详解和Demo例子

一.简介 SQLDelight 和 SqlBrite 是 Square 公司推出的一个 Android 平台数据库解决方案. 在了解这个两个东西前,必须先得有Andorid的Sqlite的知识(SqliteDatabase and SqliteDataHelper),还有AutoValue , AutoValue教程 要分清他们两个的功能: SqlDelight 是用来把Sql语句生成Java对象的 SqlBrite 才是Sqlite操作,结合Rxjava进行响应式数据库操作. 二.SqlDel

Android中Service的一个Demo例子

Android中Service的一个Demo例子  Service组件是Android系统重要的一部分,网上看了代码,很简单,但要想熟练使用还是需要Coding.  本文,主要贴代码,不对Service做过多讲解.  代码是从网上找的一个例子,Copy下来发现代码不完全正确,稍微修改了下.  AndroidManifest.xml <application android:icon="@drawable/ic_launcher" android:label="@stri

android 支持分组和联系人展示的一个小例子

先看效果图: 要实现这个效果,activity必须实现ExpandableListActivity @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.main); mContactListView = getExpa

android中activity可以响应外部的action的例子(可以用这个来导入外部文件)

如果我们在文件浏览器中点击一个文件,然后点击它,会弹出一个列表给你选择 如果使自己的应用也出现在这个列表上,必须在menifest的这个activity下加入: <activity android:name="com.example.clickabletextview.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name

Android多点触控(图片的缩放Demo)

本文主要介绍Android的多点触控,使用了一个图片缩放的实例,来更好的说明其原理.需要实现OnTouchListener接口,重写其中的onTouch方法. 实现效果图: 源代码: 布局文件: activity_main: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools&quo

Android Service demo例子使用详解

Android Service demo例子使用详解\ 概述Service 是 Android 的四大组件之一,它主要的作用是后台执行操作,Activity 属于带有 UI 界面跟用户进行交互,而 Service 则没有 UI 界面,所有的操作都是基于后台运行完成.并且 Service 跟 Activity 一样也是可以由其它的应用程序调用启动的,而且就算用户切换了应用程序,Service 依旧保持运行.一个组件如果与 Service 进行了绑定( bind ),就可以跟 Service 进行数

Android主题换肤 无缝切换

2016年7月6日 更新:主题换肤库子项目地址:ThemeSkinning,让app集成换肤更加容易.欢迎star以及使用,提供改进意见. 更新日志: v1.3.0:增加一键切换切换字体(初版)v1.2.1:完善之前版本View的创建v1.2.0:增加对换肤属性自定义扩展v1.1.0:可以直接加载网络上的皮肤文件 今天再给大家带来一篇干货. Android的主题换肤 ,可插件化提供皮肤包,无需Activity的重启直接实现无缝切换,可高仿网易云音乐的主题换肤. 这个链接是本次的Demo打包出来的

Android中Fragment和Activity之间的互操作代码例子

摘要 本文介绍了Android中一个Activity中有多个Fragment的情况下,Fragment之间如何通过Activity进行互操作. 源代码 源代码地址为:http://download.csdn.net/detail/logicteamleader/8931199 源代码使用ADT编写,ADT版本为2014,Android版本为android-22. 技术要点 1.在Activity中的多个Fragment之间要互操作,一定要通过此Activity,不能直接通信: 2.在Activi

Android JSON数据的解析与封装小Demo

今天早早的下班了,写了一个简单的JSON Demo,这里总结一下. 首先是效果图: 简单起见,解析部分并没有采用解析URL的方式,直接把JSON写到String里,逻辑比较简单,这里就不啰嗦了,上代码: package com.example.jsondemo; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.app.Activity; imp