Reputation: 5605
I have ViewPager
which contains three different Fragments
, every fragment has it's own API call. Let's say that first fragment is requesting something from API. Callback is returned, then I am saving it to local Realm
database and after that I am sending it with EventBus
to Fragment. The problem is that I get No subscribers registered for event class
error and nothing happens.
After some time I managed to solve this in this way :
final GetInfoResponse response = new GetInfoResponse(databaseService.getInfo());
new Handler().post(new Runnable() {
public void run() {
EventBus.getDefault().post(response);
}
});
If I put EventBus in Handler the Event
is delivered properly to Fragment.
I was thinking that maybe Realm
is switching threads when it gets data from database. But I am not sure. On the other side, if I am not doing local saving and send EventBus
straight from REST Callback, everything works fine.
EDIT :
GetInfo
method
public List<Information> getInfo() {
List<Information> informationList;
Realm realm = Realm.getInstance(getConfig(context));
realm.beginTransaction();
RealmResults<Information> realmList = realm.where(Information.class).findAll();
informationList = new ArrayList<>(realmList);
realm.commitTransaction();
return informationList;
}
Why is it so, and how can I do it better?
EDIT 2 :
After changes proposed by @EpicPandaForce.
This is my code structure and path to call API.
I have Fragment. Let's call it InfoFragment
. In onCreateView
I am doing this :
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.info, container, false);
realm = Realm.getInstance(DatabaseConfiguration.getConfig(getActivity()));
DataManager dataManager = new DataManager(realm, getActivity());
dataManager.getInfo();
return view;
}
public void onEvent(GetFaqCategoriesResponse response) {
...
}
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
Now, my DataManager
looks like this :
public DataManager(Realm realm, Context context) {
this.context = context;
databaseService = new DatabaseService(realm);
}
public void getInfo() {
if (ConnectionUtils.isNetworkAvailable(context)) {
ServerService.getInfo(this);
} else {
final GetInfoResponse response
= new GetInfoResponse(databaseService.getInfo());
new Handler().post(new Runnable() {
public void run() {
EventBus.getDefault().post(response);
}
});
}
}
My DatabaseService
:
private Realm realm;
public SupportDatabaseService(Realm realm) {
this.realm = realm;
}
public List<Info> getInfo() {
RealmResults<Info> realmList = realm.where(Info.class).findAll();
return new ArrayList<>(realmList);
}
I am closing Realm
instance with realm.close()
in onDestroyView
of InfoFragment
.
Upvotes: 1
Views: 759
Reputation: 81539
To automatically update the Realms on all looper threads, Realm sends a message to the main thread looper's handler to start updating when you commit a transaction. So unless you are subscribed to the Realm's changes in a RealmListener
(which I don't recommend as it updates every single time the realm is modified!), you will only receive the notification about it when the next handler cycle runs. If you use onEvent()
, then as specified for the default threading mode, your event will be delivered immediately and not through a handler (which sends a runnable to execute on the other looper thread on next iteration).
Basically, if you don't send it through the handler, then the Realm of the other thread won't be updated yet at the time of receiving the event. If you are sending these Realm objects from the main thread to the main thread, you can use onEventMainThread()
instead of onEvent()
to automatically pass it through a handler to the main thread.
By the way, you are using Realm incorrectly, the Realm instances you open should also be closed, but a Realm object associated with a given Realm can only be accessed on that same thread, and a Realm object can only be accessed from an open realm. You don't need to open a new realm to execute the query, you could just use findAll()
on your main thread using the Realm instance you opened in onCreateView()
as you also close it in onDestroyView()
, and findAll()
is executed as a lazy query and therefore isn't memory intensive whatsoever. And you're also beginning and committing a transaction even though you're not actually doing any writes...? :P
Upvotes: 1