world!
I'm building an application that has to retrieve data from a server in several different Activitys. Some data is cached to a SQLite database (and retrieved from there instead in future), and some must be called fresh from the server every time. I need to know what the best multi-threaded architecture would be for this application. Multiple Activitys will be connecting to the server.
I'm thinking a bound Service would be best, but of course I'm not sure. If that's the way to go, how exactly do I implement multi-threading in it?
Thanks
The android classes such as IntentService and AsynTask are thread safest because they will not keep your activity open when your activity's finish method is called. If you create your own Thread implementation you must remember to stop the thread on Activity finish so that the process' memory will be reclaimed.
In a situation like yours I am going with a set of singleton factory classes to access local SQLite db and a background service doing asynchronous replication
Related
The documentation for Android's SQLite interfaces mention that database accesses should be performed from an IntentService as they are potentially long-running operations, so the GUI thread should not block on them.
The IntentService is shut down as soon as no further Intents are queued for it, which would happen basically after every request, so the database handles are built up and destroyed for each query as well, which seems wasteful.
Is there a way to keep an IntentService around longer, or somehow otherwise avoid a race between the GUI thread posting more Intents and the service answering them?
Should I just make my query Intents contain a list of queries that should all be performed, or would that cause other problems with message sizes?
The documentation for Android's SQLite interfaces mention that database accesses should be performed from an IntentService as they are potentially long-running operations, so the GUI thread should not block on them.
I/O of all forms should be performed on background threads, so as not to block the main application thread. IntentService itself is not a great choice, given changes on Android 8.0+.
A more typical approach nowadays is to have database access be managed by a singleton repository (whether a manually-created singleton or a singleton supplied to you via a dependency injection framework). The repository can use any number of approaches to provide a reactive API while doing the I/O on a background thread, including:
RxJava
LiveData and ordinary threads, executors, etc.
Kotlin coroutines
If you use Room as your database access layer, it gives you all three of those options "for free". Some other ORMs offer similar capabilities.
Is there a way to keep an IntentService around longer, or somehow otherwise avoid a race between the GUI thread posting more Intents and the service answering them?
Background services can only run for one minute. If your concern is the overhead in opening the database, use a singleton repository, and only open it once per process invocation. It's also entirely possible that you do not need a service; if you have a foreground UI, a service may be pointless.
Should I just make my query Intents contain a list of queries that should all be performed...?
Um, possibly, but again, using a service here may not be necessary and definitely makes the problem more complex.
So: use a background thread for I/O. That does not have to involve a service.
I need a shared list of computers made available to all my app's activities. The list of computers needs to be upated by two background tasks of some kind, one that blocks on a socket waiting to receive data, and another task that periodically purges computers from the list. What is the proper Android way of doing this to avoid running into activity lifecycle problems? Specifically,
Can/should I use a singleton to maintain and expose the list to the activities and background tasks? (I'm familiar with thread synchronization issues and am prepared to deal with that.)
Can/should I use the IntentService class (two separate instances for the work I need to carry out) or is there a better way? Do I need to use a BroadcastReceiver in that case or could I still store the list in some common place, like a singleton?
How do I avoid keeping my services running when my application is put in the background?
Updated answer for updated question
You can use a Singleton if you don't have a problem with losing your data when your app get's killed (e.g. when you can rebuild the data on restart). In this case you should check that all your components run in the same process (which is default).
You should not use IntentService for intra-app-communication, however bound Services might be an option here
If you bind services from an Activity and unbind them in onPause, they get automatically stopped (if there are no other bound contexts and they weren't started with startService)
If you think your tasks are too complex to accomplish in the same Service, I would recommend two Services bound by an Activity and backed by a ContentProvider which e.g. can be backed by a database.
Old answer
The issues you expierenced might be a problem of Thread-safety (or the lack of it)
Two Intent Services just to share data within an application is definetly way over the target
A broadcast is the right way to notify components of a change
You might want to take a look at Content Providers
Another solution might be a service, which can be bound by all your other components
You can use Database to maintain the UDP packets with timestamp.
Also periodically check the last sync time from Database to check whether UDP packet is coming or not. Hope you know how to use Database.
There are couple of things that are bugging me in the process of downloading data and notifying the UI in Android. I'm using (Intent)Services to download the data, which works good enough.
I'm not sure how to deal with notifying the UI that data has been retrieved though. After some research and discussion in Downloading data using IntentService - Lifecycle Changes, and Which is the best way to communicate between service and activity?, I'm arriving at a point where I'm not sure which method to use anymore.
The alternatives I'm looking at are:
Service + LocalBroadcasts + Databases
An Activity would start the Service
The Service would download the data into a database
The Service would send out the Broadcast with a 'done' notification
The Activity would pick up this Broadcast and retrieve the data from the database using an AsyncTask
The Activity would retrieve the data from the database using an AsyncTask every time it is shown to the user (onResume, for cases it has missed the broadcast due to the user navigating away).
Service + ResultReceivers + Databases
An Activity would start the Service
The Service would download the data into a database
The Service would notify the ResultReceiver that it's done
The Activity would retrieve the data from the database using an AsyncTask
Instead of retrieving the data every time, the ResultReceiver is reused across lifecycle changes, and notifications are not lost.
Service + ResultReceivers + Bundle
An Activity would start the Service
The Service would download the data (optionally into a database)
The Service would notify the ResultReceiver that it's done, and supplies the data in a Bundle.
The Activity would retrieve the data from the Bundle (No AsyncTask needed).
Instead of retrieving the data every time, the ResultReceiver is reused across lifecycle changes, and notifications are not lost.
Options 1 and 2 require the user waiting for the database read/write operations. Option 3 is therefore quicker, but I've seen many sources recommend not using Broadcasts or ResultReceivers to transfer data (I'm not sure exactly why though).
For now, I am sticking with option 3, but I'm not sure if this is actually a proper approach, and if I'm missing something.
Can someone shed some light on this?
While some people (possibly righteously) vote this question to be opinion based, I am looking for pitfalls I am possibly overlooking. Furthermore, I'm looking for the answer as to why using ResultReceivers or Broadcasts for sending result data is recommended against.
Carefully using some sort of DataManager singleton instance, backed up by a database seems to be a robust solution. Using ResultReceivers, the UI gets notified and pulls the data from the DataManager.
I have also found out that using ResultReceivers and Broadcasts to send data has a negative impact on performance, because the objects need to be serialized. This is a costly operation, and GC might kick in because of it.
im wondering if it would be a bad idea to create a Singleton that is used between some Android Activities and a Android Service. As far as I know the static fields, in my case the Singleton, is available as long as the whole Process is alive.
My plan is to use a singleton instead of Parcelable to share data between my activities and a Background service. So my Activity1 will add some data by calling MySingleton.getInstance().addData(foo); then I would sent an Intent to inform my Service that new Data has been added to the singleton. Next my BackgroundService would handle the intent and call MySingleton.getInstance().getLatestData(); then it would process the data (takes some time). The result of the service would next be "post" back by using the singleton and fire a broadcast intent, which are handled by the Activity1 (if alive) and the Activity1 will retrieve the result from the singleton.
Do you guys think thats a bad idea?
EDIT:
What I want to implement is an peace of software that downloads data from a web server parse it and return the result. So my Activity would create DownloadJob Object. The DownloadJob-Object would be put into the DownloadScheduler (Singleton) which queues and manage all DownloadJobs. The DownloadScheduler would allow to run 5 DownloadJobs at the same time and use a queue to store the waiting. The effective Download would be done by the DownloadService (IntentService), which gets informed over an Intent that the a new DownloadJob should now be executed (downloaded) right now. The DowanlodService would retrieve the next job from the DownloadSchedulers queue (PriorityBlockingQueue) and return the Result by setting DownloadJob.setResult(...) and fires up an broadcast intent, that the Result is ready, which will be received by the DownloadScheduler which would remve the job from the queue and inform the Activity that the download is complete etc.
So in my scenario I would use the singleton to access the DownloadJobs from the DownloadService instead of making a DownloadJob Parcelable and pass it with the Intent. So i would avoid the problem, that I have two DownloadJobs in memory (one on the "Activity Site" and one on "Service site").
Any suggestions how to solve this better?
Is it true that static instances, like DownloadScheduler(Singleton), would be used by freed by the android system on low memory? So would subclassing the Application and hold there the reference (non static) avoid this problem?
If you are using the singleton just as shared memory between a background service which I assume is performing operations on a different thread, you may run into synchronization issues and or read inconsistent data.
If the data in the singleton is not synchronized, you have to be careful because you are relying on your "protocol" to be sure that nobody is reading while your background thread is writing (which may lead to errors).
On the other hand, if it is synchronized, you are risking to face anr error because the activity which reads the data may be blocked waiting the service to finish to write the data in the singleton.
As the other said, you also have to keep in mind that your singleton may be freed if the os needs resources, and that your data may not be there anymore.
I'd rather use an event bus such as otto or eventbus
EDIT:
Using a singleton as the entry point of background (intent) service is the approach suggested in 2010 Virgil Dobjanschi talk about building rest client applications for android.
The suggested approach is having a singleton that performs as controller of ongoing requests. Please consider also that request to intent service are already queued by the os, so you can throw several intents that will be processed sequentially by the intent service.
Some time ago I also tried take that as a starting point for a library, which still remains unfinished. YOu can find the sources here
What I would certainly not do is to store your data in the singleton. The approach I would prefer is to store the data in some persistent storage (such as sql / preferences / file / content provider) and let the client know of the change through a broadcast message (or, if you are using a content provider, through an observer).
Finally, to some extent this is the approach followed by the robospice library, which looks quite mature and ships a lot of interesting features such as caching.
A better idea is to subclass Application and put any long living objects in there. By subclassing Application you can properly handle startup and shutdown of the application something you can't easily do with a singleton. Also by using an Application Activites and Services can share access to the models within your program without resorting to parcelables. And you can avoid all of the problems Singletons bring to your program.
You also don't have to resort to storing everything in a database which requires lots of boiler plate code just to shove a bunch of data in there. It doesn't do anything for sharing behavior between parts of your application and doesn't do anything to facilitate communication and centralization of activities. If you really need to persist state between shutdowns great use it, but if not you can save yourself a lot of work.
You could also look into using something like Roboguice which makes injecting shared models into your Activities and services.
You might find this helpful:
what's design pattern principle in the Android development?
Using a singleton like this is not necessarily a bad idea, but you will lose it's state if Android decides to stop your process. You may want to consider storing your state instead in a SQLite database or a persistent queue (take a look at tape for a good example).
I have an activity that has multiple spinners. Two of spinners values/data need to be populated from data I retrieve from the web via a RESTful service. The data is in JSON format and pretty basic.
I have thought about using an AsyncTask and in the doInBackground doing two web service calls that will populate two different HashMaps but I'm not sure that this is the best approach in regards to designing for performance.
Is there another way to approach this situation? Maybe have a service that fetches the data when the application starts and cache it locally?
Your suggestions would be appreciated.
You probably would want to use two different AsyncTask instances so that the requests run in parallel.
If your data should be persisted you could consider saving it to a sqlite database or storing the json String in SharedPreferences. Using a Service sounds fine as well.
Also if you just want to cache it locally for the duration of the current running program (and don't need to worry about persisting it when the program closes), you could create a simple global singleton cache that allows synchronized access to your data.
As far as actually getting the data itself, AsyncTask is probably the best way (if it's not already cached). Perform the fetch in the doInBackground() method and do the parsing/storing in the onPostExecute() method.
This article can help you a lot:
http://neilgoodman.net/2011/12/26/modern-techniques-for-implementing-rest-clients-on-android-4-0-and-below-part-1/