Just wondering what is a better practice to pass information between activites, adding it to a bundle or using a singleton class to store and access this data. I have used both in the past for various android side projects, but I am now working on an android project that is of much larger scale, so would prefer to do things right towards the beginning.
My application authenticates users and then will have to do various queries based on it's id. To minimize coupling between activities, I would think just adding the id to the bundle, and then letting each activity query for the information that it needs, would be the best bet; however to increase responsiveness, I was leaning towards using a singleton class to store persistent information, preventing more queries than need be.
Personally, I would create an extension of Application to store the state of your app and share data between the different activities. The Application acts as the context for your whole app and Android guarantees there will always only be one instance across your app. Hence it works similar to defining your own Singleton, but using Application will allow Android to take control of the life cycle of your shared data and basically do the memory management for you.
Here are some more details. If you go down this path, you can simply add any getter/setter (or other) method to your application extension to store/retrieve data and do operations on it. Especially the latter can become quite a pain to manage (and keep consistent) when using Bundles passed back and forth between activities. If would only use a Bundle if the data is needed in just one or two places that are neighbours in the activity flow and does not need any (complex) operations to be run on it.
The better way to go for you is to use SharedPreferences to keep userId you need to keep and reuse. Of course you can use singleton approach or even Application class, but the data will be lost after application is killed.
The only time I pass data between Activities via bunlde is if it's something that I won't need to access for a while(i.e the the resID of a resource I want to use only once in the calling activity, etc). I would also think the difference in responsiveness would be very minimal, so that shouldn't be of concern. I suggest the singleton approach
Passing bundles is a tedious job. You'll have to pass a bundle for every change in activity to make sure that the value is not lost, even if you're not using the value in the called activity.
Singleton pattern have some bad results. For example:From Main activity you call secondary activity. Phone call interrupted your work.After ending phone call Android is trying to bring secondary activity to screen. Here is my nightmare - many users complaint about exceptions - Google reported to me NULL pointers in my singleton. So you have to provide not only singleton, but all data inside singleton have to be as singleton too. This maked come very complicated :(
Related
I am building my first Android app. I need to add a specific set of headers to each web api call and want them to persist even when the app closes. I implemented them in shared preferences but now I need to drag around a context for every call, which seems like a bad way to do things. I would like to set the values on initialization of the app. Have them usable by the WebAPIHelper object without much trouble, and when the values change, save them. I am using Room so I could save them there.
Is it standard practice to use LiveData or extend the application object to have access to the values for use within an object such as my WebAPIHelper, or is there another, better way? Is it best to persist these values in a database or SharedPreferences?
UPDATE
I have seen some examples of extending the application object like here and here. I would want to get the values from sharedpreferences onCreate and save them to sharedpreferences by calling a setXXX, but I haven't gotten that to work.
Also I was concerned about this statement I found in an article:
"Storing data in the Application object is error-prone and can crash your app. Prefer storing your global data on disk if it is really needed later or explicitly pass to your activity in the intent’s extras."
The implication of this would mean that I would need to pass the header values to the WebAPIHelper object all the time. I am passing the context object everywhere now so I guess it's 6 of one vs 1/2 dozen of the other.
The other way to do this might be to extend the AndroidViewModel class in a BaseViewModel, add the properties there from SharedPreferences so they are available through all ViewModels in the app. Has anybody done it this way?
Currently I'am developing app which having a bad API. I have a situation where I have to use data received from network call in a activity, which is 2 steps away from the activity where I made the network call. In other word all the data necessary fill 3 activities comes on this one network call.
So I pass necessary data between activities using Intent Extra. It is not easy to maintain and It takes noticeable time to switch between activities.
I know one possible solution is to store data in database. and access those data from different activities. It feels like a bad practice because no use of those data after user pass 3rd screen.
Is there any better technique to handle this?
You can put all your network logic in the separate class, cache data in some variable and use it in your activities (you can use singleton class or injecting by dagger).
Also you can read about Clean Architecture and get some good practices from it.
If you don't want use anything from above, you can remove data from database after using and not store it forever. Or you can use SharedPreferences if your data is not complex.
I would like to have all my Activities (7 to 10 different screens) submit data to a "controller" (sorry if I'm miss using the term).
Inside said controller data would either be uploaded or saved to data for uploading when no internet.
The controller would do checks and processing such as:
Checking for valid session.
Attach other needed credentials before
upload etc.
Session/User data would be stored in a Shared Preferences file the controller has reference to.
My goal is to have Activities do nothing more than collect the data and call the appropriate method (with a data object) asynchronously. The controller would know how to process the data for uploading or saving in the database.
Would placing these methods in an extension of Application be a bad idea?
It was mentioned that depending on application size this is feasable, but there could be better solutions.
Depending on the size of your project, that would be a suitable idea. However, there are some other ways you should know before choosing the method you're actually implementing:
Using a ContentProvider for your data, an AccountAuthenticator and then sync to the server using an SyncAdapter. Advantages are a good abstraction, independence from activities and many built-in features (for example: Android executes your code without a big battery life impact). However, implementing all the stuff is quite much work at first. If you don't want to use the ContentProvider, the same technique works with a stub implementation as well, the same goes for the AccountAuthenticator.
Using a Service, probably IntentService, for your uploading needs. Advantage is that the Service has an independent lifecicle and thus is not directly related to your Activity; a Service can get restarted if it has been killed by the system. Still more work than just using some static methods.
Using a static method as you're proposing it (in your case, the Application object; not completely static, but compareable). Quite easy to implement, probably the best way if there are similar tasks in multiple activities; your AsyncTasks can send their result directly to the activitiy that started it. However not suitable for long-running tasks.
Implementing within the Activity; If code is only used once; listed for completeness only, not for your case. Basically the same as using a static method.
These are the ones that popped into my mind, there might be some others, too. Feel free to add/suggest additonal ones.
I am considering using the android Application class as a place to store temporary state and common code shared by other (fragment) activities in the app.
I would like to get more feedback as to whether it is a good place for:
Shared constants like ID's, pref key names, etc.
Global variables (i.e. setters/getters) reflecting current UI state, navigation, selected fragment, and, in general, temporary data that does not need to be persisted.
Hooks for persisting data when certain conditions are triggered.
Updating the UI after preference changes.
Providing an easy way to access the context from anywhere in the app, including code where getApplication() is not available, e.g. via a static getter such as MyApp.getApp().
Common methods that need the visibility of the global state variables and which would become too cumbersome to move away to dedicated classes.
What else would be appropriate/useful/handy to have in the activity class? What would not be a good idea to keep in it and what would be the best alternatives? And finally, what you have found Application to be best used for in your apps?
Shared constants like ID's, pref key names, etc.
I generally create a constants file called C for this, as its better for readability. C.SHARED_PREFS is easier to understand that Application.SHARED_PREFS IMHO.
Global variables (i.e. setters/getters) reflecting current UI state,
navigation, selected fragment, and, in general, temporary data that
does not need to be persisted.
This would be better off in the Activity or component which it concerns (for example, the UI state of an Activity should probably stored in the icicle bundle, or within that instance of the Activity).
Hooks for persisting data when certain conditions are triggered.
This should be fine.
Updating the UI after preference changes.
Again, I feel this would be better off in the respective component.
Providing an easy way to access the context from anywhere in the app,
including code where getApplication() is not available, e.g. via a
static getter such as MyApp.getApp().
This would work, but be careful of memory leaks. You should generally pass the context in as a parameter when calling the method from an Activity or Service or whatever. Less chances of a memory leak.
Common methods that need the visibility of the global state variables
and which would become too cumbersome to move away to dedicated
classes.
I feel it would be better to make the effort of dedicated classes, as when your app grows in features and size, this will become difficult to maintain.
It is probably some place where certain hooks can be attached.
For instance, if you use ACRA crash reporting library, you just need to use the Application class, because this is where ACRA is attached. This is that forced me to start using this class; I never needed the one before.
This is a question I've now had for a few different apps I've built, and I have yet to be satisified with any of the solutions I've come up with. I thought I'd put it out there to the community to see other solutions there might be.
Let's say you have an Activity that downloads a complex tree of data (in this case via json, but it could be anything), unmarshalls that data to a set of java objects (in this case using gson, but again, could be whatever), then spawns additional activities to view different parts of that data. There might be one activity to view Trips in your response, and another to view Flights in those trips, and maybe another to view Passengers of those flights.
My initial implementation of this app was to unmarshall all the Trips in the first activity, then pass them by value (as an extra in the intent) to the TripActivity. The TripActivity then passes individual flights to the FlightActivity, and so on.
The problem with this is that there's a noticeable pause between activities while the app serializes and deserializes the data. We're talking several seconds. The pause is quite noticeable when my tree uses Serialization or Parcelable to pass data around. Initial performance testing with using google's Parcelable instead show a roughly 30% speedup over serialization, but Parcelable is difficult to work with and doesn't seem to handle circular object references well like Serialization does, and besides it still pauses for almost as many seconds, so I've put that experiment on the backburner while I try other things.
So then I tried moving the tree of objects directly into the Application class. Each activity just gets the tree directly from the app whenever it needs it. This makes performance quite snappy, but handling corner cases like unexpected activity start/stops (either due to activity crashes or because the activity has been closed temporarily to make more memory available, or whatever other cause) seems tricky. Perhaps it's no more than implementing onSaveInstanceState(), I'm not sure, but the solution seems a bit hacky so I haven't investigated further yet.
So in search of a less cobbled-together solution, I tried creating a custom ContentProvider to store and retrieve my objects. Since ContentProviders can be configured to run in-process using multiprocess=true, I thought that would be an excellent way to avoid serialization costs while doing something more "standard" than storing data in the Application object. However, ContentProviders were clearly not intended to return arbitrary object types -- they only support types such as numbers, strings, booleans, etc. It appears I can finagle one to store arbitrary objects by using ContentResolver.getContentProviderClient().getLocalContentProvider() and accessing my custom class directly, but I'm not sure that's less hacky than storing data in the Application object.
Surely someone must have a good solution to this problem. What am I doing wrong?
In addition to fiXedd's solution, another one is to use a local service. Have the service "own" the objects, with activities calling service APIs to get whatever it needs. The service can also be responsible for fetching and parsing the data, encapsulating that bit of logic.
The Application object is the "red-headed step-child" of Android components. Members of the core Android team have come out against the practice of creating custom Application subclasses, though it is certainly supported by the API. Having engineered one ADC2 200 application that leveraged a custom Application subclass, I can say that I should have gone with a service in my case as well. Live and learn...
By using the local binding pattern, your service will automatically be created and destroyed as needed, so you don't have to worry about that. And, by definition, a local service runs in the same process/VM as your activities, so you don't have to worry about marshaling overhead like you would in the ContentProvider scenario.
The way I'm handling this in one of my apps is downloading the data then shoving it into a database. This way I don't have to carry all those objects around (which, IIRC, eat about 1kb each just for the object instantiation) and I can easily pull just the data that I need. I don't know if this will work for you, but it worked for my use-case.
Another approach would be to save the data objects to a shared preferences file. That's how we implemented one of our apps, but I didn't like that approach because it seems too slow.
It's bad coding practice, but the fastest way may be to just use a service to parse the data and save the data to a static class that you can use for the rest of the app's life.