Data exchange between a service and an activity - android

I have to publish the progress from a background service on the UI continuously on a progress bar. Any ideas on how to go about it. Intents won't work I guess coz they can only send the data once the activity is started. Ant other suggestions?
Update : The progress on the UI happens on a progress Bar

Extend Application, which is created once for entire application.
When Activity starts, store its reference to a field in your Application object. (Note that you can access Application using Activity.getApplication). Set this field to Activity reference or null in onPause/onResume calls.
Then in Service, you have also access to your Application by Service.getApplication. So look if your Activity reference is non-null, meaning that your Activity is shown to user, and update UI as needed in such case, by calling methods on your Activity.

Thanks for the help mice, but since I needed to update progress bars on different activities in my app depending on which one was visible, I found it easier to implement through Broadcast Intents and Recievers and Intent Filters. All I had to do was to Broadcast the progress in my service wrapped up in a bundle via a broadcast Intent (with a custom Intent Filter applied) and register (in onResume()) an inner subclass of BroadcastReciever in the activities which needed the progress (having the same intent filter). One can also unregister these recievers in the onPause() method of the activity to save memory headspace.

Related

Retrieving triggering Intent from Application object

I have a heavy-duty init process that I would like to run in 2 different places, depending on how the application started.
The heavy-init runs in background with an AsyncTask.
The cases are:
if the application was started from a Widget (via Intent), I need to make the heavy init inside the Application.onCreate
in any other cases, I need to make the heavy init inside the Activity.onStart
In other words, I'd like to know if inside the Application.onCreate there's a way to retrieve the triggering Intent.
thanks
Fabio
As it is reffeered in this link : Android- How to check the type of Intent Filters Programmatically?
You can use the getAction() of your intent to know what type of intent launched the activity.

How to stop an activity started with implicit intent (Intent.ACTION_DIAL etc) from a service

I would like to stop an activity started with implicit intent(using Intent.ACTIN_CALL etc). Is there a way to do this?
Also when we use "startActivity()" function of Context(abstract class), how does it actually start it?
Thanks.
No, you cannot stop an activity.
To answer your second question, when you call startActivity() the Intent that you pass as a parameter is given to the Android framework. The framework performs the appropriate Intent resolution using the contents of the Intent to determine which activity to actually start. Then, depending on the activity that needs to be started, it may need to create a new OS process, instantiate the Application object for that application and finally instantiate the activity object and call onCreate() on it. However, there are other things that may or may not happen during this process, depending on the state of the task that contains the activity, the Intent flags used, the launchMode of the activity as defined in the manifest, etc.

Pattern for notifying events to Activities and Services at the same time

I'd like to know the best pattern for the following scenario:
1) ActivityA contains a button which resets the app data when pressed
2) IntentServiceA, IntentServiceB and ActivityB want to be notified about the event. IntentServiceA clears the app's database, IntentServiceB removes some files from the internal storage and ActivityB, although stopped, remove any pending messages from a given inner Handler
Here is my current design for the situation:
1) ActivityA uses a sendBroadcast() with a specific action (say ACTION_RESET_DATA) to notify the event
2) ActivityB has an inner private BrodcastReceiver which is registered on the onCreate() method since it must respond to the action even when the activity is stopped
3) IntentServiceA and IntentServiceB also have BroadcastReceivers, but they are declared as public static and declared in AndroidManifest.xml. This way, they are accessible without any registration on the corresponding service. All the BroadcastReceiver do is start the outer service, which in turn checks the intent's action against ACTION_RESET_DATA on the onHandleIntent() method
Although it works, there are two main problems I can see with this approach:
There is an intent filter declared on the manifest which is not accessible to other apps. In fact, both IntentService and inner BroadcastReceiver are declared with exported="false"
I cannot use LocalBroadcastManager because it is not compatible with BroadcastReceivers declared in AndroidManifest.xml. That would be desirable since the broadcast in question is internal to my app
I could just remove the BroadcastReceiver from both IntentServices and start them manually via startService from ActivityA and leave ActivityB untouched, but what if the number of services increase? I would have to include code to start all of them? Actually, I have a few other cases like this one in my app and I'm not sure on how to handle them properly.
Any tips?
Try sharedPreferences. When there is a change in value the activities will be notified.
http://developer.android.com/reference/android/content/SharedPreferences.OnSharedPreferenceChangeListener.html

Send data from service to activity and screen rotation

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.

Android Service interacting with multiple activities

I'm trying to refactor/redesign an Android app. Currently, I've one UI activity (Activity 1) that creates a DataThread. This thread is responsible for network I/O and interacts (provides data) with the UI activity via a handler.
Now, I want to add another activity (a new UI screen with Video) - Activity 2. Activity 1 is still the main activity. Activity 2 will be invoked when the user clicks a button on Activity 1. Activity 2's data also comes from the DataThread.
My idea is to put the logic of my DataThread inside an Android Service (DataService). My question is - can more than on activity bind to my DataService at the same time? Is there a way to tell the service to provide data to a specific activity only?
Any other ideas are welcome?
Thanks in advance.
Definitely more than one activity can bind to your service. You will get an onBind() for each one that binds. Your service would then ideally handle the logic of interacting with multiple activities by identifying them using an ID or the intent (with your own IDs for each activities as extras) from onBind() in your service. You could then have the Service spawn off a background thread for each activity that binded to it.
I usually bind my service from the Application class and have some kind of controller class (like a "mediator" I guess...not sure how all these patterns are named) scoped in the application that handles communications between services and whatever the active Activity is.
This would involve writing your own Application class and telling the Manifest to use this one. I went into more detail on this process in a previous thread:
More efficient way of updating UI from Service than intents?
You could keep track of the "currently active" Activity by sending the Application class a reference to itself in onResume (also explained in the example above). This can be accomplished by deriving your Activities from a common base class that has a way of getting your Application class (casting from getApplicationContext), and in this base class' onResume, send a ref of itself to the application. Then, you can register activities by name with your DataServiceController, for example, and send messages to the current Activity only if it's registered with the Controller to receive them.

Categories

Resources