如何处理没有结果与Android的房间和RxJava 2?

hiz5n14c  于 2022-11-03  发布在  Android
关注(0)|答案(5)|浏览(150)

我有一个数据库表联系人,我想检查是否有一些电话号码的联系人。

@Query("SELECT * FROM contact WHERE phone_number = :number")
Flowable<Contact> findByPhoneNumber(int number);

我有RxJava 2 Composite一次性产品,上面有声明,以检查是否有电话号码联系人。

disposable.add(Db.with(context).getContactsDao().findByPhoneNumber(phoneNumber)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribeWith(new DisposableSubscriber<Contact>() {
                @Override
                public void onNext(final Contact contact) {
                    Log.d("TAG", "phone number fined");
                    Conversation conversation;
                    if(contact != null){
                        conversation = Db.with(context).getConversationsDao().findBySender(contact.getContactId());
                        if(conversation != null){
                            conversation.setUpdatedAt(Utils.getDateAndTimeNow());
                            saveConversation(contact, conversation, context, text, phoneNumber, false);
                        } else {
                            conversation = getConversation(contact, contact.getPhoneNumber());
                            saveConversation(contact, conversation, context, text, phoneNumber, true);
                        }
                    } else {
                        conversation = Db.with(context).getConversationsDao().findByPhone(phoneNumber);
                        if(conversation != null){
                            conversation.setUpdatedAt(Utils.getDateAndTimeNow());
                            saveConversation(contact, conversation, context, text, phoneNumber, false);
                        } else {
                            conversation = getConversation(contact, phoneNumber);
                            saveConversation(contact, conversation, context, text, phoneNumber, true);
                        }
                    }
                }

                @Override
                public void onError(Throwable t) {
                    Log.d("TAG", "find phone number throwable");
                    Toast.makeText(context, t.getLocalizedMessage(), Toast.LENGTH_LONG).show();
                }

                @Override
                public void onComplete() {
                    Log.d("TAG", "onComplete");
                }
            }));

如果查询可以找到具有所需电话号码的联系人,这是正常的,但如果有结果,它不会发生任何事情。
下面是我编写的两个测试用例,它们运行良好:

@RunWith(AndroidJUnit4.class)
public class ContactsTest {

    private AppDatabase db;

    @Rule
    public InstantTaskExecutorRule instantTaskExecutorRule =
            new InstantTaskExecutorRule();

    @Before
    public void initDb() throws Exception {
        db = Room.inMemoryDatabaseBuilder(
                InstrumentationRegistry.getContext(),
                AppDatabase.class)
                // allowing main thread queries, just for testing
                .allowMainThreadQueries()
                .build();
    }

    @After
    public void close(){
        db.close();
    }

    @Test
    public void insertAndFindTest(){
        final Contact contact = new Contact();
        contact.setName("Test");
        contact.setPhoneNumber(555);
        db.contactsDao()
                .insert(contact);

        db.contactsDao().findByPhoneNumber(contact.getPhoneNumber())
                .test()
                .assertValue(new Predicate<Contact>() {
                    @Override
                    public boolean test(@NonNull Contact savedContact) throws Exception {
                        if(savedContact.getPhoneNumber() == contact.getPhoneNumber()){
                            return true;
                        }
                        return false;
                    }
                });
    }

    @Test
    public void findNoValues(){
        db.contactsDao().findByPhoneNumber(333)
                .test()
                .assertNoValues();
    }

}

我怎么能解决这个问题呢?

zbdgwd5y

zbdgwd5y1#

here所述,在这种情况下可以使用MaybeSingle
也许吧

@Query("SELECT * FROM Users WHERE id = :userId")
Maybe<User> getUserById(String userId);

以下是发生的情况:

  • 当数据库中没有用户并且查询未返回行时,Maybe将完成。
  • 当数据库中有用户时,Maybe将触发onSuccess并完成。
  • 如果在完成“可能”后更新用户,则不会发生任何情况。

单个

@Query("SELECT * FROM Users WHERE id = :userId")
Single<User> getUserById(String userId);

以下是一些场景:

  • 当数据库中没有用户并且查询没有返回任何行时,Single将触发onError(EmptyResultSetException.class)
  • 当数据库中有用户时,Single将触发onSuccess。
  • 如果在调用Single.onComplete之后更新用户,则不会发生任何事情,因为流已完成。

在版本1.0.0-alpha 5中添加了此功能。

q5lcpyga

q5lcpyga2#

如果您只想使用实体一次,SingleMaybe就足够了,但是如果您想观察查询是否更新,您可以使用Flowable并将对象 Package 在List中,这样当没有结果时,您将得到空列表,之后,当数据库更新时,您将得到另一个事件,该事件结果在列表中
编码

@Query("SELECT * FROM contact WHERE phone_number = :number LIMIT 1")
Flowable<List<Contact>> findByPhoneNumber(int number)

我相信它在某些情况下是有用的。缺点是你必须访问resultList.get(0)这样的对象

c7rzv4ha

c7rzv4ha3#

当你在Dao类中使用Flowable(也是LiveData)作为返回值时,你的查询就不会停止发送数据,因为Room会监控表中的数据变化。
此外,如果响应是可观察的数据类型(如Flowable或LiveData),则Room会监视查询中引用的所有表是否失效。
我不知道处理这种情况的最好方法是什么,但对我来说,一个很好的老.timeout()操作符是有效的。请看下面的测试和评论:

@Test
public void shouldCompleteIfForced() throws InterruptedException {
    // given
    TestScheduler testScheduler = new TestScheduler();

    // when asking db for non existent project
    TestSubscriber<Project> test = projectDao.getProject("non existent project")
            .timeout(4, TimeUnit.SECONDS, testScheduler)
            .test();

    // then hang forever waiting for first emission which will never happen
    // as there is no such project
    test.assertNoValues();
    test.assertNotComplete();
    test.assertNoErrors();

    // when time passes and we trigger timeout() operator
    testScheduler.advanceTimeBy(10, TimeUnit.SECONDS);

    // then finally break stream with TimeoutException error ...
    test.assertError(TimeoutException.class);
}
uinbv5nw

uinbv5nw4#

我想你也可以用 Package 器来 Package Single。比如:

public class QueryResult<D> {
            public D data;
            public QueryResult() {}

            public QueryResult(D data) {
                this.data = data;
            }

            public boolean isEmpty(){
                return data != null;
            }
 }

并像这样使用它:

public Single<QueryResult<Transaction>> getTransaction(long id) {
            return createSingle(() -> database.getTransactionDao().getTransaction(id))
                    .map(QueryResult::new);
}

其中createAsyncSingle

protected <T> Single<T> createSingle(final Callable<T> func) {
            return Single.create(emitter -> {
                try {
                    T result = func.call();
                    emitter.onSuccess(result);

                } catch (Exception ex) {
                    Log.e("TAG", "Error of operation with db");
                }
            });
}

不要忘记使用IO线程。

unftdfkk

unftdfkk5#

@Query("SELECT * FROM contact WHERE phone_number = :number")
Flowable<List<Contact>> findByPhoneNumber(int number);

然后

Optional<Contact> queryPhone(int number) {
   findByPhoneNumber(number).map { list ->
      if (list.isEmpt()) return Optional.empty() else return Optional.of(list[0])
   }
}

如所述here
我觉得奇怪的是这种行为在官方的文件上却找不到

相关问题