简体   繁体   English

使用RxJava和Retrofit实现房间

[英]Implement Room with RxJava and Retrofit

I am trying to use Room with RxJava and Retrofit, Before You recommend use a component arch (In this opportunity is not possible, the project is in and 50% and Just need to continue with the arch clean). 我试图使用带有RxJava和Retrofit的房间,在你建议使用组件拱门之前(在这个机会是不可能的,项目是和50%并且只需要继续使用拱形清洁)。

So the problem is this. 所以问题是这个。 I have a web service that returns a POJO . 我有一个返回POJO的Web服务。 Something like this: 像这样的东西:

{
 "success":"true",
 "message":"message",
 "data":{[
   "id":"id",
   "name":"name",
   "lname":"lname",
 ]} 
}

POJO is more complex but for the example is ok with this. POJO更复杂,但是对于这个例子来说还可以。 I need to do that since my view make query to invoke data from room, but if there is not data in my db call my web services,the reponse of my web services transform to entity and save in my db (room) and after return a list of data to my view. 我需要这样做,因为我的视图使查询从房间调用数据,但如果我的数据库中没有数据调用我的Web服务,我的Web服务的响应转换为实体并保存在我的数据库(房间)和返回后我的视图中的数据列表。

I am using clean arch. 我正在使用干净的拱门。 I appreciate anyhelp with this. 我很感激任何帮助。 Again not trying to use 再次不尝试使用

data layout 数据布局

  • database 数据库
  • network 网络
  • repository 知识库

domain

  • interactor 交互器
  • callbacks 回调

presentation 介绍

  • presenter 主持人
  • view 视图

POJO API response POJO API响应

{
 "success":"true",
 "message":"message",
 "data":{[
   "id":"id",
   "name":"name",
   "address":"address",
   "phone":"phone",
 ]} 
}

My db entity 我的db实体

@Entity(tableName = "clients")
    public class clients {

    String id;
    String name;
    String address;
    String phone;
    String status;


    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }
}

My dao for room 我的房间

@Dao
public interface ClientsDao {

     @Insert(onConflict = OnConflictStrategy.REPLACE)
     void saveAll(List<Clients> clients);

     @Query("SELECT * FROM Clients")
     Flowable<List<Clients>> listClients();

}

RxJava help class RxJava帮助类

public class RxHelper {
private static final String TAG = RxHelper.class.getName();

@NonNull
public static <T>Observable<T> getObserbable(@NonNull final Call<T> reponse){

    return Observable.create(new ObservableOnSubscribe<T>() {
        @Override
        public void subscribe(final ObservableEmitter<T> emitter) throws Exception {

            reponse.enqueue(new Callback<T>() {
                @Override
                public void onResponse(Call<T> call, Response<T> response) {

                    if (!emitter.isDisposed()) {
                        emitter.onNext(response.body());
                    }
                }

                @Override
                public void onFailure(Call<T> call, Throwable t) {
                    if (!emitter.isDisposed()) {
                        emitter.onError(t);
                    }
                }
            });

        }
    });

}
}

My ClientsRepoFactory 我的ClientsRepoFactory

public Observable<ResponseClients> getApiClients(){
        String token = preferences.getValue(SDConstants.token);
        return RxHelper.getObserbable(apiNetwork.getClients(token));
}

My ClientsRepo 我的客户回复

@Override
public Observable<ResponseClients> listClients() {
    return factory.listClients();
}

i dont work with room but familiar with rxjava you can design your repository like that 我不在房间工作,但熟悉rxjava,你可以像这样设计你的存储库

your room interfac 你的房间接口

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

when use : 使用时:
Maybe When there is no user in the database and the query returns no rows, Maybe will complete. 也许当数据库中没有用户且查询没有返回任何行时,可能会完成。

Flowable Every time the user data is updated, the Flowable object will emit automatically, allowing you to update the UI based on the latest dat Flowable每次更新用户数据时,Flowable对象将自动发出,允许您根据最新的dat更新UI

Single When there is no user in the database and the query returns no rows, Single will trigger onError(EmptyResultSetException.class) Single当数据库中没有用户且查询没有返回任何行时,Single将触发onError(EmptyResultSetException.class)

read more about Room and RxJava this link 阅读更多关于Room和RxJava的链接

