美文网首页
LiveData配合RxJava

LiveData配合RxJava

作者: 风云不羁 | 来源:发表于2019-01-29 15:38 被阅读0次

    Android JetPack现在已经在android开发中大行其道,以下是个人使用LiveData与数据库查询的一点总结。

    LiveData + Room

    官方已经出了rxRoom,DAO中已经可以直接使用RxJava。这里有一个使用LiveData+Room的例子 PDFReader

    @Dao
    public interface PdfDAO {
    
        @Query("SELECT * FROM Pdf WHERE read_time != 0 ORDER BY read_time DESC")
        Flowable<List<Pdf>> getRecentPdf();
    
        @Query("SELECT * FROM Pdf WHERE read_time != 0 ORDER BY read_time DESC")
        Flowable<List<Pdf>> getAllPdf();
    
        @Query("SELECT * FROM Pdf WHERE file_path = :path LIMIT 1")
        Single<Pdf> getPdf(String path);
    
        @Insert(onConflict = OnConflictStrategy.REPLACE)
        Completable insertPdf(Pdf pdf);
    
        @Delete
        int deletePdf(Pdf pdf);
    }
    

    返回结果可以是:Maybe,Flowable,Single,其中Completeable目前只有androidx支持

    其中Flowable会一直监听数据库变化,具体如何实现的以后再分享

    于是就可以使用Flowable来实时更新界面:

    public class DocumentLiveData extends LiveData<List<Pdf>> {
        private boolean mRecentLivaData;
        private PdfDAO mPdfDao;
        private Disposable mDisposable;
    
        public DocumentLiveData(Context context, boolean recent) {
            mRecentLivaData = recent;
            mPdfDao = AppDatabase.getInstance(context).getPdfDAO();
        }
    
        @Override
        protected void onActive() {
            super.onActive();
            Flowable<List<Pdf>> flowable;
            if (mRecentLivaData) {
                flowable = mPdfDao.getRecentPdf();
            } else {
                flowable = mPdfDao.getAllPdf();
            }
    
            mDisposable = flowable.subscribeOn(Schedulers.io())
                    .subscribe(this::postValue,
                            t -> Log.e("PdfRepository", "Query pdf items failed", t));
        }
    
        @Override
        protected void onInactive() {
            if (mDisposable != null) {
                mDisposable.dispose();
                mDisposable = null;
            }
            super.onInactive();
        }
    }
    

    LiveData + RxJava + ContentProvider

    上面的方法适用与本地自建数据库,有时需要监听第三方数据库(多通过ContentProvider提供)
    以下是一个例子,查询系统CalendarProvider中有事件的天:

    public class EventDayLiveData extends MutableLiveData<List<Integer>> {
    
        private static final String[] PROJECTION = new String[]{
                Instances.START_DAY,
                Instances.END_DAY
        };
        private static final int INDEX_START_DAY = 0;
        private static final int INDEX_END_DAY = 1;
    
        public static final String SELECTION = Calendars.VISIBLE + "=1";
    
        private ContentResolver mContentResolver;
        private Handler mMainHandler;
    
        private ContentObserver mContentObserver;
    
        private PublishProcessor<Object> triggers;
        private Disposable mEventBus;
        private CompositeDisposable mQueries;
    
        // 事件加载的起始天, julianDay
        private int mStartDay;
        // 事件加载的结束天, julianDay
        private int mEndDay;
    
        private Runnable mTimeChangeUpdater = new Runnable() {
            @Override
            public void run() {
                // reload event day
                if (triggers != null) {
                    triggers.onNext("TimeChange");
                }
            }
        };
    
        public EventDayLiveData(Context content) {
            mMainHandler = new Handler(Looper.getMainLooper());
            mContentResolver = content.getApplicationContext().getContentResolver();
            mQueries = new CompositeDisposable();
            triggers = PublishProcessor.create();
    
            mContentObserver = new ContentObserver(mMainHandler) {
                @Override
                public void onChange(boolean selfChange) {
                    // reload event day
                    if (triggers != null) {
                        triggers.onNext("EventChange");
                    }
                }
            };
    
            TimeCalendar time = new TimeCalendar(1970, 0, 1);
            mStartDay = time.getJulianDay();
            time.set(2037, 11,31);
            mEndDay = time.getJulianDay();
        }
    
        @Override
        protected void onActive() {
            Timber.d("    onActive");
            // 过滤 200 毫秒内的多次加载请求
            mEventBus = triggers.throttleFirst(200, TimeUnit.MILLISECONDS)
                    .doOnNext(new Consumer<Object>() {
                        @Override
                        public void accept(Object o) throws Exception {
                            Timber.d(" receive action : %s", o.toString());
                        }
                    })
                    .subscribe(new Consumer<Object>() {
                        @Override
                        public void accept(Object o) throws Exception {
                            loadEventDays();
                        }
                    });
    
            //Utils.setMidnightUpdater(mMainHandler, mTimeChangeUpdater, TimeZone.getDefault().getID());
            mContentResolver.registerContentObserver(CalendarContract.CONTENT_URI, true, mContentObserver);
            triggers.onNext("InitValue");
        }
    
        @Override
        protected void onInactive() {
            Timber.d("    onInactive");
            mContentResolver.unregisterContentObserver(mContentObserver);
            //Utils.resetMidnightUpdater(mMainHandler, mTimeChangeUpdater);
    
            if (mQueries != null) {
                mQueries.dispose();
            }
    
            if (mEventBus != null) {
                mEventBus.dispose();
            }
        }
    
        private void loadEventDays() {
            final Disposable disposable = Observable.create(
                    new ObservableOnSubscribe<List<Integer>>() {
                        @Override
                        public void subscribe(ObservableEmitter<List<Integer>> emitter) {
                            if (emitter.isDisposed()) {
                                return;
                            }
    
                            try {
                                emitter.onNext(queryEventDay());
                                emitter.onComplete();
                            } catch (Exception e) {
                                emitter.onError(e);
                            }
                        }
                    })
                    .filter(new Predicate<List<Integer>>() {
                        @Override
                        public boolean test(List<Integer> list) {
                            // 判断数据是否变化
                            return eventDaysChanged(getValue(), list);
                        }
                    })
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Consumer<List<Integer>>() {
                        @Override
                        public void accept(List<Integer> list) {
                            setValue(list);
                        }
                    }, new Consumer<Throwable>() {
                        @Override
                        public void accept(Throwable throwable) {
                            Timber.i(throwable,"Query event day failed");
                        }
                    });
    
            mQueries.add(disposable);
        }
    
        private List<Integer> queryEventDay() {
            Uri.Builder builder = EventDays.CONTENT_URI.buildUpon();
            ContentUris.appendId(builder, mStartDay);
            ContentUris.appendId(builder, mEndDay);
            Uri uri = builder.build();
    
    
            Cursor c = mContentResolver.query(uri, PROJECTION, SELECTION, null, null);
            List<Integer> dayList = new ArrayList<>();
    
            if (c != null && c.moveToFirst()) {
                while (!c.isAfterLast()) {
                    int startDay = c.getInt(INDEX_START_DAY);
                    int endDay = c.getInt(INDEX_END_DAY);
                    if (endDay != startDay) {
                        for (int i = startDay; i <= endDay; i++) {
                            if (!dayList.contains(i)) {
                                dayList.add(i);
                            }
                        }
                    } else {
                        if (!dayList.contains(startDay)) {
                            dayList.add(startDay);
                        }
                    }
                    c.moveToNext();
                }
            }
    
            if (c != null) {
                c.close();
            }
    
            return dayList;
        }
    
        private boolean eventDaysChanged(List<Integer> oldList, List<Integer> newList) {
            if (oldList == null) {
                return true;
            }
    
            if (oldList.size() != newList.size()) {
                return true;
            }
    
            return !oldList.containsAll(newList);
        }
    }
    

    主要思路就是通过注册数据库变化来持续获取事件流丢给PublishProcessor下发到下游订阅者处理

    相关文章

      网友评论

          本文标题:LiveData配合RxJava

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