asynctask inside runnable does not stop after calling removeCallbacks - android

I have an asynctask named myAsync that performs some network operations (fetching data from server, and parsing the json).
I also have a handler created once the activity runs.
I also have a runnable in which i run the asynctask. The reason I am using runnable is because I will be using it inside a Handler's postdelayed method as I want this to be repeated every 1 minute.
Runnable runnable = new Runnable()
{
public void run()
{
new myAsync ().execute();
}
};
Then I am using the above runnable inside my onResume;
#Override
protected void onResume()
{
super.onResume();
handler.postDelayed(runnable, 60000);
}
Whenever I leave the activity, I want the check to stop, so I am calling,
handler.removeCallbacks(runnable);
However, the asynctask keeps on running non stop.
What shall I do ?

The whole point of asynctask is to run a thread on the main thread.
So it does not make sense to run it in Runnable()

What you can do is skip the Runnable and Handler...definitely not needed here. Assuming the AsyncTask is an inner class of your Activity, you can set a member boolean variable and check that in your doInBackground()
public Void doInBackground(Void...params)
{
// this is a boolean variable, declared as an
//Activity member variable, that you set to true when starting the task
while (flag)
{
// run your code
Thread.sleep(60000);
}
return null; // here you can return control to onPostExecute()
// if you need to do anything there
}
This will make the AsyncTask sleep for a minute before running the code again. Then in onPause() or wherever you want you set the flag to false. If you need to update the UI then call publishProgress() inside your loop and put the UI code in onProgressUpdate()

You can remove the AsyncTask and just do the proccess with Runnable in this way you can make the repetitions that you need. If this does not work you can set a flag to stop the proccess like said codeMagic.
runable = new Runnable() {
public void run() {
try {
//Proccess
while (flag)
{
//Proccess
handler.postDelayed(this, 3000);
}
}catch(Exception e)
{
Log.i("Log","Error: "+e);
}
};
handler.postDelayed(runable, 3000);
#Override
public void onPause() {
super.onPause();
flag=false;
handler.removeCallbacks(runnable);
}
#Override
public void onResume() {
super.onResume();
flag=true;
handler.postDelayed(runable, 3000);
}
I hope this help.

Related

How to check and set network status in TextView every 2 seconds?

I want to set network status in TextView, which I want to repetitively call method and set in background, so I used AsyncTask class with infinite loop
class setNetworkText extends AsyncTask
{
#Override
protected Object doInBackground(Object[] params) {
for(;;)
{
if(isNetworkConnected()) //check internet connection and if found it return true
setOnline(); // it set my TextView text to Online
else
setOffline(); // it set my TextView text to Offline
Thread.sleep(2000);
}
return null;
}
}
but it is not working, it stops my application.
Android will (in most versions) only execute one AsyncTask at a time - so if you keep blocking in doInBackground of one AsyncTask, no other AsyncTasks will run, thus blocking your application.
Take a look at using Handler.postDelayed or using a TimerTask. They are more suited for repeating actions.
You can not use AsyncTask to do that. You should use Handler to schedule a task periodically.
// Create the Handler
Handler handler = new Handler();
// Define the code block to be executed
private Runnable runnableTask = new Runnable() {
#Override
public void run() {
if(isNetworkConnected())
setOnline();
else
setOffline();
}
};
// Call on main thread (for example, inside onResume())
#Override
protected void onResume() {
super.onResume();
handler.postDelayed(runnableTask, 2000);
}
// Remember to unregister it onPause()
#Override
protected void onPause() {
super.onPause();
handler.removeCallbacks(runnableTask);
}
new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
//check something on time interval here 1 second
}
public void onFinish() {
//when your task done here 3 second is time to end
}
}.start();
explanation
CountDownTimer(long millisInFuture, long countDownInterval)
millisInfuture will be how long you want to run the task and countDownInterval is the interval in your case it is 2 seconds

Repeat task while activity is open