to achieve " if there is not data in db call web services " create your repository methode like that 实现“如果db调用Web服务中没有数据”,就像这样创建你的存储库方法

public Single<User> getUserById(String userId){
 return  db.getUserById(userId)
              /// if there is no user in the database get data from api
             .onErrorResumeNext(api.getUserById(userId)
              .subscribeOn(Schedulers.io())
              //check your request
              .filter(statusPojo::getStatus)
               // save data to room
              .switchMap(data -> {
              //sava data to db
              return Observable.just(data)
              })
           );

}

finally call repository method from interactor to passed obsrevable to interactor then to presentation layout 最后从交互器调用存储库方法,以便将交互式调用程序传递给显示器布局

more detail : you can inject Api and DB to your repository 更多细节:您可以将Api和DB注入您的存储库

update_Answer for reactive db if you want get last update on UI just do it : update_Answer for reactive db如果你想在UI上获得最后一次更新,请执行以下操作:

your room interface: 你的房间界面:

@Query(“SELECT * FROM Users WHERE id = :userId”)
Flowable<User> getUserById(String userId);

repository : 存储库:

   @Override
public Flowable<User> getUser(int id) {
    getUserFromNet(id);
         //first emit cache data in db and after request complete   emit last update from net 
        return db.getUserById(id);

 }


 private Flowable<User> getUserFromNet(int id){
      api.getUserById(userId)
          .subscribeOn(Schedulers.io())
          .observeOn(Schedulers.io())
          //check your request
          .filter(statusPojo::getStatus)
           // save data to room
          .subscribe(new DisposableObserver<User>() {
                @Override
                public void onNext(User user) {
                     // save data to room
                }

                @Override
                public void onError(Throwable e) {
                    Timber.e(e);
                }

                @Override
                public void onComplete() {


                }
            });
}

update_Answer2 for reactive db and " if there is not data in db call web services " according this issue is better use return a Flowable <List<T>> update_Answer2用于反应式数据库和“如果db调用Web服务中没有数据”,根据此问题最好使用返回Flowable <List<T>>

and check list size instead of Flowable<T> white swichIfEmpity because if don't any user in db Flowable<T> do'nt call onNext() and don't emite FlowableEmpity(); 并且检查列表大小而不是swichIfEmpity Flowable<T> white swichIfEmpity因为如果db Flowable Flowable<T>任何用户都没有调用onNext()并且不使用FlowableEmpity FlowableEmpity();

private Flowable<List<User>>  getUser(int id){
       return db.getUserById(id).
         /// if there is no user in the database get data from 
           .flatMp(userList-> 
           if(userList.size==0)
          api.getUserById(userId)
          .subscribeOn(Schedulers.io())
          //check your request
          .filter(statusPojo::getStatus)
           // save data to room
          .subscribe(new DisposableObserver<User>() {
                @Override
                public void onNext(User user) {
                     // save data to room
                }

                @Override
                public void onError(Throwable e) {
                    Timber.e(e);
                }

                @Override
                public void onComplete() {


                }
            });
                return Flowable.just(data)
                );
}

Kotlin way with retrofit , paging (pagingRX androidx) and room : Kotlin方式改造,分页(pagingRX androidx)和房间:

room Dao: 房间道:

@Dao
abstract class UserDao   {

@Query("SELECT * FROM users ")
abstract fun findAll(): DataSource.Factory<Int, User>
}

Repository: 库:

private fun getFromDB(pageSize:Int): Flowable<PagedList<User>> {
    return RxPagedListBuilder(userDao.findAll(), pageSize)
        .buildFlowable(BackpressureStrategy.LATEST)
}


private fun getApi(page: Int,pageSize: Int): Disposable {
    return api.getUserList("token", page = page,perPage = pageSize)
        .subscribeOn(Schedulers.io())
        .observeOn(Schedulers.io())
        .subscribe { t1: List<User>?, t2: Throwable? ->
            t1?.let {
                if (it.isNotEmpty())
                    userDao.insert(it)
            }
        }
}

override fun  findAll(page: Int ,pageSize:Int ): 
Flowable<PagedList<User>> {
    return getFromDB(pageSize).doOnSubscribe { getApi(page,pageSize) }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM