Search code examples
androidrealmdagger-2rx-androidandroid-mvp

Android: storing big size of info by realm in MVP pattern


I am trying a project with Rx, dagger,realm,retrofit in MVP pattern.I am not expert in this libraries and i do not know a lot about these libs.

In project in Scope Application i declare realm config and then get instance it for inject to my presenter.

In the first Activity called LoginActivityو As it finds it name, this activity use for login to app. I have two edittext for inserting username and pasword and i have a button for login.when the button is clicked in ViewLogin i have made an observable of clicks:

public Observable<Object> observeLoginBtn() {
    return RxView.clicks(mBinding.buttonLogin);
} 

and in LoginPresenter i have implemented this observable for login task by RX. When username and password was correct, service will return a User information as a json to client.

{
"User": {
    "Address": "     ",
    "BirthDate": "1395/09/28",
    "Email": " ",
    "EnableExpireDate": null,
    "FirstName": "kia",
    "JobLocations": {
        "AllowDomains": "9,13",
        "Altitude": "12",
    },
    "UserImage": [..]...
}

This is a part of json.By Actually by gson i have returned needed information to client. Now I want to store this information in device by realm.I have done login task by rx and when server returns user information i got this information in onNext:

        .switchMap(new Function<Response<String>, ObservableSource<UserInfo>>() {
            @Override
            public ObservableSource<UserInfo> apply(Response<String> stringResponse) throws Exception {
                String orginCookie = stringResponse.raw().header("Set-Cookie")
                        + "domain=" +
                        stringResponse.raw().header("Access-Control-Allow-Origin");
                String cookie = SerializeUtil.serializeCookie(orginCookie);
                return model.getLoginUser(info[0], cookie);
            }
        })
        .observeOn(AndroidSchedulers.mainThread())
   .subscribeWith(new DisposableObserver<UserInfo> (){
       @Override
       public void onNext(UserInfo userInfo) {

As you now onNext executes on the Ui thread. Now in this section i want to store this information by realm: First of all, i have to create a RealmObject according by user response:

public class UserInfo{
@SerializedName("User")
    private User user;
    public static UserInfo objectFromData(String str) {
        return new Gson().fromJson(str, UserInfo.class);
    }
    public User getUser() {
        return user;
    }
    public void setUser(User User) {
        this.user = User;
    }
}

Nested User class:

public class User extends RealmObject implements RealmModel {
    public User objectFromData(String str) {

        return new Gson().fromJson(str, User.class);
    }
    @SerializedName("Tel")
    private String Tel;
    @SerializedName("UserName")
    private String UserName;
    @SerializedName("UserImage")
    private RealmList<Integer> UserImage;
   @SerializedName("JobLocations")
   private JobLocations jobLocations;
    .... //getter and setter
}

Nested JobLocations class:

public class JobLocations extends RealmObject implements RealmModel {
    public static JobLocations objectFromData(String str) {
        return new Gson().fromJson(str, JobLocations.class);
    }
    @SerializedName("AllowDomains")
    private String AllowDomains;
    @SerializedName("Altitude")
    private String Altitude;
    @SerializedName("City")
    private String City;
    .... // getter and setter
}

I have created repository for insert my model to db:

public class DatabaseRealm implements IDatabaseRealm{
...
@Override
public <T extends RealmObject> T add(T model) {
    realm.beginTransaction();
    realm.copyToRealm(model);
    realm.commitTransaction();
    return model;
}

This is where ,the write is happened. This is where that i have made observable for insert my model to db:

public class TaskRepositoryImpl implements Repository<User> {
...
@Override
public Observable<User> add(final User model) {
    return Observable.create(new ObservableOnSubscribe<User>() {
        @Override
        public void subscribe(ObservableEmitter<User> emitter) throws Exception {
            try {
                databaseRealm.add(model);
                emitter.onNext(model);
                emitter.onComplete();
            }catch (Exception e) {
                emitter.onError(e);
            }
        }
    });
}

In loginPresenter in subscribeWith method that i have received my json user info i am usin realm like this:

.subscribeWith(new DisposableObserver<UserInfo> (){
               @Override
               public void onNext(UserInfo userInfo) {
                    taskRepository.add(userInfo.getUser())
                            .subscribeOn(Schedulers.trampoline())
                            .observeOn(AndroidSchedulers.mainThread())
                            .subscribe(new DisposableObserver<User>() {
                                @Override
                                public void onNext(User user) {

                                }

                                @Override
                                public void onError(Throwable e) {

                                }

                                @Override
                                public void onComplete() {

                                }
                            });

Now i have two main queastion: 1- Is the good place for storing data.I mean in onNext at subscribeWith?

2- There is a user image in response from server and it my has a large size.I think storing in realm accrue in ui thread it can make ANR error.How can i store this information on background thread in my pattern?

Excuse me that my text was long I tried to explain it perfectly and clearly.


Solution

  • 1.) I'm surprised private String UserName; is not a @PrimaryKey

    2.)

    @Override
    public <T extends RealmObject> T add(T model) {
        realm.beginTransaction();
        realm.copyToRealm(model);
        realm.commitTransaction();
        return model;
    }
    

    Could be

    @Override
    public <T extends RealmModel> Single<T> add(T model) {
        return Single.create((emitter) ->
            if(model.isManaged()) {
                return model;
            } 
            realm.executeTransactionAsync((r) -> {
                 r.insertOrUpdate(model); // if has primary key 
            }, () -> {
                emitter.onSuccess(model);
            }, (throwable) -> {
                emitter.onError(throwable);
            } 
        );
    }
    

    Or something very similar. Then you can flatMap the Single to handle the success route.