i want to repeat task while the activity is open.
For example repeat foo() every minute while the activity is open.
I tought about Timer, handler and runable.
I tought about this code:
Maybe there is some better way?
public void setRefreshRate()
{
newTimer = true
while(true)
{
if(newTimer)
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
if(isNetworkAvailable() && movedToAnotherActivity== false)
new GetWorkouts().execute();
newTimer = true;
}
}, Integer.getInteger(data.getWallRefresh()));
newTimer = false;
}
}
There may be a better way but I like AsyncTask so I would probably use that and call sleep() in doInBackground() then you can call cancel() on your task object and set it to null when the Activity finishes.
public void doInBackground(Void...params)
{
boolean flag = false;
while (!flag)
{
// do some work
Thread.sleep(6000);
}
}
then overide and set flag to true in onBackPressed() and finish(). You can then use any of the other AsyncTask methods to update the UI if necessary.
AsyncTask
Thanks to codeMagic's answer for starting me down the right path, but AsyncTask isn't really designed for this. From the docs:
AsyncTasks should ideally be used for short operations (a few seconds at the most.)
The problem is that AsyncTasks, at least by default, run sequentially on the same worker thread, so if you try to launch another AsyncTask, it won't be able to run, since the timer loop never finishes.
To work around this, I just used a raw Thread and it's working fine.
apiUpdateTimerThread = new Thread(new Runnable() {
#Override
public void run() {
while(true) {
try {
Log.i(TAG, "UPDATE FROM THE API!!!!");
doSomeStuff();
Thread.sleep(5 * 1000);
} catch(InterruptedException e) {
Log.e(TAG, "API Update AsyncTask Interrupted", e);
}
}
}
});
To stop it, just call
apiUpdateTimerThread.interrupt();

Stop Thread onPause

I want to stop a Thread when the User leaves the Activity. It sounds so simple but no function, which i tried, works.
I start the Activity with the Code
lovi = new Intent(getApplicationContext(), listoverview.class);
lovi.putExtra("reloadAll", true);
startActivity(lovi);
In the onCreate of the listoverview i start the Thread with the Code
rlMF.start();
And rlMF looks like this:
public Thread rlMF = new Thread(new Runnable() {
public void run() {
reloadMissingFiles();
}
});
I tried in the onPause to use rlMF.stop(), .interrupt(), .suspend. Nothing stops it.
You have to add some flag to to stop it. Stopping thread by other means might have dire consequences, like resource leaks.
For example:
volatile boolean activityStopped = false;
When creating runnable:
public Thread rlMF = new Thread(new Runnable() {
public void run() {
while (!activityStopped) {
// reloadMissingFiles() should check the flag in reality
reloadMissingFiles();
}
}
});
In onPause():
protected void onPause(){
super.onPause();
activityStopped = true;
}
Using the Android Handler
Runnable r = new Runnable()
{
public void run()
{
// do stuff
handler.post(this);
}
};
handler.post(r);
In the onPause:
protected void onPause(){
super.onPause();
handler.removeCallbacks();
}
Instead of Thread try and use an AsyncTask, this way you can call the cancel(boolean mayInterruptIfRunning) method of the AsyncTask. You should also keep in mind to catch the InteruptedException that may be thrown if you use cancel(true).
Here's a usefull tutorial about Threads, Handlers and AsyncTask that may help you.

How can I run my code after Activity is made visible?

I have an Activity with 3 spinners. These spinners get their data from a web-service by a method that takes about 1 minute to be completed.
I want to load the Activity first and after it is made visible, call that web-service method and load data. I have tested the following codes separately but none of them solved my problem. In these samples application goes into a black screen and when the web-service operation completed, it is made visible.
#Override
protected void onCreate() {
//.........
final Runnable r = new Runnable()
{
public void run()
{
loadMyData();
}
};
Utilities.performOnBackgroundThread(r);
}
#Override
protected void onResume() {
new Thread() {
#Override
public void run() {
loadMyData();
}
}.start();
super.onResume();
}
#Override
protected void onStart() {
if (comesFromOnCreateMethod)
{
final Runnable r = new Runnable()
{
public void run()
{
loadMyData();
}
};
Utilities.performOnBackgroundThread(r);
}
comesFromOnCreateMethod = false;
super.onStart();
}
#Override
protected void onResume() {
if (comesFromOnCreateMethod)
{
final Runnable r = new Runnable()
{
public void run()
{
loadMyData();
}
};
Utilities.performOnBackgroundThread(r);
}
comesFromOnCreateMethod = false;
}
If you are getting a black screen, then I would assume your code is being run on the UI thread and not on the background, causing the UI to hang until the work is completed.
One of the best solutions to doing background work is an AsyncTask. Using this, you can call it in your onCreate() method, and when its done, it will post a callback to the UI thread for you in which you can display you data.
If you want this method to run everytime this Activity displays, then call it in onResume(). Otherwise, call it in onCreate().
In your onCreate, make the async tasks as the others have advised. Make sure you generate the content for the app first and then call the asyncTasks. You can control your spinners from the callback.
First of all, you might want to increase your accept rate, 39% is pretty low.
Anyway, you might want to check AsyncTask, it should do the thing. http://developer.android.com/reference/android/os/AsyncTask.html
Typically, you will want to initialize in onPreExecute, do the networking in the doInBackGround, and set the result to the UI thread on the OnPostExecute. Hope this will help.
Use AssynchTask() and you should call super.onResume() or any lifecycle method in respective life cycle method first then other specific method you want to do....

