I would like to pass data from activity to service. Currently I am trying to use an ArrayList<HashMap<String, String>>. What options do I have for passing this to the service? I was thinking about putting it as extra data in the intent but I'm not sure how to do this. Or is it possible to have this set up as some sort of global?
At the moment it is set up as a static of the activity, and the service is calling back to the activity to be provided with the next item from the ArrayList. I'm not happy with how that is working, so would like to move the list into the service.
EDIT
In response to the questions raised below:
I am trying to pass a playlist (yep, another media app) to the service. The playlist ArrayList<HashMap<String, String>> contrains paired song info, such as "songTitle" , "this is a title".
I think however that i am getting confused with the lifecycle of the application. When a user clicks play, the service is created. If I used a static for the list, when the service is created it would see that list. So the service will happily continue to play songs from this list. However, if the user changes folder etc, how do I get the app to recognise the change in playlist? The way the app is designed, the user can untick tracks in the list at any time, or can browse to a different folder. When the song completes the new list should be loaded. What is the best way of doing that? Or is the way that I am doing it now the best way? When the song completes send a broadcast back to the main activity requesting the next track. Should I destroy the service at this point and allow the "next song" function recreate it?
Lifecycle confusion!
Have you considered storing the data in a database and simple sending the intent that data has changed? Or use a ContentProvider that signals "by itself" that data has changed and needs to be reloaded? That way you won't use state even if the app closes unexpectectly.
Both ArrayList and HashMap implement Serializable, so you should just be able to stuff your structure in an Intent, and retrieve it using Intent.getSerializableExtra().
From your Activity, all you need to do is call the Intent.putExtra(String name, Serializable value) overload.
As a rule of thumb, try to avoid having static variables hanging out in your application if possible. They get tricky when your app is shut down by the OS and then recreated (i.e. from the recent apps list).
Related
The home page of my app displays a list of records. Another page allows adding a new record. After creating a new record, on hitting the save button, when the app goes back to the home page, I want the latest record to also be displayed.
Is there a better way of retrieving all the records rather than fetching them all from the SQLite database in a call inside onResume()?
You can save the created model in a background job/thread and then call finish() only after the save is done. You can also display a loader in the meantime.
After that, in your home Activity/Fragment (?), do another background job (in order to not freeze the UI) to retrieve the data from the SQLite. When the job is done, display it. Again, you can always display a loader while the task is running.
Simple way : have a look at AsyncTask
I have a Service which runs in the background when my app starts, and continues to run after the app is closed. It implements a Loader.OnLoadCompleteListener<Cursor> for a registered Uri from a Content Provider. When a new Cursor object is delivered on the callback method onLoadComplete(Loader<Cursor> loader, Cursor data) I then run an AsyncTask using the Cursor to create an ArrayList of custom Objects that implement the Parcelable interface. Once processed, if the app is open it sends back to the App getting marshalled/demarshalled using the IPC framework using a Handler with Messenger,Messages and aBundle. If the App is not open then the ArrayList is ready to be sent back to the App once opened, which calls to the Service when opened.
Problem:
The ArrayList can get relatively large (it doesn't contain Bitmaps, only Primitives and several short String objects) and the sheer amount means it hits the FAILED BINDER TRANSACTION when the ArrayList gets to about 700 objects.
Current Solution (that feels a bit hacky)
I am splitting the ArrayList into chunks and sending several Messages back to the Handler where it is then reconstructed into one ArrayList and then used in the App (updating RecyclerViews etc..).
I use this approach as the performance is significantly improved - only need to do initial query when App/Service is started first time, rather than always querying the Content Provider every time the App is opened.
The reason I say 'hacky' is because this feels like a workaround for a limitation of the Binder Framework rather than a solution.
Any advise on approaching this differently would be welcomed.
Two alternatives that come in my mind is:
Having a static ArrayList inside your service and sending a broadcast when the cursor received to the Activity to copy the contents of the static Arraylist which is inside the service in the local arraylist inside the activity. With this way Activity only has reference of the static aarraylist only the time it copies the contents.
I would save the contents in sql database asynchronously and then send broadcast to activity to retrieve asyncrhonously again the cursor from the database. On the UI thread then I would call notifydatasetChanged on the adapter.
I have question regarding my previous ListView activity.
I have my ListView which is continue updating using socket connection, now when I click on any of the list row i can go to my next screen now when i come back to my previous ListView screen my ListView is start updating again but i want to keep updating my ListView in a background when i am on my nextscreen.
Something like i want to keep my previous screen alive when i am on my nextscreen.
Sounds to me like your the code you are using to load the data for your ListView is tied to your Activity.
For instance you have an AsyncTask or Thread in your Activity that cointains your ListView and you use it to download data, or do whatever is needed to get the data to populate the list. I also assume you start it in one of the Activity lifecycle methods e.g. onCreate().
If that is the case then you should consider seperating the code used for getting the data for the list from your activity code.
One way to do this is to use a Service which will be able to run independantly of the rest of your application and do all the heavy lifting involed with fetching the data for your list. You can communicate with the service from anywhere in your application. The Service can save the data to a database. Then all you have to do in your Activity is query the database and populate the adapter to get the latest data without much delay.
You can read more about services here:
http://developer.android.com/reference/android/app/Service.html
You could (and probably should) do what Paul suggested or you could change to way you switch your screens by using Fragments or a ViewFlipper. This way you still run your AsyncTask or Thread while doing something else on a different page.
Is there any way I can go from one activity to another and delay the display of the screen on the target activity?
What I want to be able to do is to allow the target activity to fetch its required data but not to display anything until does.
I want the screen of the source activity to still be visible until I am ready with the data in the second activity.
Specifically, I am using an AsyncTask to fetch the data.
I know I could fetch the data in the source activity and then send it on to the target activity but this is not viable in our case.
Edit: More Info:
The whole reason I want this is because I am trying to change the structure of certain parts of the current code.
At present the way it works is the the first activity gets the data and then sends it to the second activity as a bundle.
This created problems when the second activity could be invoked from multiple places. It resulted in loads of duplicate code.
So, I decided to move the fetching of the data into the target activity thus cutting out any need for repeating code.
it also makes more sense for the activity to fetch its own data rather than relying on something else sending it.
You should first make a service that runs your async task. Then, start the service from your first activity with startService(new Intent(this, UpdaterServiceManager.class));
When the task ends in the service, start the second activity.
Click here for an excellent service tutorial.
Try to use service for this purpose.
I would like to write an app to follow the price of lists of stocks.
There would be three activities containing lists of stocks :
myStocksActivity containing the stocks I'm interested in
searchedStocksActivity containing a list of stocks I could add in the list contained in myStocksActivity
winnersLoosersStocksActivity containing the list of stocks with the best or worst performance of the day.
I would like to persist the list of stocks in myStocksActivity, to be able to remove or add stocks from that list and to add the stocks displayed in searchedStocksActivity or winnersLoosersStocksActivity to myStocksActivity.
Another challenge : the price of the stocks should be updated every X minutes depending on the settings of app. The prices should only be updated when the app is running and should only update the prices of the list I'm currently looking at.
For the moment, my architecture isn't great : almost all the logic is contained in myStocksActivity and I know it's not a good thing.
I was thinking about moving the update of the stock list to a service, but I don't want this service to run when the application is not running.
What do you think ? Is my problem clear ? Thank you !
If I was you I would try and design(and build) a domain model first. This should end up being a set of classes which allows you to do everything you want with your stocks, independently of the a UI. You should also build in data persistence directly into these classes (i suggest using SQLite for this bit).
Then once you have a working model, build the UI on top of that. The MVP design pattern works pretty well with android.
Implement your activities as Views, these should both present data, and captures UI events and delegate these events to to Presenter instances, which then communicate/manipulate the model, and updates the Views accordingly. For example,
MyStocksView could present the user with a list of stocks, and the latest movements of stock price (or whatever). The MyStocksView contains the actual widgets that make up the user interface, and also acts as event listener and handler for various UI events (like when the user click a button). It should also contain a instance of a MyStocksPresenter class.
Once the user clicks the button, lets say, "remove stock", the event handler of MyStocksView then fires a method in the presenter instance for example, presenter.removeStock(id) , this method then updates the model (removes it from the in-memory data structures and database) and finally, if everything was successful, updates the View. It basically works as a middle man between the presentation layer, and the data-model.
In regards to the automatic updates every X minutes, I would handle this with a AsyncTask, there's not really much point in using a service if you only want this to happen while you app is running.
Whenever you main activity gets paused (or destroyed), call StopService(blabla);.
That way you can keep it as a service, and it won't run in the background.
Create a class for a stock, and store the update logic in there
I would put the handler - what holds instances of the stock-class and loops over a set to tell them to update - either in its own class purely with static methods and variables, or also in the stock class with static methods/etc.
The service then contains timing information, and calls the static update() method
The activity that displays stocks starts/stops the service with onCreate/onDestroy or onUpdate/onPause (I think it's update; the on that happens each time the Activity is brought to the forefront)
Same activity tells the handler class which ones to load, and uses its list for the display.
One other thing: I'd suggest against using a service. Use an AsyncTask. Services actually do run on the UI thread, so if there's a long-running loop during the update, the UI will freeze. AsyncTask starts a thread and will not block the UI.