I am currently creating an Android events app that uses RxJava to wrap an old network layer and cache setup with Observable.create(). I'm currently stumped as how to approach prefetching data though. Initially I display a list of events which will then open an EventDetail Activity which will fetch the contents of the given event. I want to prefetch some of events' contents, but end up making redundant network calls if the event is selected before the prefetch returns and caches. Is there a good way to keep Observables/subscriptions alive over Activity switches? A singleton network layer held in the application? Any help would be greatly appreciated.
Typically, I keep all the logic away from Activities, so, "Yes, definitely!": A network layer is what you need.
Keeping this approach, your Subscriptions will stay alive even if the Activity is restarted, for instance, on rotation. A very useful operator you need to look into is .cache(), that will help you to reuse the ongoing network request instead of firing a new one on a new subscribe().
Related
I have my full functional code working, but as much as I took time to write this clean code, I am having problems notifying my UI for data.
The data state I want to notify my UI with are:
State Data available
State no data
State poor network connection
State loading data.
I have all the callbacks that makes these data state, but how to notify my UI in a clean way is a pain. Though, I have tried several means like using an Interface and ViewModel that controls a progress bar and dialog and just make them visible and invisible at the right time. This method is clean but I wish do do more cleaner handling plus I have a issue of delaying a little for data to arrive especially in case of a little weak network connection to download data.
Here are my questions:
How to effective way notify UI for data states.
How to delaying effectively while waiting for data.
I appreciate your reply.
I have a fragment and the data displayed are fetched from a network call.
I am using onSaveInstanceState in order to avoid fetching the data again when the orientation changes, but if I understand the lifecycle for fragments correctly as long as the app is never destroyed (either explicit by the user or because the Android OS kills the activity due to lack of resources) the data from the server will never be refreshed.
If I have understood this part correctly, I would need to define some way to periodically refetch the data from the server or is there another way?
There are no rules about data refresh. It depends on your app, your data, etc. If you fetch a list of receipts, you do not need to implement a refresh mechanism. But if you fetch, I don't know, the exchange rate of currencies, you must have one.
What about a pull to refresh pattern ?
I would use the Android Architecture components ViewModel and LiveData to save the data during screen rotations preventing multiple calls to the server for screen rotation changes. This is the preferred method Google seem to be pushing to their developers https://developer.android.com/topic/libraries/architecture/saving-states
To prevent the data from going stale I would either let the user decide when to update using the "Pull to Update" (as described in the other answer) or add a timer to update if the fragment has been in the foreground for an extended period of time using the method described here: https://guides.codepath.com/android/Repeating-Periodic-Tasks
Loaders
monitor data source and deliver new results
After a configuration change : no need to re-query the data
I read the android guide about Loaders.
I read Alex Lockwood 4 parts tutorial . Tested his sample app too.
Tried to read the Google App for I/O 13, there's a Stream feature and reading its code find out it uses Loaders since it provides code to create a StreamLoader. Here is the Link
I suppose they use it to monitor for new data and add them to their view.
Same for Alex's app. There's an observer and when there is new data entries triggers a refresh for the UI.
So far it seems to me, Loaders are ideal choice for a "livescore" app. When there's a new update ( which means a new data entry ) it appears on your screen.
Maybe something like Twitter. New messages for you, custom Observer to notice for changes, custom Loader brings the data and an adapter to display them. No need to "pull-to-refresh".
But then again Twitter has its own RESTful API which kinda does the same job. No need for a pointer to the new data. ( don't know how they do it but I guess somehow the "push" new data to your device ).
So my question is :
Loaders are best option when we want to observe a data source and change our view so it will display the new data?
Are there any examples/app I can check dealing with that logic : monitor the data source -> get the data -> refresh UI
Any characteristic cases ( like the one with the "livescore" previously mentioned by me ) that when we have to deal with them we have to choose Loaders?
The second part of the Loaders ( configuration change, keeping the data ) I think its clear. No one want's to re-download an Image gallery when the user rotates the device.
Thank you and excuse my confusion
The best way I can describe a Loader is a Handler that is always on. Both Loaders and Handlers pass data between objects.
I agree with what you said about the "livescore" app.
The Loader monitors the source of their data and delivers new results when the content changes.
To answer your questions:
1) Loaders are best option when we want to observe a data source and change our view so it will display the new data?
A: Yes. if your data source is constantly updating. For example, like a stock-ticker app. If your data isn't constantly updating, then no, don't use a loader. For example, if your data source is only retrieved once, then there's no need for a Loader.
2) Are there any examples/app I can check dealing with that logic : monitor the data source -> get the data -> refresh UI
A: https://www.youtube.com/watch?v=3d9BeWqlfTk
Yes, they are what you want to use for the flow you're describing. Tangentially, there's also AsyncTasks and Services that have similarities.
AsyncTasks
Description (from docs):
AsyncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few seconds at the most.)
Caution: Another problem you might encounter when using a worker thread is unexpected restarts in your activity due to a runtime configuration change (such as when the user changes the screen orientation), which may destroy your worker thread. To see how you can persist your task during one of these restarts and how to properly cancel the task when the activity is destroyed, see the source code for the Shelves sample application.
If you specifically just want a wrapper to basic threading boilerplate, use an AsyncTask otherwise I'd suggest you use an AsyncTaskLoader if you need a general purpose way to run intensive operations in an Activity or Fragment. You get the same benefits from AsyncTask, but it handles lifecycle issues for you. There are also specialty loaders, such as CursorLoader that will are made to handle specific data sources and have conveniences for interacting with certain UI elements.
Services
Description (from docs):
A Service is an application component that can perform long-running operations in the background and does not provide a user interface. Another application component can start a service and it will continue to run in the background even if the user switches to another application. Additionally, a component can bind to a service to interact with it and even perform interprocess communication (IPC). For example, a service might handle network transactions, play music, perform file I/O, or interact with a content provider, all from the background.
You would use a service to handle data being pushed to a phone. Otherwise, the user would have to open your app to get any pushed data. Services do not interact with your UI. So a common design pattern is to use a Service to gather data from a server (whether pushed real time or if you poll) and store it in your database for use both when your app is opened or when not. There are many other use cases for Services, but this one is probably the most popular.
Conclusion
So no, you aren't required to use a Loader to load data or do long running operations on a background thread and pass the results (or progress) to your UI thread, but they are the best option for most use cases.
I'm new to Android development and have written a small app that calls a web service and hydrates a relatively simple object (think: auction listing or something of that magnitude). Right now, when the phone rotates and the view is reloaded the web service is re-called, the object is re-hydrated and the listing re-displayed. This seems very wasteful. What is the best practice when storing data via onSaveInstanceState? Is it considered OK to store the object itself, or is it best practice to store the ID and go through the whole process of loading it fresh each time. Are there any other rules of thumb or gotchas to be considered here?
Thank you
JP
Even re-creating information form a database is usually considered too much effort for the Android config change scenario.
What you want to use is to create a class holding references to objects which you want to survive the config change, and have your Activity have a reference to that. Also, you will return that in the onRetainNonConfigurationInstance() callback. In onCreate(), you call getLastNonConfigurationInstance() to see whether this is a re-creation due to a configuration change. This call will return your object with all the data you need.
Since you are calling a web-service to populate your list, I guess you should store your list's data (calling web-services consumes time and may fail if your user doesn't have a steady connection). Which you can do in different ways (a database, for instance). This approach would also help you if the user restarts your app, since he won't have to wait until the web-service responds.
Also: re-consider your terminology when you ask a question. You don't usually see someone speaking of "hydration" of objects; it's more common to speak of populations and so on.
If you only want to avoid recalling service when orientation changes then you can add below in your Manifest in activity tag.
android:configChanges="navigation|orientation|keyboardHidden"
But as #DigCamara said, his approach is best and even useful for other scenarios like restarting.
Cache your data as much as you can, every data connection has a "standard" cost in terms of time, resources, and ultimately battery life.
Try to group your requests and make them all in once and cache the responses as long as you can.
Good read about network on android developers
I'm using Fragments and LoaderManager. I have to launch an unknown number of tasks, and they might be run in parallel (otherwise I'd just reuse one and only one loader). For example, I have a listview, and each row might have a button to save the content of that row to a webserver. The user could initiate a save request on multiple items in parallel.
private int nextId = 0;
private void onClickListener() {
Bundle bundle = new Bundle();
bundle.putNextData(...);
getLoaderManager().initLoader(nextId++, bundle, this);
}
I could try bookkeeping myself, so create a pool of loaders manually and reuse them when possible, seems like it might be something already implemented by the API?
Thanks
I don't think you should use a Loader for saving data to a remote server.
Instead, use an IntentService or something similar to process a queue of "save" operations. This way, your communication with the web server can be batched, collapsed (i.e. multiple queued saves for a single item can be collapsed into one operation), and will live beyond the lifespan of your activity if need be.
A save queue processed by an IntentService (or equivalent) is also a great way to retry failed operations with backoff, since you can implement delayed retries with exponential backoff using AlarmManager.
An IntentService or bound service are always good approaches for that.
As Roman points, note that enqueuing several requests and called them separately is not highly recommended (it is very likely that you give a lot of work to the radio connection - when using data - which among other things drain your battery. Here is must-read about that)
I'd personally recommend to use a bound service with a queue of requests and a pool of threads available (that approach gives you full control for more complex network operations like in your case). There are more details on the approach here and a testcase working example over here.
Update us about your progress.
You are at the right direction, let me just help you a bit.
Reusing is indeed a good idea, and you do not have to worry about it because Android did it for you(Or Java actually ;)
It called ThreadPoolExecuter, you can start as many tasks as you wish and he will only open the predefined number of threads.(Best practice is trying to open as many threads as parallel network connection can be run on the device. From my research it is between 4 - 9).
And if you are trying to download same URL twice may be you can protect your self and open only one task for it.