Android unit tests with multiple threads

I have a problem with unit tests in Android.
My object MyObject has a method start() like this :
public void start() {
final Handler onStartHandler = new Handler();
new Thread() {
#Override
public void run() {
super.run();
onStartHandler.post(new Runnable() {
#Override
public void run() {
mIsRunning = true;
onStart();
}
});
}
}.start();
}
And I want to test that onStart() is called.
So I tried something like that :
public void testOnStartIsCalled() {
assertFalse("onStart() should not be called", mMyObject.isRunning());
mMyObject.start();
assertTrue("onStart() should be called", mMyObject.isRunning());
mMyObject.stop();
assertFalse("onStop() should be called", mMyObject.isRunning());
}
But it doesn't work, I guess it's because it's in a Handler and a new Thread.
My test class extends AndroidTestCase.
What should I do ? What is the best practice for this case ?
Regards.
When I deal with testing some multi-threaded code I try to let the program take as much of its natural flow as possible. Additionally, I avoid the use of sleep statements since you don't get any guarantees that the sleep interval you've chosen is enough to allow the subject of your test to finish what it's doing; you often end up having to choose sleep intervals that are too large and it forces a much slower execution of your test cases.
I would recommend that you try to add some code into the class you're testing, in this case MyObject, which call a listener whenever something happens. It seems that you already have callback methods for onStart() and onStop()(if those are events/callbacks), so those should be getting invoked and you should use them to control the flow of your test. When you get an onStart() event, you should then call stop() and wait for an onStop() event.
Update
First and foremost, you have redundant code:
public void start() {
final Handler onStartHandler = new Handler();
new Thread() {
#Override
public void run() {
super.run();
onStartHandler.post(new Runnable() {
#Override
public void run() {
mIsRunning = true;
onStart();
}
});
}
}.start();
}
Either start a new thread to call onStart() or schedule the runnable on the Handler's thread queue.
Version 1- remove the handler and just let the code be executed in a new thread:
public void start() {
new Thread() {
#Override
public void run() {
super.run();
mIsRunning = true;
onStart();
}
}.start();
}
Version 2- only use the handler to asynchronously execute the callback:
public void start() {
final Handler onStartHandler = new Handler();
onStartHandler.post(new Runnable() {
#Override
public void run() {
mIsRunning = true;
onStart();
}
});
}
And second: I noticed is that if you don't have a Looper, then whatever you post with the Handler will be ignored (thus it will never be called). For more information on the Looper-Handler pattern see the article: Android Guts: Intro to Loopers and Handlers. The Looper and the Handler are supposed to be attached to the same thread (usually the main thread). Additionally, if you're creating the Handler on a separate thread as your Looper, then you'll run into the same problem: anything you post with the Handler will be ignored.
Here are a few more good questions and articles on loopers and handlers:
Just do IT: looper and handler in android
Handler-Looper implementation in Android
The relationships between Looper, Handler and MessageQueue is shown below:
The problem here is that you are calling onStart() which invokes a new thread, and then immediately ask if it is started. There is startup time for the new thread and while that is happening, your test is asking if it is started -- it's not YET.
I bet if you waited by using Thread.sleep(), or a loop, you'd find it is started "eventually".
What is it you're actually trying to test?
If you need the new thread, you might want to read up on threads, synchronize, etc.
http://developer.android.com/guide/topics/fundamentals/processes-and-threads.html

Categories

Resources