I have a simple approach question about Android design.
I envision a scenario where I provide a service and an activity. Both the service and the activity need to read/write to the same data. The basic idea is a live playlist: the service that is playing the list "pops" a song from the list when it's done playing, but the the app can also edit the list by adding or deleting songs.
I considered using a ContentProvider for the actual playlist, thinking it would be simple, but all ContentProvider examples I can find on the internet seem morbidly overcomplicated or involve solely SQLite.
Another approach would be to keep a simple file in my resources, and access that from both the service and the app.
Which approach seems to be better here? If I should indeed use a ContentProvider, can someone please direct me to the simplest possible implementation, preferably not involving SQLite? From my prior looks, ContentProvider seems overcomplicated for my simple purpose.
Thanks for any opinions!
-Chase
A ContentProvider may persist the data it's entrusted with however it likes. Typically, that means SQLite, because the mapping to the ContentProvider interface is intuitive.
However, as long as your ContentProvider implements the insert(), update(), delete() and query() operations, (or implements as much as the app that uses the provider needs to have implemented to do it's job) you can persist the data that goes in and out using whatever mechanism you like. Feel free to store it in a SQLite database, a file, or whatever.
Just keep in mind that your ContentProvider may be subject to being killed and restarted, maybe even being garbage collected and re-constructed later, so you need to use something that's robust against the class going away and being reinitialized.
In your case, you probably don't care about persisting across reboots (who cares about the playing music list being there after you reboot) so some sort of list in a static variable ought to be sufficient.
Related
I have a multiple Activity application that progresses the user from entering an IP/Host address, to entering some data (another Activity), to viewing a stream of video frames (yet another Activity). I share the Socket between the Activities by creating a singleton. Is this considered a bad pattern to use for an object that cannot be serialized?
I have looked all morning through some of these posts and others through out the web and the best that I can come up with is there is no real easy way, but this one seems very easy to me. The only other approach I think has merit is a custom Application object.
Any insight by people who have worked with singletons across Activities I would really like to hear of any problems I may not be aware of that might get me later... Thanks!!
The downside to your approach is that you cannot rely on the singleton's data structures to always be kept around in memory. Your best bet is to persist information in either SharedPreferences or a SQLite database.
It sounds like your singleton might be a good candidate for a Service. Services are meant for long runnning operations that do not have any UI. Multiple Activities can bind to a service and interact with it. Unlike a singleton, if/when your service gets killed, you will get lifecycle hooks to deal with it appropriately. You can also set it to be restarted when appropriate.
I'm currently learning to develop for Android and I'm having a somewhat hard time figuring out when and how to use services. I have already seen the numerous questions asked about very similar things, but I can't quite find the exact answer to my questions.
I have an app which talks to a restful api. I fetch several lists which I would like to cache in memory and only update if the user hits a refresh button, or certain activities are created. If a list is refreshed, sometimes several activities need to be notified, so that they update their content (if they are on screen at the time). I store the data I retrieve in value objects.
On a non-android app I would usually create a sort of dataproxy class in a singleton pattern. I could ask the dataproxy to update its data via http request, and then it would send some kind of system-wide notification as soon as the data is changed, so the interested views can all be updated. I hope this makes sense.
My question is now: How do I do this the android way? Do I bind and unbind to a dataproxy service, which I can actively ask to fetch certain data? Should I do my non-persistent caching in this service or somewhere else? Do I need AIDL, or can I just use normal objects for moving data between a service and an activity? Although I find the android dev guide pretty well written and useful, I haven't found much information on services best practice.
Thank you in advance!
How do I do this the android way?
You assume that there is a single "android way".
Do I bind and unbind to a dataproxy service, which I can actively ask to fetch certain data?
You can either bind, or send commands via startService().
Should I do my non-persistent caching in this service or somewhere else?
If you're sure that you only want it to be in RAM, I'd lean towards static data members. Make the service be the "do-er", not the store.
That being said, I'd treat this more as a synchronization pattern, with the real store being a database or directory, with a cache in RAM. Users will find this less frustrating -- under your current plan, if they are in your app, then take a phone call for a while, they'll have to have you download all the data again.
Do I need AIDL, or can I just use normal objects for moving data between a service and an activity?
If they are all in the same process, normal objects is fine via binding, or use Intent extras for the command pattern.
Now, back to:
How do I do this the android way?
Option #1: Wrap your store in a ContentProvider and use ContentObserver for changes.
Option #2: Have your service send a broadcast to your package when the data changes, so the foreground activity can find out about the change via a BroadcastReceiver registered via registerReceiver(). Other activities simply grab a fresh look at the data in onResume() -- the only one that immediately needs to know of the data change is the one the user is interacting with, if any.
Option #3: Use the binding pattern with the service, and have the foreground activity register a listener with the service. The service calls the listener when data is updated. Once again, ather activities simply grab a fresh look at the data in onResume()
Option #4: Cook up your own listener system as part of your static data members, being very very careful to avoid memory leaks (e.g., static reference to an activity or service that is destroyed, preventing its garbage collection).
There are probably other options, but this should get you started.
The Google IO session mentioned by Andrew Halloran:
http://www.google.com/events/io/2010/sessions/developing-RESTful-android-apps.html
Check out the Google I/O session videos. I implemented REST api calls the easy BUT wrong way. It wasn't until watching this Google I/O video that I understood where I went wrong. It's not as simple as putting together an AsyncTask with a HttpUrlConnection get/put call.
The Android Dev Guide says
Content providers are also useful for
reading and writing data that is
private to your application and not
shared.
Generally, Content Providers are used for providing data to different applications or sharing data among them. I was wondering if there is any use to having private providers and not wanting to share it. Are there any benefits provided that a direct access to DB or file system don't provide?
Thanks,
Rajath
It automatically schedules all your server-side and synchronization DB access in a background thread. However, in your application frontend, the Content Resolver/Provider will normally execute queries/transactions from the UI thread by default. You must perform all transactions asynchronously (i.e. using a CursorLoader) to ensure that your application runs smoothly on the UI side
It localizes re-entrant DB access from the any threads that access through ContentProvider, so that all locking can happen entirely in your ContentProvider override calls, rather than keeping track of it in a DB layer, a service, and a UI layer.
As part of the above, it also provides a nice singleton interface to your data -- If you have ten Activity classes in your app, you just go through ContentResolver static calls from each one, versus needing to deal with opening/closing a SQLiteDatabase in each activity as you jump from one activity to another in your app.
ContentProvider is tied very tightly to the SyncAdapter model -- Meaning it's pretty much the only way to go if you want to keep your database in sync with a server-hosted database out on the net. (your app mirrors a REST api type of situation)
It ties into ContentResolver's ContentObserver interface -- This is an interface where (among many other useful things) a view can register as observing a specific set of data (through the Cursor to that data). Then, if you drive a change into the ContentProvider, the CP can notify the CR, which can in turn notify any relevant cursors, which in turn will requery and cause the view to update. This is much cleaner than having to manually keep track of your views so you can invalidate and redraw them.
As for re-entrant locking of the DB, it doesn't do it completely, but it helps -- your ContentProvider class implements four simple functions (CRUD interface) and, if you choose to override it, a fifth, batchAdd() -- This localizes your locking. The bone simple answer is to simply tag all four/five of those function declarations "synchronized" at the function level and you're done. Much cleaner than trying to figure out locking out from 20 places that access your DB in 5 different Activites.
For example,a multiprocess application use scenario(like: music play service usually run in a remote process), between the two process that in one application share database should use private ContentProvider.
I am working on a program that has the following situation.
You want to look up a recipe, so the Activity will call the db ContentProvider.
The recipe isn't stored locally, so it will call out to a web service to get the data.
This data will be stored in the database as I am assuming that if you don't want to keep a local copy you will choose to delete it later, but you may want to shop and cook without going to the Internet constantly.
So I think my design may be getting overly complicated.
I currently have a Service that will call the REST service, and a ContentProvider to go to the database.
I am now considering replacing the Service with a ContentProvider, as I don't need a long-running Service as it should infrequently go out.
So, the Activities would call the db ContentProvider, and if the query is empty then the ContentProvider would call the REST ContentProvider, as the Activity shouldn't care where the data comes from, and the db ContentProvider would then store the information before returning back to the Activity.
Is this the best approach for my scenario, or is it bad form to have ContentProviders chained together?
I think that is quite reasonable. However, I think you could still keep the Service but just always expose the data through the ContentProvider. One glitch here is that you will have to start(or bind) the service in the ContentProvider and you will have problems when testing your Provider using ProviderTestcase2<Provider> as the MockContext does not support starting the service.
It seems a good approach. Currently I'm developing something similar and I've found this great article, where the author explains everything step by step, saying which thing for what is used for, what is the best approach and so on. Take a look at it if you are having some troubles implementing something:
http://programming-android.labs.oreilly.com/ch11.html
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.