I have a activity (ListActivity) in which if a user click on a button, I kick off an intent to a "IntentService" which basically makes a REST call to a web service and gathers data.
My problem is that once the service is done, i populate list of items in the Activity which is just a static var. However, I am having trouble kicking off listadaptor to ask it to refresh the view as the data has changed. Can someone tell me how can i "notify" the activity to refresh as the IntentService has completed it task?
If you're making a REST call, I would suggest you use IntentService instead of an AsyncTask. AsyncTask looks nice and useful, but it needs much care not to leak the context and return the result to an Activity that might be as well long gone, which makes it not that easy to properly use.
Please watch this presentation for very useful guidelines:
http://www.youtube.com/watch?v=xHXn3Kg2IQE
EDIT:
As for sending back the result, you can include a parcelable ResultReceiver in your Intent that you start the IntentService with, and notify the Activity (and handle the adapter refresh there) using .send()
As for refreshing the ListAdapter, it really depends on which kind you are using. If it's a simple adapter, you could swap it using
getListView().setAdapter(adapter)
but you'd be much better with CursorAdapter and simply calling
context.getContentResolver().notifyChange(uri, null);
Where context is the Context of your IntentService.
Hope that helps!
Related
Do You know if there is any way to start a Service from the MainActivity, send some data and when the service is done, get the data from the Service. For example:
//MainActivity.class
private ArrayList myList = new ArrayList();
public void fetchDataFromInternet()
{
Intent intent = new Intent(this, DataFromInternetService.class);
intent.putArrayListExtra("MYLIST", myList);
startService(intent);
//In DataFromInternetService the app fetches data from the internet and puts them in the myList.
/*
TODO:
1. Get the data from the service after the it has finished.
*/
}
//Note: The service runs only 1 time.
Also, If this is not possible, what alternative do You suggest, in which MainActivity has access to the data from the DataFromInternetService.class.
Note: I don't want to use LoaderManager, I use Services to do background tasks that don't effect the UI.
To communicate with your service you can use Bound Service:
Please check this:
https://developer.android.com/guide/components/bound-services.html
or you can send your data within: broadcast receiver, database, shared preferences. It depends on your needs.
Instead of using a service to run stuff on the background you should use Async Tasks
you can do the following:
new AsyncTask<Void,Void,Void>(){
doInBackground(){
//DO STUFF
}
onPostExecute(){
//Do What You want with the results
}
}
}
If you want to communicate with your service you have to use bound service and bind to it in your activity. Then create handlers for your activity and also for your service. Using these handlers you can notify your activity once the download is finished.
Please let me know if you managed to solve your problem or some further instructions are needed.
That's the kind of question where any discussion at this point was already finished few years ago, but still bothers us every time we need to choose the most comfortable approach for our app. I don't thing that I should dive into code samples or low level explanations. You can find more than needed information by yourself. One thing I can be helpful(I hope so) is to share my approach.
When I'm facing issues like how to pass data between two different components? - I treat such situations kind of straight-forward. You need to notify your hungry component(activity in our particular case) that's fetching was finished an it can get his info from a trustworthy place. Or to be more cruel, pass the data directly to it. This can be achieved by different implementations/solutions but the abstract ideology remains the same.
What can you do? Here are some links :
Read docs?
Trust Mr. Snowflake?
Broadcasts?
Magic with handler?
I'm even not talking about binding a service or using Event Bus.
And still there are even more valuable solutions, but those are enough.
I have several Activity subclasses in my project, each calling a SOAP based web service, processing and displaying the results. The SOAP serialization, the call handling and the parsing of result into various POJO objects is encapsulated in the MyWebService class. This class executes the actual web service call(s) via an AsyncTask.
For being able to pass back the results to the calling Activity subclass, I figured I enforce that all these activities should implement a WebServiceResultProcessor interface, defining a single function (processWebServiceResults) acting as a callback for the AsyncTask, called from onPostExecute.
I also want to display a ProgressDialog during the web service call. And here comes my question. For being able to display the ProgressDialog (either from MyWebService or it's AsyncTask), I need to pass a reference to the caller Activity's Context. And for being able to execute the callback function from the AsyncTask, I also need to pass the same object reference, but this time as a WebServiceResultProcessor. This seems to me a code smell, passing the same object twice, but can't see any way around that. Instead of interfacing, I could create a new base class, extending the Activity class and enforce inheritance from the extension class, but that would mean I'd exclude ListActivity and the likes from using this MyWebService class.
Is there a better way to do this?
+1, a nice question!
This is not a direct answer on your question. However let me say I think AsyncTask is not a right choice for such stuff. I think so because in this case AsyncTask holds a reference to an Activity (via ProgressDialog instance or the callbacks to be called from onPostExecute()).
Just imagine: in Android the OS may kill the Activity before AsyncTask executes its doInBackground(). This is, of course, some sort of a corner case, but it isn't impossible. Consider a scenario: user gets an incoming call, your activity becomes invisible, the OS needs some more RAM and thus it decides to kill your activity. A memory leak case, at least.
I don't know why Google literally hides the info on how UI should be properly separated from background tasks. Yes, they say "use a Service". But it is not a trivial undertaking. It's a pity Google provides nice guides to almost every development topic, but not on this one. Nevertheless I can suggest to check the "Google I/O 2010 - Android REST client applications" presentation for inspiration. Looks like they gave a key on how such things should be done in Android.
You may have a look into this blog article (part 1 and part 2), which implements a web service with AsyncTaskLoader and the same web service with a Service component. Furthermore it shows the differences between both approaches and there are also interesting comments to the article.
Despite Arhimed's warning, I ended up using AsyncTask, as it still fits my purposes. I just make sure that all Activities calling web services, upon their onDestroy(), send a cancel() to the invoked AsyncTask. The AsyncTask implementation itself gracefully handles the cancel request by checking isCancelled() everywhere where necessary.
As for the original question, I must have had a lapse - the solution is really simple. I pass the Activity subclass instance as an Object to the AsyncTask, and cast it to either Context or to WebServiceResultProcessor, as necessary. Fragments showing how it works:
if (callerActivity instanceof Context) {
ProgressDialog dialog = new ProgressDialog((Context)callerActivity);
}
...
if (callerActivity instanceof WebServiceResultProcessor) {
((WebServiceResultProcessor)callerActivity).processWebServiceResults(soapObject);
}
I'm trying to write an Activity that spawns off an AsyncTask for a long-running operation, and periodically publishes status updates back to the Activity. I'd like to make sure the AsyncTask survives screen rotation or other destruction conditions like OOM correctly.
I've read this thread on the android-developers list, which in turn led me to this implementation, which is almost what I need. However, the last step of my AsyncTask is to delete some data from a content resolver. It is extremely important that this step is not skipped, because the data is sensitive and should not be left on the phone under normal conditions. However, ContentResolvers come from Contexts, in this case the Activity, and with this scheme the Activity may be null by the time the AsyncTask is ready to do the deletion.
Is it safe to get a ContentResolver from the Activity at AsyncTask construction and hold onto that past the lifetime of the Activity? If not, what can I do to handle this case?
Why don't you get the ContentResolver from the Application ? You need to understand the different concepts behind an Activity and Context - just because an Activity is a Context, doesn't mean that you need to use an Activity for all tasks that it does. Use an Activity only for UI stuff
Hey all, this will contain a few questions since I don't seem to really get it.
I have 1 class, the activity. which should display informations.
Then I have a background thread, extends runnable, which keeps getting new data (there for I didn't use AsyncTask, I could use it as a service, but since I hold a some critical resources in it, I would like not have it released when exiting the activity thread)
But I am in great doubt how to communicate between these 2.
First I thought of Intent, but these seem to be used mostly for launching other activities, or alike, and I need something permanent, since data will be in a steady flow.
Then I found out handler, but this doesn't seem to work when my thread is not an innerclass, so I'm thinking about either going back to the old Java observer pattern, if it's not possible to somehow pass the handler to the outerclass.
Any thoughts would be greatly appreciated
Sincerely
Anders Metnik
There is a mechanism for your case - it is called handlers. Read more here.
As for having thread as inner class:
Create your thread as a separate class, add a constructor with a handler parameter and pass it from your activity.
Thread is not suppose to live outside Creator Activity Context, especially you want to preserve it out of Activity, better use Service (and manage the thread) to hold those data.
Intent is the best in terms of communicating between contexts. I think one of the scenario you can adopt is like this:
Application-class: holds those 'permanent' data you mentioned
Service-class: Work (background) and send out "intents" to signal the update state of the operations
Activity-class: Intent Receiver. Whenever intent signal received, grab the necessary data from the Application-class.
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.