Okay so up front I will say that I am new to Android. I have made a few small projects and played with a few things and done tons and tons of reading. So here is the task I am trying to accomplish:
I have a remote service that runs in the foreground of my phone that can send and receive information with other android devices over a wifi network. APK's on the phone that are built to use this service contain multiple SQLite DB's. I want these APK's to register there content providers with the service so the service always know where to put data that it recieves (I have accomplished this task). When data comes in I will identify where it belongs and place it in the right DB (no problem here). So what would be the best way to notify the correct activity that new data has been received. Do I register Broadcast Receivers for my service to call? Will Broadcast Receivers work if the APK has been killed by the OS? Once the correct activity is loaded would I use a content observer to show the new data? Why would I use IntentServices?
I'm sorry for so many questions. Like I said I am learning fast but Android's SKD is massive and there are so many cool things. I want to make sure I am thinking things through right with best practices and making this very easily maintainable and expandable. Thanks for any help or advice I can get.
If you are asking what the best way is for a current Activity to know data has changed in the ContentProvider it is reading from, than the answer is a ContentObserver.
Lets say, for examples sake, you have a set of Activities and ContentProviders. Activity A is a list view of items from Content Provider A, and that list view is populated via a CursorAdapter of some kind. Whenever you have a query on a ContentProviders CONTENT_URI, the cursor should automatically monitor the CONTENT_URI for changes via a ContentObserver.
The reason this works is because in the ContentProvider:
Your query method calls setNotificationUri on your cursor to the URI that was queried.
Whenever a change happens in an insert/update/delete method, you are calling notifyChange on the URI.
If there is additional data that can change in your service that is not tied to a ContentProvider, than you have a few choices on how to pass data. If the Activity is in the same APK as your service, than you could use some sort of static variable, or the application context, or some other custom form of communication. The methods are rather liberal here because you are running in the same VM, so you have a lot of things available to you.
In your situation, it sounds like most activities will be in separate APKs. If that is the case, you will probably want to send out broadcast Intents to let the entire system knwo about the changes. If these changes only matter when an activity is running, you can register a BroadcastReceiver for the life of the Activity that cares about the change. Alternatively, you could put a BroadcastReceiver in the applications manifest, and always receive that change.
That brings us to IntentServices. IntentServices are the "easiest" way to handle long running tasks in Android. All they do, is create a background thread that will handle intents being sent into the service. A common use case is as follows:
You receive a broadcast intent that you need to react to (and it will take a while)
Send a directed intent (intent with a set component name) to an IntentService with some info from the broadcast intent.
IntentService either spawns a new BG thread, or adds the intent to the processing queue on the existing BG thread
The onHandleIntent function is called in the IntentService so that you can now process that change using as much processing time as you want.
Related
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.
My fragment represents dynamic information which is obtained asynchronously. I am interested in how to provide the DAO/DTO to the fragment. Should the fragment maintain a reference to the DTO? What about updates. Should it request updated DTO and be the listener on these async calls or request that the activity make the requests and then update the fragment when the async response arrives?
There isn't really a "best practice" way to do this in Android. There are many ways and many of them are valid.
My recommendation would be to create a service that keeps track of changes in the data and report back to the fragment that requires it. Should be careful with this and make sure the service is only active when required, otherwise we can get background tasks that drain the battery.
The simplest way to register a BroadcastReceiver when the fragment is visible (after onResume, remove in onPause). This is like the intent filters that you can set for activities in the manifest. Here is a nice example: http://www.vogella.com/articles/AndroidBroadcastReceiver/article.htmlz
Once the receiver gets the intent there are 3 possible ways to procede.
Create a DAO and access the data (possibly a bit slow)
Use a ContentProvider and receive the new items in the intent sent to the receiver
If your data is Serializable or Parcelable you can add the new new data to the sent intent. (Possibly the fastest)
UPDATE
There is a useful tool for this kind of task that I forgot to mention: Loaders
They provide a simple way to handle data sources (like content providers).
I am developing an application which has around 8 Activities, and a class which is used to connect/receive data to/from an embedded Bluetooth chip. When I started, a Bluetooth object was initialized in my initial Activity, where there was a Handler which received messages from the Bluetooth object.
After poking around on the internet for a while, it seems like the best idea for me is to turn my class into an Application subclass. However, doing this removes the need for me to initialize an object in the MainMenu, which removes my ability to pass it the Handler used.
Does anyone know of a way to eliminate the need for a Handler, so that every time the Bluetooth Application changes it state or receives data, the current Activity can access it?
My main problem with this approach is that the Activity doesn't know when the Bluetooth Application will be sending it messages, the Application waits and listens, and then notifies the Activity when it happens.
OR
Is it bad practice for me to write the Handler into the MainMenu, have it handle messages for ALL the different activities, and then pass the Handler from Activity to Activity?
I'm going to assume that you're trying to achieve the following as it's a little unclear from your question your ultimate aim (sorry!):
Your application has several activities but only one Activity receives the data from the bluetooth device.
The other activities in in your application require the data from the bluetooth device but are not receiving it directly from the bluetooth device. Currently you're providing the data via the one activity mentioned above.
You want to NOT use a Handler to achieve this.
If my above assumptions are correct then you are going along the correct lines but you probably do not want to use a Handler.
You are quite correct in having one Activity handle all the interactions with the Bluetooth device. It simplifies things and provides a much better, cleaner way of handling the Bluetooth device. However you need to get the data from this one Activity to all the others and to achieve this you would probably want to use Broadcasts, BroadcastReceivers and Intents. See here for an overview.
However if you can you might want to take a look at using LocalBroadcastManager as this keeps any broadcasts within your own app's space. Broadcasts are global and should be avoided if you do not need to pass the data outside of your own app due to security implications.
Finally, have you considered using Fragments for your other Activities? Another disadvantage with Broadcasts is there is extra overhead associated with them. If you're keeping data within your app then you can create an interface to be implemented by each of your Fragments and your main activity just calls that interface on the Fragment that is currently selected.
You can use BroadcastReceiver class to send broadcast messages to your activities. see here http://developer.android.com/reference/android/content/BroadcastReceiver.html
When you get the data you need into the application class, you can send it to the activity you want.. just make sure that the activity has registered to receive that broadcast message..
So I'm working on a service that will handle requests to send data to a socket.
I've done socket programming in a service before, but only within the same application. I'd like this to just sit and do nothing until any application wants to give it data to send. That's all well and good.
I have register an intent filter and the usual stuff and can process the data. But I want to process the data coming from different activities in different threads (subsequent calls from the same application will be computed on the same thread).
Is there a way to get the calling package or app or whatever? I'd prefer not to require passing in an identifier as an extra to prevent spoofing. (It's not a serious security concern, it's just each application needs its data processed in the order that it's received.)
I had run to the same issue in the past. I couldn't find a way to know how send the intent and I ended up adding an extra.
If you don't want to use an extra perhaps you might want to set an Action but it's almost the same thing.
Is there a significant difference in time needed for sending data over a service or by using an intent?
Are there general advices when to use service and when to use intents?
These are two completely different things. The question isn't which is faster, but what you are trying to do.
If you want to transfer data from one activity to another, you pass it through the intent. If this is not sufficient for you (too much data for example), you can take other approaches but they will not involve a Service. For example, you may have a singleton holding your shared data, which both activities access... but be extremely careful about your process being killed at various points which causes the singleton to go away (and using a Service for this won't let you get away with not dealing with such a situation).
A Service is to do some work in the background even if the user isn't directly interacting with the app. Especially if we are talking about stuff within one .apk (and thus typically one process), there are very few other reasons to use a Service.
It depends of what you need.
Intent is preferable if you can. You will be able to send primitives from an activity to an other, and using startActivityForResult() you'll get an intent back to the caller Activity.
Service is for data processing in the background and can be very CPU/Memory consuming. With a Service, you have to create an interface between your Activity and the Service, so you can call basic methods of the Service directly from the Activity, you can control the service from the Activity.
This is really not the same purpose. Read documentation about Intents and the information you can Bundle in it, that's probably what you need.
When you want to pass data from your current activity to a new activity, the best is to pass a Bundle along with your Intent. It is used to pass on "acquired" user data.
Services run in the background while another activity is still in the foreground. "Background" doesn't mean that it doesn't display - most services have a graphic visualisation of some sort - it means that it isn't part of the activities stack. For example, your Activity may be sending a text message and your Service may be a soft keyboard. Services can communicate with activities - in this instance, your keyboard of course needs to send the characters to the text message Activity - but it often involves using a rather complex interface. It is used for collecting and passing on "live" user data to an Activity.
Many methods to pass data between activities. See here for tips on a way to choose.