I have problem with AsyncTasks.
My application is simple: ListView and Activity with custom Extras.
In Activity class I have some AsyncTasks with DefaultHttpClient (Downloading Jsons, Images)
When I wait until AsyncTask load everything and then go back to list and choose another row everything is fine.
But If I start my activity and immediately press "back", then choose another row, then new activity starts, but with task of the previous AsyncTask ( inappropriate images and strings ).
After a while everything back to normal(AsyncTask download proper content), but I want to avoid downloading unnecessary data.
How to not stop, but remove AsyncTask permanently when I press "back" ? Or maybe is other way ?
I will be grateful for the help.
Edit:
Of course I use cancel method:
Activity.class
#Override
public void onDestroy() {
super.onDestroy();
lastFM.cancel(true);
}
AsyncTask.class
#Override
protected String doInBackground(String... urls) {
if (isCancelled()) return null;
inputStream = getInputStreamFromHttp(urls[0]);
if (isCancelled()) return null;
jsonObject = getJSONObjectFromInputStream(inputStream);
bio = getBioFromJSON(jsonObject);
return bio;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
if (!isCancelled()) {
Intent i1 = new Intent(ActivityStation.UPDATEFRAGMENT3).putExtra(ActivityStation.ARTISTBIO, s);
LocalBroadcastManager.getInstance(context).sendBroadcast(i1);
}
}
There are techniques to leverage AsyncTasks to avoid this problem. Rather than dwelling on the details of these techniques, I would advise you to look at Loaders (specifically AsyncTaskLoader) which will handle the nuance of managing state for you. Have a look at this link: http://developer.android.com/guide/components/loaders.html
Calling
myAsyncTask.cancel(true);
will attempt to cancel the task. After this has been called, inside the AsyncTask's doInBackground() method, check
isCancelled()
to decide whether to stop or continue.
The simplest way to kill the asynctask
Shoutdown the HtppClient it will automatically stops the http requests
httpclient.getConnectionManager().shutdown()
Related
Experts,
My goal is simple, input an address, click a button to test a URL, if not get the expected result, a toast info and then do nothing. If get expect result, continue the program.
Since I can not use URL in UI thread, I used AsyncTask, the problem is: though I know the result from AsyncTak, how to inform activity to do or do nothing?
What I want is a statement inside the OnClickListener like this:
if (result is not expected) return; else continue do things.
I cannot write above statement in onPostExecute, it will return onPostExecute(), not onClickLIstener().
Another is: even if I can pass the result to activity(namely to onClickLIstener()), when the result arrives, probably UI thread already run some other codes, but they shouldn't before knowing the result.
In short, I need the URL result to decide how to run remaining codes, therefore cannot use async task, what should I do?
Thanks.
Below is the example code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
btnConfirm.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new XXX().execute(code);
});
}
class XXX extends AsyncTask<String, Void, String> {
protected String doInBackground(String... strArr) {
XXXXX;
}
protected void onPostExecute(String result) {
XXXXX;
}
}
This should be easy. Try this approach:
Since you already have your AsyncTask as an inner class in your activity, you can easily return a result in onPostExecute() then check if request was successful or not.
Now, here is the final part: create a method in your activity like this:
private void executeOnAsyncSuccess(){
//place the code here you want to run
}
Now you can call it inside onPostExecute() easily!
You can also do this using Events but this approach should just work!
I hope this helps!
I just learned that maybe Callable is a good way, use its V get().
I have a loading activity which makes few requests to server and converts data.
And layout of this activity is just simple logo image and progressBar.
All my operations were made in onCreate() and according to received request from server I start different activities:
if (request == 1) { start activity A}
else { start activity B}
The problem is loading takes 2-3 sec and operations are made even before onResume(), before activity's view come to UI.
So its just blank activity which does some work.
How can I ensure that those operations are made only after activity complete its creation?
If i clearly understand you you want to start activity 0 in which onCreate function is doing internet requests and after getting feedback from it you decide to call activity A or B. Is that correct? If yes you need to do network request in backgroud so your user interface thread doesnt freez. You can use AsyncTask for example and on it's onPostExecute method decide to fire acitivty A or B
EDIT
private class YourAsyncTask extends AsyncTask<String, Long, String> {
protected Long doInBackground(String... params) {
//here is background thread work calling net API request, hard working etc... but you can't touch UserInterface thread, since we are in background
//here call your API and parse answear
String ret = flag
return flag;
}
protected void onProgressUpdate(Long... progress) {
}
protected void onPostExecute(String result) { //here you are getting your flag from doInBackground as a result parameter
// this is executed after doInBackground, fired automatically and run on User interface thread here you can for example modify layout so you can run activity A OR B
}
}
and if you have your logic in AsyncTask you can run it from onCreate for example it doesn't matter.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_layout);
new YourAsyncTask().execute();
}
So you layot will be displayed and after executed your onPostExecute will be called
You need to move that server call off the main ui thread. Use an IntentService or something similar.
What I understand from this question, you must be using AsyncTask or Service to connect to server. You put the main thread in while loop and AsyncTask or Service is doing the required operation for you. After operation is complete, it will break out of while loop and then use if/else loop and decide which activity to start next.
Something like this:
public void onCreate(Bundle savedInstanceState)
{
boolean isDone = false;
// initialization code here
// start AsyncTask
BackgroundThread.execute(params);
while(!isDone)
{
Thread.sleep(1000); // 1 sec
}
}
doInBackground()
{
// your code
isDone = true;
}
onPostExecute() is executed on main thread, not on background thread.
I have a download activity which downloads some zip files for my application.
I want my activity have this features :
capable of pause/resume download
shows download progress in my activity's UI by a progress bar ( not with
dialogProgress)
shows notification with download progress and when user clicks on the
notification it opens my activity even when the app is closed and my UI keeps updated during download
I have searched a lot and saw lots of methods that can be used to download files (like using AsyncTask/Downloadmanager/Groundy ... ) but I don't know which one of them has the features I want
what do you think is the best way to achieve this features all together ??
I don't want the full code from you, just some tips and methods or references to help me implement each of these features and find the best way.
Thanks for your time.
Fundamentally you can use AsyncTask through which you would be able to achieve the above, if the download is strictly tied to the activity. However AsyncTask needs to be properly cancelled once user cancel or back out from activity. Also it provide basic mechanism to do the progress thing.
For example, imagine a simple async task (not the best implementation) but something like below
class SearchAsyncTask extends AsyncTask<String, Void, Void> {
SearchHttpClient searchHttpClient = null;
public SearchAsyncTask(SearchHttpClient client) {
searchHttpClient = client;
}
#Override
protected void onProgressUpdate(Void... values) {
// You can update the progress on dialog here
super.onProgressUpdate(values);
}
#Override
protected void onCancelled() {
// Cancel the http downloading here
super.onCancelled();
}
protected Void doInBackground(String... params) {
try {
// Perform http operation here
// publish progress using method publishProgress(values)
return null;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute() {
// If not cancelled then do UI work
}
}
Now in your activity's onDestroy method
#Override
protected void onDestroy() {
Log.d(TAG, "ResultListActivity onDestory called");
if (mSearchTask != null && mSearchTask.getStatus() != AsyncTask.Status.FINISHED) {
// This would not cancel downloading from httpClient
// we have do handle that manually in onCancelled event inside AsyncTask
mSearchTask.cancel(true);
mSearchTask = null;
}
super.onDestroy();
}
However if you allow user to Download file even independent of activity (like it continues downloading even if user got away from Activity), I would suggest to use a Service which can do the stuff in background.
UPDATE: Just noticed there is a similar answer on Stackoverflow which explains my thoughts in further detail Download a file with Android, and showing the progress in a ProgressDialog
so I am coming across a weird problem I cant find an explaination for. I have an async task in which in its doBackground method does a wait until a certain variable is set then the "wait" is notified
private class TestAsyncTask extends AsyncTask<Void, Object, Boolean> {
#Override
protected void onPreExecute() {
Log.d("Test1");
}
#Override
protected Boolean doInBackground(Void... params) {
Log.d("Test2");
while (nextCardToPlay == null) {
wait();
}
Log.d("Test3");
}
}
Activity A:
protected void onCreate(){
a = new TestAsyncTask().execute();
}
protected void onPause(){
a.cancel()
}
So as you can see when the activity starts, the asyncTask is started. When activity is closed the asyncTask is supposed to be cancelled.
What I noticed is that if I open the activity, close it, and reopen it again then the asynctask is created and in wait mode (never cancelled). No problem. Whats confusing is that when I start the activity (while the stale asyncTask is there), then it seems a new asyncTask is started ( because the logs from OnPreExecute are called) however the doInBackground in the nextAsyncTask is not executed because the Test2 log is not showing.
Any idea why?
This behavior is not at all weird if you look at the documentation, which states the AsyncTasks run on a single background thread, i.e. sequentially. If you really want your tasks to run on parallel worker threads, then use the executeOnExecutor() method instead of a simple execute() and pass it the AsyncTask.THREAD_POOL_EXECUTOR parameter.
I need my Android app to periodically fetch data from a server using AJAX calls, and update the UI accordingly (just a bunch of TextViews that need to be updated with setText()). Note that this involves 2 tasks:
Making an AJAX call, and updating the UI once I receive a response - I use a simple AsyncTask for this.
Doing the above repeatedly, at regular intervals.
I haven't figured out an elegant way to achieve Point 2 above. Currently, I am simply executing the task itself from OnPostExecute(). I read on this thread at SO that I need not worry about garbage collection as far as the AsyncTask objects are concerned.
But I'm still unsure as to how I set up a timer that will fire my AsyncTask after it expires. Any pointers will be appreciated. Here is my code:
public class MyActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new AjaxRequestTask().execute(MY_REST_API_URL);
}
private void updateReadings(String newReadings) {
//Update the UI
}
class AjaxRequestTask extends AsyncTask<String, Integer, String> {
#Override
protected String doInBackground(String... restApiUrl) {
//Do AJAX Request
}
#Override
protected void onPostExecute(String result) {
updateReadings(result);
/*Is there a more elegant way to achieve this than create a new AsyncTask object every 10 seconds? Also, How can I update the UI if I create a timer here? */
new AjaxRequestTask().execute(MY_REST_API_URL);
}
}
}
Thanks in advance
EDIT:
I tried posting an answer but couldn't do it since I don't have the reputation to answer within 8 hours.
Well, so I found a solution. I'm not convinced however.
protected void onPostExecute(String result) {
updateReadings(result);
// super.onPostExecute(result);
new Timer().schedule(
new TimerTask() {
#Override
public void run() {
new AjaxRequestTask().execute(MY_REST_API_URL);
}
},
TIMER_ONE_TIME_EXECUTION_DELAY
);
}
Are there any flip sides that I should be aware of when I use this? In particular, I am seeing lots of GCs happening in the LogCat. Also, I am wondering how an AsyncTask can be candidate for GC unless the onPostExecute() completes?
How can I "stop" the updates? One way I thought of was to make the very first AsyncTask instance as a member variable of the Activity. That way, I can invoke cancel(true) on it and hope that this will "stop" the tasks.
SOLUTION:
In case anyone is looking for something similar - none of the solutions I mentioned here work satisfactorily. They all suffer from OutOfMemory issues. I did not debug into the details of the OOM, but I suspect it could either be because of the recursion, or because of having HTTP-related objects as member variables in the AsyncTask rather than as members of the Activity (basically because of NOT reusing HTTP and other objects).
I discarded this approach for a different one - making my Ajax Calls endlessly in the doInBackground() of my AsyncTask; and updating the UI in onProgressUpdate(). That way I also avoid the overhead of maintaining too many threads or Handlers for updating the UI (remember UI can be updated in onProgressUpdate() ).
This approach also eliminates the need for Timers and TimerTasks, favoring the use of Thread.sleep() instead. This thread on SO has more details and a code snippet too.
Call postDelayed() on any View to schedule a hunk of code to be run on the main application thread after a certain delay. Do this in onPostExecute() of the AsyncTask to create and execute another AsyncTask.
You could use AlarmManager, as others have cited, but I would agree with you that it feels a bit like overkill for timing that occurs purely within an activity.
That being said, if the AJAX calls should be occurring regardless of whether the activity exists, definitely consider switching to AlarmManager and an IntentService.
I think the android way to do this is using AlarmManager. Or you can user a basic java Timer as well. I'd recommend AlarmManager.
Set it up to send some intent with a custom Action, and register a broadcastreceiver for it.
If the ajax calls are only executed in the activity you can just use a timer in the activity which starts the tasks.
Otherwise use a service which uses the AlarmManager and which connects to the gui via a broadcast.
The recommended way to do a repeated task, is via AlarmManager, as alluded to by Scythe. Basically it involves setting up a broadcast listener, and having AlarmManager fire off an intent to that listener at whatever interval you choose. You then would have your broadcast listener call out to the activity to run the AsyncTask. If you need a very tight timer (less than 5s calls I'd say), then you're better off using a Timer within a Service, and using AIDL to call back to the activity.
Instead of talking directly from the broadcast intent, you could also setup an IntentService which you can poke, and use AIDL to update the activity.
This is how I achieved it finally. Note that the AsyncTask cancel(true) method is useless in my scenario because of the recursion. I used what #CommonsWare suggested - used a flag to indicate whether any more tasks should be executed.
public class MyActivity extends Activity {
/*Flag which indicates whether the execution should be halted or not.*/
private boolean mCancelFlag = false;
private AjaxRequestTask mAjaxTask;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
if(mAjaxTask == null){
mAjaxTask = new AjaxRequestTask();
}
mAjaxTask.execute(MY_REST_API_URL);
}
#Override
protected void onResume() {
super.onResume();
mCancelFlag = false; /*when we resume, we want the tasks to restart. Unset cancel flag*/
/* If the main task is Finished, create a new task and execute it.*/
if(mAjaxTask == null || mAjaxTask.getStatus().equals(AsyncTask.Status.FINISHED)){
new AjaxRequestTask().execute(TLS_REST_API_URL);
}
}
#Override
protected void onPause() {
mCancelFlag = true; /*We want the execution to stop on pause. Set the cancel flag to true*/
super.onPause();
}
#Override
protected void onDestroy() {
mCancelFlag = true;/*We want the execution to stop on destroy. Set the cancel flag to true*/
super.onDestroy();
}
private void updateReadings(String result) {
//Update the UI using the new readings.
}
class AjaxRequestTask extends AsyncTask<String, Integer, String> {
private AjaxRequestTask mChainAjaxRequest;
private Timer mTimer;
private TimerTask mTimerTask;
#Override
protected String doInBackground(String... restApiUrl) {
//Do AJAX call and get the response
return ajaxResponse;
}
#Override
protected void onPostExecute(String result) {
Log.d(TAG, "Updating readings");
updateReadings(result);
// super.onPostExecute(result);
if(mTimer == null){
mTimer = new Timer();
}
if(!mCancelFlag){/*Check if the task has been cancelled prior to creating a new TimerTask*/
if(mTimerTask == null){
mTimerTask = new TimerTask() {
#Override
public void run() {
if(!mCancelFlag){/*One additional level of checking*/
if(mChainAjaxRequest == null){
mChainAjaxRequest = new AjaxRequestTask();
}
mChainAjaxRequest.execute(MY_REST_API_URL);
}
}
};
}
mTimer.schedule(mTimerTask,TIMER_ONE_TIME_EXECUTION_DELAY);
}
}
}
}