So, I've this HugeService which periodically gets DataX.
In HugeService I also register a ImportantBroadcastReceiver who is listening to important event Y.
Whenever ImportantBroadcastReceiver hears important event Y, I have to go and ask HugeService to tell me the current [periodical] DataX.
My idea:
Whenever ImportantBroadcastReceiver is called I should go and ask HugeService data via some kind of callback, but then again, how does this part work? Is it good idea to pass HugeService instance into ImportantBroadcastReceivers constructor and then call static method that retrieves data (as Receiver strongly depends on Service [it's created from there])? Or is there other/better ways to handle this?
Related
I have an app where I need to establish and maintain a bluetooth connection with another phone. However, this connection needs to remain alive even if the screen turns off.
So the way I've done this is 1) make it a service so the connection can exist in the background and 2) make an explicit call to start/stop the service instead of binding it to the activity (I believe if the screen goes off, the activity goes away, thus the service will stop)
This has now made things more complicated because my service has methods that I need to be able to manually invoke. For example, I want to start bluetooth discovery when the user clicks a button. So on button click, I need to tell this service to call my startDiscovery method. There are many situations like this (e.g. open a socket, pair to a device etc) where I need to manually call service methods
A lot of what I've read on this topic solves this by binding the service, but this I cannot do as explained earlier
Without binding, others suggest to use some sort of event bus, where on button click I send a message to the service. When it receives the message, it checks what type of message it is and then invokes the appropriate method.
OK, this works, but what if my method requires me to pass something into it? For example, lets say I have a list or something that I need to send over bluetooth. So I have a method in my Service that takes a list object, serializes it and sends it over BT to the other phone. But this doesn't seem possible with a basic messaging/event bus system
In sum, how do I pass an object through to a method in a service that is not bound to an activity, but instead has been manually started with startService?
I have seen this question here, but that method only seems to allow me to send objects when I start the service. In my case, the service is already started and sits in the background handling bluetooth traffic. I need to be able to invoke methods and pass objects while the service is already running
I have done something similar in my service. Sometimes i need to manually hide the notification that the service created. So i made the method public and static so it can be called anywhere like this:
public static void hideNotification(){
notificationManager.cancel(0);
}
Then call it in your activity like this: MyService.hideNotification()
EDIT
If you do not want a static method, you can create an empty constructor for your service and then when you need to call the method, create a new instance of your service and call it from that. For example:
In the service:
public class MyService extends Service{
public MyService(){}
public void hideNotification(){
notificationManager.cancel(0);
}
}
When you need to call a method:
MyService service = new Myservice();
service.hideNotification();
I have a BroadcastReceiver which listens to system intents such as Intent.ACTION_PACKAGE_ADDED. When it receives one, the Activity needs to refresh its the data it presents.
Of course, the Activity may not have focus, or may not even be running when this happens. What is the proper way to "leave a message" for the next time the Activity gains focus?
I thought of storing a boolean in the SharedPreferences, but something tells me this is not the right way to go.
What is the proper way to "leave a message" for the next time the Activity gains focus?
IMHO, you have four separate issues here:
Issue #1: How does the BroadcastReceiver tell a running Activity that an event occurred that may be of interest?
Solution: Use an event bus (LocalBroadcastManager, greenrobot's EventBus, Square's Otto), and post a package-added event from the receiver on the bus. Your activity can be registered for events from the bus while it is in the foreground, and it can update its view on the data when your event is received.
Issue #2: How does the BroadcastReceiver update the model data in the SQLite database when the broadcast occurs?
Solution: Delegate this, plus the receiver's side of the event bus logic, to an IntentService, as you need a background thread to do the database I/O. Post the event on the bus when the work is completed.
Issue #3: So, what happens if my activity is not in the foreground at the time the event goes out, but the activity exists (i.e., is in the background)?
Solution: Either reload your data in onResume() or use some sort of a "sticky" event with the bus. LocalBroadcastManager does not offer that, but greenrobot's EventBus has the notion of sticky events, and Square's Otto has a related #Producer construct.
Issue #4: What happens if I do not have an activity instance at all? For example, the package is added when my process is not running, so Android forks a process for me and invokes my receiver, but I have no UI code at all in my process right now?
Solution: Do nothing special. Your existing "load-the-data" logic will handle this case.
One simple solution can be a static variable flag in Broadcastreceiver. Once receiver receives intent, make flag=true.
Activity when gains focus can look at this static variable and can refresh data accordingly and turn this static flag to false.
It depends of what you are trying to do when the Intent is received. If you only want to refresh the content, the the proper way is to use the onResume and onStopto attach the broadcast receiver listener. This will only work while the activity is on the foreground, so every time the user enters the activity again you need to reload the list to avoid the case that this intent arrived while not in foreground.
Another way to proceed if you want to listen it while you are not showing your UI is to create a Service that listens to this Intent with the BroadcastReceiver. Again it depends of the moments you need to receive this event.
To sum up:
For foreground UI: onResume to attach and onPause to detach.
For background: use a Service
I have an activity that shows a map with markers on it. Also I have a location listener, whose values will update the activity arraylist and cause a redraw of the markers based on the updated arraylist values.
I want this to always run (even if the activity is put in the background). I understand that Activity may get killed so I expect that I need a service for the location lisntener. Now my question is: How can I update the activity arraylist and redraw contents when the service is actually the one obtaining info?
I read something about boundservice so maybe I need that? However I need the service running even if activity is killed.
OR Do I just create service and then send a broadcast to activity?
Thank you
Like you have written at the end of your post you could use a BroadcastReceiver for this. That's the way I use it.
In onCreate(...) of your Activity, register it locally:
LocalBroadcastManager.getInstance(this).registerReceiver(...);
in the onReceive(...) method of your receiver, update the required data and unregister it in Activity's onDestroy() method, again using the LocalBroadcastManager object.
Needless to say, you send the broadcast signal from your Service's onLocationChanged(...) method, since it is in the same package as your Activity, the LocalBroadcastManager will forward the signal to your Activity.
LocalBroadcastManager.getInstance(this).sendBroadcast(...);
I am using an Intent Service that performs an action and needs to pass back to the activity that started it the results of the action.
I've searched through dozens of similar posts but as far as i can tell, all solutions i found have a problem. They don't handle well screen rotation. Suppose an activity starts the Intent Service, the service takes 10 seconds to perform the action, and during those 10 secs, the screen gets rotated. The activity gets destroyed and a new one is created.
Use Receiver : It creates a memory leak , as the receiver is bound to the activity that must be destroyed, so the activity never gets destroyed.
Use Broadcast : You have to register a listener, and unregistered the listener before the activity gets destroyed. If the broadcast message arrives after the listener is unregistered, and before the new activity's listener is registered, the message will never be received.
Use Messaging : Same as receiver.
Use Shared Preferences/database with listener : Same as Broadcast.
The solution i came up with, is having the service save the result in a preference file, and the activity checking regularly (lets say every 200ms) for a change in the preference file. Thus, when the screen rotates, the activity stops checking, and starts again when recreated. If the result was delivered in between, it still gets to the (recreated) activity. However, it seems as though this consumes cpu and performs unnecessary reads from the SD card.
Another solution would be to have the service save the result in preference file/database and set a global variable to the time it saved it. The activity has a listener to the preference file/database. Before registering the listener, it checks the global variable to see if the result was put during the screen rotation (global var < currentTimeMillies()) and if true, gets the result, if not, registers the listener. Since the result might be put between the check and the registration, this has to be done inside a block in which the activity holds a lock that the service must acquire to put the result. This would also work, but it is way too complicated.
Is there a simpler and more elegant way of doing it, surviving a screen rotation?
Have a look at my answer to this question:
How to handle IPC between a service and an activity (and its subactivity)?
Perhaps that will give you an idea.
EDIT (Add following suggestion):
Another approach would be to use a Receiver which you create in the Activity. On a screen rotation, the OS will call onRetainNonConfigurationInstance() where you can return the Receiver instance and it will get handed off to the new Activity (see getLastNonConfigurationInstance()). NOTE: These methods have been deprecated in 4.0 and you can use a Fragment and setRetainInstance() to achieve similar behaviour.
I'm writing an Android widget. I have MyAppWidgetProvider which extends AppWidgetProvider.
During the widget's lifecycle, it gets various callbacks called on it: onUpdate, onEnabled, onDisabled, etc. They're triggered by actions ACTION_APPWIDGET_UPDATE, ACTION_APPWIDGET_ENABLED, etc.
According to the App Widget Guide, "[onDisabled] is where you should clean up any work done in onEnabled". I interpreted that to mean that onEnabled may set up some instance state in MyAppWidgetProvider, and onDisabled should tear it down. However, I'm finding that a new instance of MyAppWidgetProvider is created for every single action.
So, is this the expected behavior? Should I always expect a new instance to be created for every callback, or is there some way to configure the broadcast receiver or sender to use the existing instance? If a new instance is always created, then it's unsafe to store any instance state in MyAppWidgetProvider, which is not clear from the docs.
Yes, you can't hope to ahve a single instance of BroadcastReceiver beeing recycled.
The docs states that :
A BroadcastReceiver object is only valid for the duration of the call to
onReceive(Context, Intent). Once your code returns from this function, the system
considers the object to be finished and no longer active.
And as AppWidgetProvider extend BroadcastReceiver, you got your answer. :)
I am not very familiar with AppWidgetProvider but as it is a type of BroadcastReceiver then it is correct that a new instance should be spun up on each event. Processing in the BroadcastReceiver should be minimal. In this case solely to update the app widget with the information obtained from the new intent.