I'm currently working on an app that is composed of a background IntentService running all the time (even when activity lost focus) and a Activity (a section pager with fragments).
The background service is checking time very often and storing a large array of objects (up to 300) parsed from an xml file.
Each object represent an event with an associated startTime and when this startTime matches the current time the service has to notify the activity (if available) to display that the event is happening.
On the activity side I have fragments (tabs of the section pager) with a custom arrayAdapter to list the events into a ListView.
Right now what I'm doing is sending my object from my service with a LocalBroadcastManager. Fragments are the listening and when they receive the object they simply update their local Arraylist by replacing it and notifying the ArrayAdapter that the data set changed.
Since each fragment has to keep an arrayList to update the ArrayAdapter and then the ListView, I end up with the same object stored both inside the service's array and in one of the fragment' array. I'm wondering if there is a better way.
The question : What would be the most efficient (on memory/cpu usage and speed) way to share a large array of objects between my service and my activity ?
You could use greenrobot's EventBus. I don't think you can avoid duplicating the data. If you will use the same object instance in the Service and in the Fragments, you'll have to take care to notify the adapters each and every time, otherwise you'll get errors.
You would be better off storing the downloaded objects in a local SQLite database and only loading the minimum amount of information needed in the Fragments. This would minimize the time it takes to transfer the data from the IntentService thread to the Activity's main thread (because you wouldn't even transfer the data, just send a signal to the current Fragment that the data has been updated). A ContentObservable may also help you.
Also, you shouldn't use an IntentService for tasks that run all the time. The IntentService is intended to run a single task and finish, being started again the next time you need it to run another task. You should use a plain Service with a Thread or HandlerThread inside it. You will have better control this way, and you will also be able to run multiple tasks in parallel if you need to.
Related
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 ListView which shows, through an Adapter, the data from a global ArrayList. If I want to add an element to this ArrayList the proper approach is to do that in the main (UI) thread and immediately call Adapter.notifyDataSetChanged() afterwards, in order to avoid an "IllegalStateException: The content of the adapter has changed but ListView did not receive a notification". However the ArrayList is changed in a secondary thread, executed by a Service which is not bound to the Activity all the time, and thus does not always have a reference to the Adapter in order to post these operations in the main thread queue. So when (I suppose) the main thread runs into the changed list, the exception ensues.
I see two ways of circumventing this:
Make the Adapter global so I can reference it any time I want.
Clone the list and make the Adapter backed by the clone. Thus when the original list is changed the clone will remain untouched until the moment the main thread needs to exhibit the changes (e.g. on Activity.onResume()), at which I update the clone based on the original and call notifyDataSetChanged().
The drawbacks of the second approach seem to be the apparently unnecessary redundancy and the memory overhead (although the list is not big, at maximum some 500 objects of 12 fields each). I tend to choose the first one, but which one do you find best? If there is a third approach, please let me know.
As you've not shown your code, I don't know if this might help, but have you considered using a CountDownLatch? in the manual page comes a perfect example on blocking the execution of a thread until the Latch is released. You could simply declare an instance in your main Activity and pass a reference to the Service and other involved parts.
As your service is unbound, you might use a BroadcastReceiver to pass the instance to the service, or even using a Semaphore instead, as this last is serializable and thus able to be put as an extra to an Intent (you would need to bind the Service in that case, though).
I have an array adapter which is used in my listview. The adapter is periodically updated by fetching or removing contents from a server. I have used a scheduledthreadpoolexecutor to periodically update the adapter and then use adapter.notifydatasetchange();
The list view gets refreshed and removes any items etc, but for example if two items where removed from the list when I scroll the listview on android and get close to the end of the listview the application crashes. I guess something does not get updated in the listview and it things that the size of the list is the initial size.
Do you have something to recommend?
Regards,
Aris
Hi all,
I actually found a solution to my problem and forgot to check here for any replies.
Thank you all for your suggestions.
Basically scheduledthreadpoolexecutor called a runnable (lets call it updateRunnable) to do the updates.
What I did was the following:
In the updateRunnable, when it gets the new data and stores them in the array adapter, it then calls another runnable (lets call it updateListView) using runOnUiThread and in updateListView I set the adapter of the listview.
This solved my problem
If your data is at all database-like, which I assume, given your use of a ListView, then you'll want to refactor your background service into a model that uses a ContentProvider and SyncAdapter to stay in sync with the server, and then automatically notify the ListView through binding it with a CursorAdapter which uses its implementation of ContentObserver to automatically update the list when the underlying DB changes.
Why does ContentResolver.requestSync not trigger a sync? tells you how to set up the ContentProvider.
How to handle REST calls, data persistence, syncing and observing ContentProvider tells you a little more about how list update notification operates once the ContentProvider is syncing.
It's a lot of infrastructure work to get set up, but once you do, there's so much that's wonderfully automatic about the SyncAdapter model.
I had a similar problem once. Since the ListView keeps updating you can
1) display the Listview just as the activity starts in OnCreate, and
2) call this SAME activity so as to display refreshed data in the listview.
but after calling the same activity again, finish() the current instance first immediately since you can get multiple instances of it one over the other.
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.
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.