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.
Related
I have a Background service that sometimes needs to start an activity. I would like to wait for this activity to be created (that is OnCreate() has exited).
Once the activity has been created it has registered for receiving messages.
I'd like the background service to send a message once the activity is created.
How can I do the waiting without blocking?
Well I ended up with using an IOC container to share an object instance between the the two contexts. This object would contain an AsyncAutoResetEvent for the activity to set and the service to await.
I have one service and two activities. I from one Activity go to another, and in the onStop method, do unbindService.
When I came in the second Activivity the service destroyed.
When the second activity calls the bindservice, a new service is created.
How to make so that the service is not destroyed?
If you want that service should not stop when migrating to next activtiy,then you should use IntentService instead of Service.
InetntService don't have any UI,so it will contiously runs in the background without user interaction and when it finishes then you have to store its data somewhere (or you can use the broadcast reciver )and populate that data in the next actvity if you need.
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.
In my application I start a Register activity from the Main Activity with a button
startActivity( new Intent(getBaseContext(),Register.class));
This Register activity creates records that can be viewed in a ListActivity.
If I go to the ListActivity from the Main Activity (with another button) and decide that I want to send the data of a record from the ListActivity to the Register activity in order to edit it, there are two possibilities:
1- the Register activity has never been called
2- the Register activity is opened in the background
I have two questions:
-Calling startActivity Register.class once from Main and once from ListActivity will it make two copies of Register or one?
-When I call Register activity from ListActivity and try to pass data with a handler, the handler message arrives before the activity is opened and the data do not show in the Register screen? How can I do that? Is there a way to know from the ListActivity when the view of Register is opened?
Thanks.
Charles.
The first question has a complex answer, but shortly you can control instantiation of activities, only it has implications in flow of user interaction: see Activities and Tasks, particularly Launch modes.
For the second, I don't know what kind of data you're going to pass, but consider putting it in the intent with some Intent.putExtra() method (there are many for many types of data).
I have a class that fetches data in response to button presses in the main activity. Unfortunately, I keep running into problems because this class is not an Activity or a Service. For example, without a Context I cannot translate a resource id into a string:
getString(R.string.example_string); // Doesn't work
Should I make this class into a Service and have the main Activity stop the class when it is closed? Should I pass the Context from the Activity into this class like this?
MyClass c = new MyClass(this);
Or is there some better way to handle this problem?
This issue also comes up when I try to send a Toast from this class.
Update: Erich and Janusz pointed me in the direction of the AsyncTask class which works perfectly, except that it creates a new thread and never kills that thread. This means that ever time the user presses a button, another thread is added and the old ones just sit there.
If you have a background action whose lifecycle is decoupled from your activity, I would use a Service. In that case, the Service will have its own Context, so you won't need to pass it in. If, however, you need to perform a background action in response to a UI event (and optionally post the results back into the UI thread), I would recommend you use an AsyncTask.
I agree with Erich, if you only have a something small like posting a change to a web backend or loading something from the phone memory to show it on screen use a Async Task. If the task will exit very "quick" (some seconds) you can make an anonymous class inside your activity. This will enable you to use a implicit reference to the outer activity inside the task and you can get your context from there.
If the task is running for a longer time you can pass down the context. If you are passing down the context try to not pass this from the activity use this.getApplicationContext() this will minimize the number of references to your activity and enable the garbage collector to clean up properly.