My project using clean architecture. In this situation, the UI layer is separate from Domain layer. So I think it would be better the UI layer doesn't own realm instance. As realm's doc recommend managing the realm instance in Activity's lifecycle, how should I deal with the realm instance then?
To be more clear, my project is too heavy to change all objects extends RealmObject. So I use separate object to persistent data. When the api call finish, a business object convert to a realm object, opposite when query from realm. I create the method like this:
public void insert(T object){
final Realm realm = RealmProvider.getRealm();
realm.executeTransactionAsync(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
realm.copyToRealmOrUpdate(createRealmObject(object));
}
}, new Realm.Transaction.OnSuccess() {
#Override
public void onSuccess() {
realm.close();
}
}, new Realm.Transaction.OnError() {
#Override
public void onError(Throwable error) {
realm.close();
}
});
}
Actually, it works fine. But below I don't know how to handle closing realm instance.
public Observable<T> queryAsync(Condition<? extends RealmObject> condition) {
final Realm realm = RealmProvider.getRealm();
return condition.getQuery(realm).findFirstAsync()
.asObservable()
.filter(new Func1<RealmObject, Boolean>() {
#Override
public Boolean call(RealmObject realmObject) {
return realmObject.isLoaded();
}
})
.map(new Func1<RealmObject, T>() {
#Override
public T call(RealmObject realmObject) {
return createObjectFromRealm(realmObject);
}
});
}
If you want a clean separation between UI and database layers in your code, and you want to abstract away your database logic so that ideally your activity can call database layer without knowing how that layer is implemented, then Realm is probably not what you're looking for.
Realm objects are tied to realm instances which means that if you retrieve an object from a realm instance and then close that instance (which you must), you can no longer use the object. Which defeats the entire purpose of using Realm.
If you are going to use Realm, you should keep the realm logic closely tied to your activities/services etc, and don't try to hide it in a separate layer, so that you have full control over it.
.map(new Func1<RealmObject, T>() {
#Override
public T call(RealmObject realmObject) {
Object o = createObjectFromRealm(realmObject);
realm.close();
return o;
}
});
One of the major aspect of a clean architecture is, isolation of major libraries (i.e. Realm). Since Realm, RealmObject, RealmResults are not accessible outside of the Thread they are created in, it makes it even more important to keep Realm & Realm related calculations isolated from rest of the code.
You are using RxJava in your queryAsync() method, and at the same time you are using executeTransactionAsync() method, which defies the whole purpose of using RxJava. You could have done like this,
public void insert(T object){
final Realm realm = RealmProvider.getRealm();
realm.executeTransaction(realm1 ->
realm1.copyToRealmOrUpdate(createRealmObject(object)));
realm.close();
}
In a good Architecture, for each jsonModel class there should be a corresponding realmModel class & a DAO (Data Access Object). DAO class must take jsonModel as argument and must return jsonModel as result. All Realm related operations must be restricted within the DAO file, that way none of the code other than DAO and realmModel knows about Realm.
Here is an article about Realm best practices with a good architechture https://medium.com/#Viraj.Tank/realm-integration-in-android-best-practices-449919d25f2f
Also a sample project demonstrating Integration of Realm on Android with MVP(Model View Presenter), RxJava, Retrofit, Dagger, Annotations & Testing.
https://github.com/viraj49/Realm_android-injection-rx-test
Related
I have a JSON file in the assets folder and DataManager(repository) class needs it so assetManager(and context) should have access to the assets.
The problem is that based on Best practice, Android context or android specific code should not be passed into the data layer(ViewModel-Repo-Model) because of writing unit tests or etc easily and also view should not interact with the data layer directly.
I ended up providing the list using and injecting it to the repository.
Is this the right thing to do?
-Thanks
P.S: my Module class which provides the list
#Module
public class UtilModule {
#Provides
#JsonScope
JsonUtil provideJsonUtil(AssetManager assetManager){
return new JsonUtil(assetManager);
}
#Provides
#JsonScope
String provideJson(JsonUtil util){
return util.getJson();
}
#Provides
#JsonScope
Type provideType(){
return new TypeToken<List<Data>>() {}.getType();
}
#Provides
#JsonScope
DataManager provideDataManager (Gson gson, Type type,String json) {
return new DataManager (gson.fromJson(json, type));
}
}
It's not a violation of MVVM for a ViewModel and/or Repository to access the Application context directly, which is all you need to access the AssetsManager. Calling Application.getAssets() is OK because the ViewModel doesn't use any particular Activity's context.
For example, you can use the Google-provided AndroidViewModel subclass instead of the superclass ViewModel. AndroidViewModel takes an Application in its constructor (ViewModelProviders will inject it for you). You could pass your Application to your Repository in its constructor.
Alternately, you could use Dagger dependency injection to inject an Application directly into your Repository. (Injecting the Application context is a bit tricky. See Dagger 2 injecting Android Context and this issue filed on the Danger github repo.) If you want to make it really slick, you could configure a provider for AssetManager and inject it directly into your Repository.
Finally, if you are using Room, and all you want is to pre-populate your Room database with a pre-configured database stored in assets, you can follow instructions here: How to use Room Persistence Library with pre-populated database?
Since you are using MVVM for the first time, we can try to keep things simple.
[ View Component C] ---- (observes) [ ViewModel Component B ] ---- [ Repository ]
According to the Separation of Concerns rule, the ViewModel should expose LiveData. LiveData uses Observers to observe data changes. The purpose of the ViewModel is to separate the data layer from UI. ViewModel should not know about Android framework classes.
In MVVM Architecture, the ViewModel's role is to fetch data from a Repository. You can consider either storing your json file as a local data source using Room, or keeping the Json API as a remote data source. Either way, the general implementation is as follows:
Component A - Entity (implements your getters & setters)
Method 1: Using Room
#Entity(tableName = "file")
public class FileEntry{
#PrimaryKey(autoGenerate = true)
private int id;
private String content; // member variables
public FileEntry(String content){ // constructor
this.id = id;
this.content = content;
}
public int getId(){ // getter methods
return id;
}
public void setId(int id){ // setter methods
this.id = id;
}
public String getContent(){
return content;
}
public void setContent(String content){
this.content = content;
}
}
Method 2: Using Remote Data Source
public class FileEntry implements Serializable{
public String getContent(){
return content;
}
private String content;
}
Component B - ViewModel (Presentation Layer)
Method 1: Using Room
As you asked about how android context can be passed, you can do so by extending AndroidViewModel like below to include an application reference. This is if your database requires an application context, but the general rule is that Activity & Fragments should not be stored in the ViewModel.
Supposing you have "files" as a member variable defined for your list of objects, say in this case, "FileEntry" objects:
public class FileViewModel extends AndroidViewModel{
// Wrap your list of FileEntry objects in LiveData to observe data changes
private LiveData<List<FileEntry>> files;
public FileViewModel(Application application){
super(application);
FilesDatabase db = FilesDatabase.getInstance(this.getApplication());
Method 2: Using Remote Data Source
public class FileViewModel extends ViewModel{
public FileViewModel(){}
public LiveData<List<FileEntry>> getFileEntries(String content){
Repository repository = new Repository();
return repository.getFileEntries(content);
}
}
In this case, getFileEntries method contains MutableLiveData:
final MutableLiveData<List<FileEntry>> mutableLiveData = new MutableLiveData<>();
If you are implementing using Retrofit client, you can do something similar to below code using asynchronous callbacks. The code was taken from Retrofit 2 Guide at Future Studio with some modifications for this discussion example.
// asynchronous
call.enqueue(new Callback<ApiData>() {
#Override
public void onResponse(Call<ApiData> call, Response<ApiData> response) {
if (response.isSuccessful()) {
mutableLiveData.setValue(response.body().getContent());
} else {
int statusCode = response.code();
// handle request errors yourself
ResponseBody errorBody = response.errorBody();
}
}
#Override
public void onFailure(Call<ApiData> call, Throwable t) {
// handle execution failures like no internet connectivity
}
return mutableLiveData;
Component C - View (UI Controller)
Whether you are using Method 1 or 2, you can do:
FileViewModel fileViewModel = ViewModelProviders.of(this).get(FileViewModel.class);
fileViewModel.getFileEntries(content).observe(this, fileObserver);
Hope this is helpful.
Impacts on Performance
In my opinion, deciding whether to use which method may hinge on how many data calls you are implementing. If multiple, Retrofit may be a better idea to simplify the API calls. If you implement it using Retrofit client, you may have something similar to below code taken as provided from this reference article on Android Guide to app architecture:
public LiveData<User> getUser(int userId) {
LiveData<User> cached = userCache.get(userId);
if (cached != null) {
return cached;
}
final MutableLiveData<User> data = new MutableLiveData<>();
userCache.put(userId, data);
webservice.getUser(userId).enqueue(new Callback<User>() {
#Override
public void onResponse(Call<User> call, Response<User> response) {
data.setValue(response.body());
}
});
return data;
}
The above implementation may have threading performance benefits, as Retrofit allows you to make asynchronous network calls using enqueue & return the onResponse method on a background thread. By using method 2, you can leverage Retrofit's callback pattern for network calls on concurrent background threads, without interfering with the main UI thread.
Another benefit of the implementation above is that if you are making multiple api data calls, you can cleanly get the response through an interface webservice above, for your LiveData. This allows us to mediate responses between different data sources. Then, calling data.setValue sets the MutableLiveData value & then dispatches it to active observers on the main thread, as per Android documentation.
If you are already familiar with SQL & only implementing 1 database, opting for the Room Persistence Library may be a good option. It also uses the ViewModel, which brings performance benefits since chances of memory leaks are reduced, as ViewModel maintains fewer strong references between your UI & data classes.
One point of concern may be, is your db repository (example, FilesDatabase implemented as a singleton, to provide a single global point of access, using a public static method to create the class instance so that only 1 same instance of the db is opened at any one time? If yes, the singleton might be scoped to the application scope, & if the user is still running the app, the ViewModel might be leaked. Thus make sure your ViewModel is using LiveData to reference to Views. Also, it might be helpful to use lazy initialization so that a new instance of the FilesDatabase singleton class is created using getInstance method if there are no previous instances created yet:
private static FilesDatabase dbInstance;
// Synchronized may be an expensive operation but ensures only 1 thread runs at a time
public static synchronized FilesDatabase getInstance(Context context) {
if (dbInstance == null) {
// Creates the Room persistent database
dbInstance = Room.databaseBuilder(context.getApplicationContext(), FilesDatabase.class, FilesDatabase.DATABASE_NAME)
Another thing is, no matter your choice of Activity or Fragment for your UI, you will be using ViewModelProviders.of to retain your ViewModel while a scope of your Activity or Fragment is alive. If you are implementing different Activities/Fragments, you will have different instances of ViewModel in your application.
If for example, you are implementing your database using Room & you want to allow your user to update your database while using your application, your application may now need the same instance of the ViewModel across your main activity and the updating activity. Though an anti-pattern, ViewModel provides a simple factory with an empty constructor. You can implement it in Room using public class UpdateFileViewModelFactory extends ViewModelProvider.NewInstanceFactory{:
#Override
public <T extends ViewModel> T create(#NotNull Class<T> modelClass) {
return (T) new UpdateFileViewModel(sDb, sFileId);
Above, T is a type parameter of create. In the factory method above, the class T extends ViewModel. The member variable sDb is for FilesDatabase, and sFileId is for the int id that represents each FileEntry.
This article on Persist Data section by Android may be more useful than my comments if you would like to find out more, on performance costs.
Okay, so I just started a new Android project and wanted to try implementing the Clean Architecture by Uncle Bob. I have a nice beginning using RxJava and stuff from GitHub samples & boilerplates and Fernando Cerjas' blog (like this article), but still have some questions on how to implement some UseCases.
TL;DR
Should an Entity have fields that are another Entity (in my example, User having a List<Messages> field)?
Or should the Presenter combine UseCases to build a ViewModel mapped on multiple Entities (then how to you code the mapper?)?
Or should the Presenter have a ViewModel associated to each UseCase/Entity, and create some kind of "wait for all data to onNext" to call the view.show() for each ViewModel?
Basically, should UseCases only return Entities? Can an Entity be composed of other entities (as in a field of the class)? Are Entities only dumb datamodels POJOs? How to you represent 'join SQL' queries?
As an example, let's take a simple users/messages app.
I want to implement two views: UserList and UserDetails:
UserList displays a list of Users
UserDetails displays a user's information and its latest messages.
UserList is pretty straightforward, and I can see how to code the associated UseCase and layers (code below).
My problem is with the UserDetails screen.
How should I code my GetUserInfoUseCase if I want all the data to be passed at the view at the same time (like building a ViewModel composed of a User class, with a field List)? What should be the return value of the GetUserInfoUseCase?
Should I code a Observable<User> GetUserInfoUseCase and a Observable<List<Message>> GetUserLatestMessages and merge them somehow in my presenter? If yes, how can I manage this, as I don't have the Observables in my Presenter (I'm passing only an Observer as my UseCases parameters)?
User Entity
public abstract class User {
public abstract long id();
public abstract String name();
...
}
Message Entity
public abstract class Message {
public abstract long id();
public abstract long senderId();
public abstract String text();
public abstract long timstamp();
...
}
GetUsersUseCase
public class GetUsersUseCase extends UseCaseObservableWithParameter<Boolean, List<User>, UsersRepository> {
#Inject
public GetUsersUseCase(UsersRepository UsersRepository,
#Named("Thread") Scheduler threadScheduler,
#Named("PostExecution") Scheduler postExecutionScheduler) {
super(usersRepository, threadScheduler, postExecutionScheduler);
}
#Override
protected Observable<List<User>> buildObservable(Boolean forceRefresh) {
if(forceRefresh)
repository.invalidateCache();
return repository.getUsers();
}
}
UsersPresenter
public class UsersPresenter extends BasePresenter<UsersContract.View> implements UsersContract.Presenter {
#Inject
GetUsersUseCase mGetUsersUseCase;
#Inject
UserViewModelMapper mUserMapper;
#Inject
public UsersPresenter() {
}
#Override
public void attachView(UsersContract.View mvpView) {
super.attachView(mvpView);
}
#Override
public void detachView() {
super.detachView();
mGetUsersUseCase.unsubscribe();
}
#Override
public void fetchUsers(boolean forceRefresh) {
getMvpView().showProgress();
mGetUsersUseCase.execute(forceRefresh, new DisposableObserver<List<User>>() {
#Override
public void onNext(List<User> users) {
getMvpView().hideProgress();
getMvpView().showUsers(mUsersMapper.mapUsersToViewModels(users));
}
#Override
public void onComplete() {
}
#Override
public void onError(Throwable e) {
getMvpView().hideProgress();
getMvpView().showErrorMessage(e.getMessage());
}
});
}
}
UseCaseObservableWithParameter
public abstract class UseCaseObservableWithParameter<REQUEST_DATA, RESPONSE_DATA, REPOSITORY> extends UseCase<Observable, REQUEST_DATA, RESPONSE_DATA, REPOSITORY> {
public UseCaseObservableWithParameter(REPOSITORY repository, Scheduler threadScheduler, Scheduler postExecutionScheduler) {
super(repository, threadScheduler, postExecutionScheduler);
}
protected abstract Observable<RESPONSE_DATA> buildObservable(REQUEST_DATA requestData);
public void execute(REQUEST_DATA requestData, DisposableObserver<RESPONSE_DATA> useCaseSubscriber) {
this.disposable.add(
this.buildObservable(requestData)
.subscribeOn(threadScheduler)
.observeOn(postExecutionScheduler)
.subscribeWith(useCaseSubscriber)
);
}
}
UseCase
public abstract class UseCase<OBSERVABLE, REQUEST_DATA, RESPONSE_DATA, REPOSITORY> {
protected final REPOSITORY repository;
protected final Scheduler threadScheduler;
protected final Scheduler postExecutionScheduler;
protected CompositeDisposable disposable = new CompositeDisposable();
public UseCase(REPOSITORY repository,
#Named("Thread") Scheduler threadScheduler,
#Named("PostExecution") Scheduler postExecutionScheduler) {
Timber.d("UseCase CTOR");
this.repository = repository;
this.threadScheduler = threadScheduler;
this.postExecutionScheduler = postExecutionScheduler;
}
protected abstract OBSERVABLE buildObservable(REQUEST_DATA requestData);
public boolean isUnsubscribed() {
return disposable.size() == 0;
}
public void unsubscribe() {
if (!isUnsubscribed()) {
disposable.clear();
}
}
}
Quite a lot questions within a single question. let me try to consolidate what I think I understood are ur key questions
Can Entities reference each other? the answer would be: YES. Also in
Clean Architecture u can create a domain model where entities are interconnected
What should be returned from a UseCase?
Answer: UseCases define input DTOs (Data transfer objects) and output DTOs which are most convenient for the use case. in his book uncle bob writes that entities should not be passed to use cases or returned from use cases
What is the role of the presenter then? Answer: ideally a presenter is converting data only. It converts data which is most convenient for one layer into data which is most convenient for the other layer.
hope this guidance helps u to answer ur detailed questions
More details and examples you can find in my recent posts:
https://plainionist.github.io/Implementing-Clean-Architecture-UseCases/
and
https://plainionist.github.io/Implementing-Clean-Architecture-Controller-Presenter/
Basically, you want to push your "instrumental" aware code as far as possible (on the circle).
Use cases are very close to the model and contain a lot of business logic - you want this layer very clean to be able to do quick and easy unit tests. So, this layer shouldn't know anything about storage.
But the fun part is when Room enters the room :) Room makes it so easy to have model-like objects that you can use around and IMO it's a grey area should you use Room annotated classes for your model or not.
If you think about Room objects as Data Layer objects, then you should map them to your business objects before reaching use cases.
If you use Room as a built-in mapper of DAO to model objects, then IMO you can use them in your use cases, although clean purists probably would not agree on this.
My pragmatic advice would be - if your model has a complex structure built in from multiple entities then have a dedicated model class for it and map entities to it.
If you have something like an Address, IMO just go with the Room entity.
New to RxJava and I have question about interface callbacks ( called from inner layer/module of code through interface variable) vs RxJava.
To make it more clear, quick example:
Standard callback interface implementation, interface, class A and B
interface CustomCallback {
void onCallbackCalled(String str);
}
class ClassA {
private ClassB classB;
public ClassA() {
classB = new ClassB(new CustomCallback() {
#Override
public void onCallbackCalled(String str) {
System.out.println("Callback called " + str);
}
});
}
}
class ClassB {
private CustomCallback customCallback;
public ClassB(CustomCallback callback) {
customCallback = callback;
}
private void somethingHappened() {
customCallback.onCallbackCalled("method somethingHappened");
}
}
When classB method "somethingHappened" is called, result is: "Callback called method somethingHappened".
Interface's method onCallbackCalled(String str) can be called from classB as many times as I want.
CLASS A ↓ ............................................ injection of interface through constructor
CLASS B................↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ onCallbackCalled(...) 0...n number
Now RxJava. 99% of cases which I find.
class ClassA {
private ClassB classB;
public ClassA() {
classB = new ClassB();
}
public void rxJavaMethod() {
DisposableObserver<String> observer = classB.getObservable()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableObserver<String>() {
#Override
public void onNext(String s) {}
#Override
public void onError(Throwable e) {}
#Override
public void onComplete() {}
});
}
}
class ClassB {
private Observable<String> getObservable() {
return Observable.just(can be different from "just", for sake of example);
}
}
Scheme is:
CLASS A ↓........................ one call for getting Observable resource
CLASS B................↑ EDIT returns observable which emits 0...n values
So basically you call from top layer ( in this example) and you get response about state from inner layer.
QUESTIONS:
1) What in case when you have a model ( inner layer) which is changing dynamically ( but not any kind of AsyncTask etc.), and you want to notify top layer ( UI for example) that state has changed ( good example: game).
2) Is there any kind of "bridge" class in RxJava library ( I think about it as "subscribe to it, then you can pass arguments to it as many times as you want and information/observable will be emitted to subscribers).
3) Is there any sense and advanatage of trying to do that instead of standard interface callbacks ( in case like above, not " click button, get response once")
UPDATE, ANSWER BASED ON EXAMPLE ABOVE
As Bob Dalgleish mentioned, way of making such bridge is by using one of the class extending Subject<T> rxjava.
http://reactivex.io/documentation/subject.html
class ClassA {
private ClassB classB;
public ClassA() {
classB = new ClassB();
}
public void rxJavaMethod() {
DisposableObserver<String> observer = classB.getCallbackSubjectRx()
.subscribeWith(new DisposableObserver<String>() {
#Override
public void onNext(String s) {}
#Override
public void onError(Throwable e) {}
#Override
public void onComplete() {}
});
}
}
class ClassB {
private BehaviorSubject<String> mCallbackRx;
public ClassB() {
mCallbackRx = BehaviorSubject.create();
}
// method somethingHappened can be invoked whenever whe want and
// it will send given parameter to all subscribers
private void somethingHappened() {
mCallbackRx.onNext("method somethingHappened");
}
// multiple subscribers allowed
public BehaviorSubject<String> getCallbackSubjectRx() {
return mCallbackRx;
}
}
Downside might be, that if we want to use one "bridge" to handle multiple callback types ( interface have methods, we use only one method: "onNext()"), we might need to create wrapper class with callback parameters. Which isn't big problem in my opinion.
On the other hand, we get access to all of RxJava operators.
http://reactivex.io/documentation/operators.html
( Example above is for RxJava2, where Disposable is basically Subscription from RxJava1).
The first thing to note is that
CLASS B................↑ returns 0...n observables to observer
is not true. Class B returns an observable, on which it will occasionally emit 0..n values.
(the question is not clear). The inner observable, from class B, is changing state for whatever reason. The most common reason is that another process/task/thread is feeding it, and you want to display the resulting state in the UI.
A simple type of "bridging" class that I use all the time any of the several Subject<> classes. You can emit new values to them using .onNext() and the subscribers will get those values.
If callback interfaces were all standardized, then they would have some advantage, but they vary all over the place. You have to remember that you need some particular interface for this thing you are looking at and and a different one for the other thing. While UI events tend to be quite uniform these days, trying to mix UI events and network events and database events will still leave you feeling overwhelmed. Having a much smaller class of interfaces, mostly encapsulated inside of the rxJava generic classes, makes composing functionality much easier.
Edit: Improve example code.
There is a good article from Yammer Engineering on using Observable.create() (formerly Observable.fromEmitter(), formerly Observable.fromAsync(). The important points he makes are
Using Observable.create() handles the subscription step for you by registering a listener to the underlying interface. More importantly, it arranges to de-register the listener when the unsubscribe() occurs.
Out of the box, this code handles multiple subscribers, each of which receives its own observable stream of data.
As I mentioned above, the listener protocol is particular to the thing you register with. If that thing supports only a single listener, then you will likely want to introduce a Subject that subscribes to the thing under observation, and all your other observers subscribe to the subject.
End of edit.
My favorite example of composition of solutions is the distinctUntilChanged() operator. Because it is an operator that works on a generic observable, it encapsulates the stateful property of saving consecutive values for comparison and only emitting differing ones. I use it frequently for logging state changes. To achieve the same end using standard callback interfaces would require adding a different interface for saving prior values to every existing interface.
So, yes, most of the time it is worth using the rxJava approach of observables, simply for the sake of not having to remember which of the many call back protocols might be applicable in the current case.
I used to work with un-auto-managed model objects that were copied from Realm. I switched to using auto-managed Realm object for my new projects and have a problem.
Where before I could keep my DB logic separate, in DAO classes, right now, the Realm code is all over my application.
Realm objects should be managed (closed) well, everywhere, on every thread, on every activity and fragment. But what I dislike most: every setter on every model object needs to be in a Realm transaction. There is Realm all over my code right now!
Did anyone find a way to keep the DB logic somewhat separate, while using auto managed Realm objects?
Conclusion, after a few months with Realm auto-managed objects:
Having your database code centralised, in Data Access Object (DAO) classes or the like, is hardly possible when using Realm’s auto-updated objects.
Every setter on every model object needs to be inside a Realm transaction block. If you use RetroLambda, the calls are relatively clean:
realm.executeTransaction(r -> user.setFirstName(firstName));
These blocks will be all over your project within no time. Forgetting to wrap a setter method (or a constructor call) in a transaction will crash your app. Believe me, this will happen a lot in the first weeks of adopting auto-updated objects.
Auto-updated objects cannot be shared across threads. The same is true for Realm instances.
All threads, and often activities and fragments, will have to open and close Realm instances. You’ll be thinking constantly “On which thread am I?”. If you cross thread boundaries with model objects or Realm instances, you will crash your app.
More info here: https://medium.com/#ffvanderlaan/realm-auto-updated-objects-what-you-need-to-know-b2d769d12d76
and here: https://medium.com/#Zhuinden/how-to-use-realm-for-android-like-a-champ-and-how-to-tell-if-youre-doing-it-wrong-ac4f66b7f149#.gazrajqwt
What I did was created a RealmController class that handles all of my Realm transactions, and fetches new data from the API. The skeleton for the implementation is borrowed from another SO post which I can't find right now, but you should be able to find it on Google by searching RealmController.
public class RealmController {
private static RealmController instance;
private final Realm realm;
private ServiceInterface restInterface;
private final String TAG = "RealmController";
private static boolean browseFetchAllowed = true;
private RealmConfiguration config = new RealmConfiguration.Builder()
.name("myRealm")
.schemaVersion(0)
.deleteRealmIfMigrationNeeded()
.build();
public RealmController(Application application) {
restInterface = ServiceGenerator.createService(ServiceInterface.class);
realm = Realm.getInstance(config);
}
public void setAuthentication(String token, String uid) {
this.restInterface = ServiceGenerator.createService(ServiceInterface.class, token, uid);
}
public static RealmController with(Fragment fragment) {
if (instance == null) {
instance = new RealmController(fragment.getActivity().getApplication());
}
return instance;
}
public static RealmController with(Activity activity) {
if (instance == null) {
instance = new RealmController(activity.getApplication());
}
return instance;
}
public static RealmController with(Application application) {
if (instance == null) {
instance = new RealmController(application);
}
return instance;
}
public RealmController getInstance() {
return instance;
}
public ServiceInterface getRestInterface() {
return restInterface;
}
public Realm getRealm() {
return realm;
}
public RealmResults<MyRealmObject> getStuff() {
return realm.where(MyRealObject.class).findAll();
}
public void setStuff(RealmList<MyRealmObject> stuff) {
realm.beginTransaction();
realm.copyToRealmOrUpdate(stuff);
realm.commitTransaction();
}
public void getStuffFromServer() {
restInterface.getStuff().enqueue(new Callback<RealmList<MyRealmObject>>() {
#Override
public void onResponse(Call<RealmList<MyRealmObject>> call, Response<RealmList<MyRealmObject>> response) {
if (response.isSuccessful()) {
realm.beginTransaction();
realm.copyToRealmOrUpdate(response.body);
realm.commitTransaction();
}
}
#Override
public void onFailure(Call<RealmList<RealmAd>> call, Throwable t) {
t.printStackTrace();
}
});
}
}
Towards the bottom of the file I've added a few examples, but usage is quite simple:
RealmResults<MyRealmObject> results = RealmController.with(this).getStuff();
In terms of having the objects auto-managed, what I've been using is RealmResults, which is always auto-managed (even if you're querying for a single object). Then just add a change listener to the results of the query and voilà. Also, if you want to have auto-updating data in recyclerviews, I would recommend RealmRecyclerView.
I'm trying to save my Objects from Retrofit directly into Realm but always getting the Error:"Realm access from incorrect thread".
This is my code:
public class RestaurantRepositoryRetrofit implements IRestaurantRepository {
private RestaurantApi mApi;
private Realm realm;
private IMapper<RestaurantJson,Restaurant> mRestaurantMapper;
public RestaurantRepositoryRetrofit(IMapper<RestaurantJson, Restaurant> restaurantMapper) {
mApi = ApiProvider.getApi().create(RestaurantApi.class);
mRestaurantMapper = restaurantMapper;
// Get a Realm instance for this thread
realm = Realm.getDefaultInstance();
**}
#Override
public Observable<Restaurant> getRestaurantById(String restaurantId) {**
return mApi.getRestaurantById(restaurantId)
.map(new Func1<RestaurantJson, Restaurant>() {
#Override
public Restaurant call(RestaurantJson restaurantJson) {
realm.executeTransaction(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
realm.copyToRealm(restaurantJson);
}
});
return mRestaurantMapper.transform(restaurantJson);
}
});
}
}
You should open the Realm instance on the background thread that receives the results of the API.
return mApi.getRestaurantById(restaurantId)
.map(new Func1<RestaurantJson, Restaurant>() {
#Override
public Restaurant call(RestaurantJson restaurantJson) {
try(Realm realm = Realm.getDefaultInstance()) {
realm.executeTransaction(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
realm.copyToRealm(restaurantJson);
}
});
return mRestaurantMapper.transform(restaurantJson);
}
}
});
Although if you intend to return a managed RealmObject, you should map out the ID from the saved proxy and then observe on main thread and query with a UI thread instance of Realm using the ID.
realm = Realm.getDefaultInstance(); will return the instance for the thread on which the object is created. But Observable.map() is called on the thread the observable sends the message from.
Since the observable comes from Retrofit this can be 2 options:
If the CallAdapter was created without specifying a scheduler then it will execute on the thread Observable.subscribe was called on.
If the CallAdapter was created with a specific scheduler it will be executed on that thread.
If the option that applies is not the same thread as the one where the object is created the "Realm access from incorrect thread" error will be thrown.
Realm is thread confined, which means that you need to make sure that you make calls on Realm objects and the realm instance on the same thread that you got the reference on. You probably want to use the scheduling method observeOn() from RxAndroid to make sure that you call realm::executeTransaction() on the same thread that you got the realm instance on.