美文网首页
Android Architecture Components

Android Architecture Components

作者: JokAr_ | 来源:发表于2018-02-10 21:15 被阅读162次

最近使用了 google 新发布的框架 Android Architecture Components,使用起来很酷,不用操心数据的持久化,自动刷新等生命周期问题。但是却遇到了个问题,这个框架一起使用很爽,但是要是使用其中的几个就会遇到些问题,比如:不使用 room sql 框架把自己的数据库数据转换为 DataSource.Factory,下面介绍如何解决的:

查看了 room 源码发现了所有跟DataSource.Factory相关的数据转换都用到了LimitOffsetDataSource类,所以我们只要仿照这个类来实现我们自己的DataSource.Factory转换就行了。

Step 1

创建一个继承 PositionalDataSource的抽象类,由于我本地数据库框架用的是 DBFlow, 所以我需要传入 几个我需要的参数来实现监听数据库变化:


public abstract class LimitOffsetDataSource<T extends BaseModel> extends PositionalDataSource<T> {
    private Class<T> mClass;
    private FlowContentObserver mContentObserver;
    private Where<T> mWhere;

    protected LimitOffsetDataSource(final Class<T> aClass,
                                    Context context,
                                    Where where) {
        mClass = aClass;
        mWhere = where;
        //监听数据库改变
        mContentObserver = new FlowContentObserver(FlowManager.DEFAULT_AUTHORITY);
        mContentObserver.registerForContentChanges(context, mClass);
        mContentObserver.addContentChangeListener(new FlowContentObserver.ContentChangeListener() {
            @Override
            public void onModelStateChanged(@Nullable Class<?> table,
                                            BaseModel.Action action,
                                            @NonNull SQLOperator[] primaryKeyValues) {
                invalidate();
            }

            @Override
            public void onTableChanged(@Nullable Class<?> tableChanged,
                                       @NonNull BaseModel.Action action) {
//                invalidate();
            }
        });
    }

如上的构造函数,FlowContentObserver是为了实现当数据库数据变化时我们能改变数据,mClass,mWhere 是为了创建通用的 dbFlow 查询所需的参数。

Step 2

创建 方法返回 当前查询表里一共有多少数据:

public int countItems() {
        try {
            mContentObserver.beginTransaction();
            int size = SQLite.select()
                    .from(mClass)
                    .queryList()
                    .size();
            mContentObserver.endTransactionAndNotify();
            return size;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

Step 3

重写相关方法:

    @Override
    public boolean isInvalid() {
        mContentObserver.setNotifyAllUris(true);
        return super.isInvalid();
    }

加载初始化数据

  @Override
    public void loadInitial(@NonNull LoadInitialParams params,
                            @NonNull LoadInitialCallback<T> callback) {
        int totalCount = countItems();
        if (totalCount == 0) {
            //如果当前表数据为空直接返回
            callback.onResult(Collections.<T>emptyList(), 0, 0);
            return;
        }

        // bound the size requested, based on known count
        // 实现分页加载功能
        final int firstLoadPosition = computeInitialLoadPosition(params, totalCount);
        final int firstLoadSize = computeInitialLoadSize(params, firstLoadPosition, totalCount);
        //loadRange 是我们自己实现的数据查询方法
        List<T> list = loadRange(firstLoadPosition, firstLoadSize);
        if (list != null && list.size() == firstLoadSize) {
            callback.onResult(list, firstLoadPosition, totalCount);
        } else {
            // null list, or size doesn't match request - DB modified between count and load
            invalidate();
        }
    }

下面就是核心了,就是下面两个方法把我们本地的数据传给 LiveData,并且增加了个对外公开方法以在需要改变查询的数据所需

  
    /**
     * 提供对外数据接口方便改数据需求
     * @param dataList
     * @return
     */
    @SuppressWarnings("WeakerAccess")
    protected abstract List<T> convertData(List<T> dataList);

    /**
     * Return the rows from startPos to startPos + loadCount
     */
    @Nullable
    public List<T> loadRange(int startPosition, int loadCount) {
        mContentObserver.beginTransaction();
        List<T> ts = mWhere.
                limit(loadCount)
                .offset(startPosition)
                .queryList();
        mContentObserver.endTransactionAndNotify();
        return convertData(ts);
    }

在加载初始回调传递到分派加载初始化初始化PagedList后,将调用此方法以从DataSource加载附加页面。

  @Override
    public void loadRange(@NonNull LoadRangeParams params,
                          @NonNull LoadRangeCallback<T> callback) {
        List<T> list = loadRange(params.startPosition, params.loadSize);
        if (list != null) {
            callback.onResult(list);
        } else {
            invalidate();
        }
    }

Step5

使用:

 new DataSource.Factory<Integer, Session>() {
            @Override
            public LimitOffsetDataSource<Session> create() {
                return new LimitOffsetDataSource<Session>(Session.class,
                        context,
                        where) {
                    @Override
                    protected List<Session> convertData(List<Session> dataList) {
                        return dataList;
                    }
                };
            }
        };

这样就创建了自己的DataSource.Factory,注意这里的第一个类型只能是Integer类型,因为LimitOffsetDataSource继承的PositionalDataSource用的是Integer类型。

总结

以上就是所有了,最关键的两个核心就是

  • 增加数据库监听,数据库改变时需要调用invalidate();来刷新这个 数据model,这个很关键,否则做不到数据的自动刷新
  • 把查询的本地数据传给 DataSource,就是我们的loadRange(int startPosition, int loadCount)方法了

相关文章

网友评论

      本文标题:Android Architecture Components

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