Consider this scenario : There are two activities Activity A do network call and display count of tasks and the Activity B fetch tasks from database, or from same network API call if data is not available. While A is busy in network call user can traverse to Activity B. I am using Retrofit2 and Rxjava2.
My question is when Activity A is doing network call and user go to Activity B, and still the network call is running then, I want the object of Observable<> created on Activity A,also on Activity B because if I do not get callback then another network call for same task would be done on Activity B which is not feasible.
Anyone have idea How I can persist object of Observable<> created on Activity A ,by using this observable object I will get callback on Activity A as well as on Activity B and do some functionality.
Seems what you like is to do work in the background, that will be accessible to a different parts of your app (Activity), in this case you might want to consider using an AndroidService.
In short create a Service from ActivityA that will trigger fetching the data, then in the ActivityB connect to this Service to get an Observable with the data fetched in ActivityA.
For persisting the data and avoid making 2 calls to the same API, you can use operators like cache() that will multicast your Observable and cache the data, and then it can be available to ActivityB as well.
Another option as suggested is to hold a static reference to the Observable or reference at Application level, that will be available to your entire app, but then you should be careful with leaks as detailed by #Blackbelt.
My question is when Activity A is doing network call and user go to
Activity B, and still the network call is running then,
You should unsubscribe the observable in order to cancel the network call. If you keep a strong reference to it, you will leak the activity for the time the network call runs. You should decouple this logic
I want the
object of Observable<> created on Activity A,also on Activity B
because if I do not get callback then another network call for same
task would be done on Activity B which is not feasible
It is feasible. You could have a singleton, or better use Dagger to do that, that handles the network call, and emits the result to a BehaviourSubject to which you will subscribe. The nice thing of BehaviourSubject is that the latest value will always be emitted
to new subscribers.
Related
I've been using Realm with UI thread writes until I found out the UI was unusable at some point with significant database volume.
I'm now trying to figure out how to properly orchestrate asynchronous writes in app with activities and fragments showing data list and screens to enter the data.
At this moment, my problem is:
I have an Activity A, with its own Realm instance, listing data and listening to realm changes to update itself.
If I want to add more data, I create an Activity B with its own Realm instance.
I've started listening to the onSuccess callback of the transaction to refresh() the Realm instance in order to trigger Realm listeners and have Activity A update itself. Unfortunately it doesn't work when I quickly go back to activity A because the Realm of Activity B is closed and onSuccess is not getting called.
At this point I'm not sure how should I organize all this. I see the option where I don't create Activity B and use fragments but having to do this everywhere in my app doesn't feel great and might be error prone.
What's the best practice for this use case?
Thanks a lot!
I'm using rxAndroid with an MVVM architecture. In my Activity, I need to bind my streams then fetch data from the server, which will eventually call the downstream.
My reasoning is the following:
- I need to unsubscribe my streams in onStop() (onDestroy can cause memory leaks).
-> therefore I need to subscribe to them in onStart() (otherwise coming back from background doesn't recreate the stream).
-> therefore I need to fetch my data in or after onStart(), because the stream has to be bound before I can start calling the upstream.
But in this case, every time I come back to the app after background, it's going to call the fetch method, which is not a behavior I want. Ideally I'd like to call the fetch method once, for example in onCreate().
How can I nicely deal with this problem? I've tried finding solutions on SO and other websites but no luck.
So what you are saying is you ONLY want the stream recreated if it hadn't completed yet when the Activity was destroyed and restarted? In this case consider a BehaviorSubject.
It would live outside of the context of the Activity (be sure not to hold a reference to any Activity in the subject, a weak reference would be okay.)
It will deliver the last fetched result when you reconnect to it from the new activity.
Currently, I am using ViewModel to load a list of Shows in my app. Then, I display it in the main screen. It survives to configuration changes and does not provoke memory leaks since ViewModel has this features.
Now I need to do something a bit different. I need to log in a user making a network call to an endpoint using retrofit 2 and rxjava 2, he will type the email and password, and then will be redirected to the MainActivity. Second, I also need to update the user information, he types his new information and then I send to the server.
May I use ViewModel to log in a user or to update user information? If not, what sould I use instead?
What I need
This retrofit 2 call should survive to configuration changes, as rotating the screen, and it can not cause memory leak.
What I tried
Calling retrofit using enqueue() method in the MainActivity. Obs: This approach is not good because it puts to much things in the ui class, it provokes memory leaks.
Using static inner classes. Obs: It does not survive to configuration changes, as I need to cancel the task in onDestroy().
MVP seems fine to login a user.
You can check google sample project, specifically this class
https://github.com/googlesamples/android-architecture/blob/todo-mvvm-databinding/todoapp/app/src/main/java/com/example/android/architecture/blueprints/todoapp/addedittask/AddEditTaskViewModel.java
Usually you would trigger the network operation in the model view, while the code for implementing the network logic is written in a different class (ApiManager for example), and then get the results in your ViewModel
LoginViewModel will have an object of some network manager class
When you click login, the viewmodel will call networkManager.performLogin()
Results are then passed to the viewmodel (RxJava is handy in here).
In your ViewModel do whatever processing you need when you receive the results
I am working on an android app to display the popular movies. I am able to fetch the result from the themoviedb.org API which gives me different values like movie-name, movie-poster-id, movie description, etc. Now I want to make another API call to fetch the posters. I already have one AsyncTask fetching the movie information, should I create another AsyncTask for images and call them one after the other ? Or there's a better way ?
AsyncTask may not be the best solution; if the device rotates the activity is destroyed and when the async task finishes, it no longer has an activity to return the data to.
If you want to use async tasks, consider using a fragment with setRetainInstance(true) to do the network call. Your activity would launch the fragment and, if destroyed, it would remove its listener from the fragment and then when recreated, it would attach its listener again - the fragment continues to run regardless of the activity life cycle.
That said, you are probably better off with other solutions, like an IntentService or a full Service, depending on your flow.
Look at Volley and Retrofit libraries to help you with the network calls as well.
I have my MainActivity which gives the user a selection of pages to open, all of which involve downloading some data from the internet and displaying it. To save the user waiting when they choose their page I've made an AsyncTask as a subclass of MainActivity which produces an object DATAwhen the download is complete.
How would I pass DATA on to the SecondActivity in the following circumstances:
The user chooses the SecondActivity before the AsyncTask download has completed.
The download completes before the user chooses the SecondActivity.
the AsyncTask doesn't have to be a sub-class of MainActivity its just been tidy to do it that way so far,
thanks for the help!
Here's one way to do this:
Create a reference to your data in your Application. The Android Application is a good place to store global data. Next, populate the data via your AsyncTask (Watch out for the pitfalls of using an AsyncTask). You can now access your data via a call similar to this: ((MyApplication)getApplication).mydata
As you mentioned, two scenarios can come up. Either the data has been populated, or not. To handle this, use an observer that observes changes to the data. Have SecondActivity register as an observer when the data is null. When the data is available your SecondActivity's update method will get called and you can do whatever you please with it. Finally, make sure to unregister from being an observer.
Hope this helps.
Passing information directly between activities works only if it is Parcellable (via Intent). Almost anything could be made Parcellable but it is not always a good idea especially when the amount of data is large.
The next problem is that your AsyncTask most likely keeps the Context of your first activity alive when it is running longer than the activity lasts. Activity instances are quite often recreated when you rotate the device and naive implementations tend to start another asynctask in the new instance and end up with multiple tasks that download the same data. You would need to pass the reference of a running task between instances of the same Activity.
The simplest solution is probably to create a singleton (or a Service) accessible from both activities that hosts the AsyncTask & loads the data. If it requires a Context use getApplicationContext() since that's safe to use outside the lifetime of Activites.
Activities could register themselves as listeners for "data loaded" events while they are active.
I've recently struggled with AsyncTask and had difficulty having the UI behave while the task was running in the background. While there are comments around that services aren't really appropriate for the sort of thing you're describing, I've found them much easier to work with. You might check intentService as a middle ground. Good tut's can be found here and, specifically concerning intentService, here.