I am using an Asynctask as the loop controller for a game and noticed that the thread created kept on running after the activity was finished.
I realised that was the correct behaviour of a separate thread and then I tried hunting down answers on how to end the thread when the app enters onPause.
I found lots of similar questions but no direct answers but eventually came up with a method so I'm going to answer my own question here to hopefully help others in future. (And to receive improvements to my answer as well)
Firstly, AsyncTask have a fully valid cancel() method. Secondly, do not use an AsyncTask for a proper game loop. AsyncTask isn't for long-running operations.
Therefore, skip AsyncTask for your game loop and learn how to properly manage pausing / resuming in an ordinary Thread by reading another answer from me here on SO.
public class CamOverlayTest extends Activity {
//...
public static BackgroundLoop BackgroundLoopTask;
//...
#Override
protected void onResume() {
//...
BackgroundLoopTask = new BackgroundLoop();
BackgroundLoopTask.execute();
}
#Override
protected void onPause() {
//...
BackgroundLoopTask.cancel(true);
}
private class BackgroundLoop extends AsyncTask<Void,Integer,Boolean> {
#Override
protected Boolean doInBackground(Void... arg0) {
int count =0;
while (!this.isCancelled()) {
// Basically, this is where the loop checks if the Aysnctask has been asked to be
// cancelled - if so - it exits.
try {
Thread.sleep(1000);
updatePhysics(count);
} catch (InterruptedException e) {
e.printStackTrace();
}
count +=1;
Log.i("SW","Count: "+count);
publishProgress();
}
return true;
}
#Override
protected void onProgressUpdate(Integer... values) {
// swDrawOnTop is my view
swDrawOnTop.invalidate();
}
//...
}
Related
Is it possible that the android OS may delay or suspend my asynctask for some reason. If so what can I do to ensure that my task (e.g fetching data from database) is not delayed or suspend. Run it on a UI thread maybe but I have read that it is not a good idea as it can freeze the UI and cause lag.
Is it possible that the android OS may delay or suspend my asynctask for some reason.
It might be blocked by another instance of an AsyncTask. By default they run on a single background thread: https://developer.android.com/reference/android/os/AsyncTask.html
If so what can I do to ensure that my task (e.g fetching data from database) is not delayed or suspend.
Investigate what exactly causes the delay. Is it something inside doInBackground method or maybe delay happens before or after the background operation. It can be anything, hard to tell without debugging the code.
Run it on a UI thread maybe but I have read that it is not a good idea as it can freeze the UI and cause lag.
Although AsyncTask is not a good solution in this case, it should work fine if you implement it correctly. Other approaches to consider will be Loaders, or AsyncQueryHandler with ContentProvider. Depends on your use case.
#Override
protected void onPreExecute() {
holdWait = false;
stop = false;
}
#Override
protected Void doInBackground(Void... params) {
synchronized (this) {
while(true) {
if(Work) return null;
if(HaveWork) {
//make some
} else {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
return null;
}
public void mynotify() {
synchronized (this) {
if(holdWait) {
notify();
holdWait = false;
}
}
}
public void setStopWork() {
synchronized (this) {
stop= false;
if(holdWait) {
notify();
holdWait = false;
}
}
}
}
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....
I have listed of products with different category. I have to sort them. Because of the queries, It is taking more time to load. Between two activities, the screen is coming black. I want to run the query in the background. How can I do that and how to use its result in main activity?
private class InsertTask extends AsyncTask {
String cat;
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Boolean doInBackground(String... params) {
Boolean success = false;
try {
category(cat);
success = true;
} catch (Exception e) {
if(e.getMessage()!=null)
e.printStackTrace();
}
return success;
}
#Override
protected void onPostExecute(Boolean success) {
super.onPostExecute(success);
}
private void category(String category) {
try{
Cursor1 = mDbHelper.fetchcategory(category);
}catch(Exception e){
Log.v("Excep", ""+e);
}
}
And when called
InsertTask task = new InsertTask();
task.execute();
I have listed the category in buttons. How can I get the values then?
You should use AsyncTask for that. And some more info.
Its good you have thought of AsyncTask. Firstly, you can declare this class as inner in you class activity (if you haven't previously did) and so you are able to access you view class members.
You can do this also by creating thread and one handler that will be used to update your UI components. Remember that if you use threads you'll need to lock/unlock your database object because of the thread safety(if any other thread is accessing the database for any reason). Read more about thread safety of dbs.
I was doing some searching myself, and I came across this read, its rather long but looks extremely helpful, with lots of code examples. (I bookmarked it for myself).
Threads, Async, and Handlers O MY!
But some form of threading is the ticket.
From Android dev.
(My favorite code snippet)
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
//Do Work here
}
}).start();
}
I have a Service that launches a Thread and a Runnable like so.
t = new Thread(new Runnable() {
public void run() {
doSomething();
}
});
t.start();
The reason for the thread is to perform an Async task doSomething(). For now lets not worry about the other class AsyncTask. I have tried it and it does not work for my case. Edit: I can't use AsyncTask because it is meant for the UI thread only. This piece of code has to operate inside a Service, so nope, no AsyncTask :(
doSomething() contains some external libs so the issue I am having is that it can potentially be hung at one of the commands, without return any value (hence no error checking can even be done)
To work around this, I will want to, at some point of time, destroy the Service.
stopService(new Intent("net.MyService.intent));
This works fine and is easily verified on the phone. However, the Thread which was created above will continue to run even when the Service that spawned it is destroyed.
I am thus looking for the correct commands to insert in the Service's onDestroy() which will clean up the Thread for me.
t.destroy();
t.stop();
are both depreciated and cause application crashes.
I took this code from somewhere
#Override
public void onDestroy() {
Thread th = t;
t = null;
th.interrupt();
super.onDestroy();
}
but it still does not work, the thread continues to run. Any help guys?
The thread destroy and stop methods are inherently deadlock prone and not safe. Their existence also gives the illusion that there might be some way of halting another thread immediately when something else tells it to.
I understand your thinking, from your point of view their is one main thread, and when this thread hasn't received a response from it's worker thread in a while you'd like to kill it and restart it, without caring what it's up to. But the reason those methods are deprecated is you should care what the thread is up to. A lot.
What if the thread has a lock around a variable you need to use later? What if a thread has a file handle open? In all these cases, and many more, simply stopping the thread at it's current operation would leave things in mess -- quite likely your application would just crash further down the line.
So in order for a thread to be interruptible or cancel-able or stoppable, it has to manage this itself. If a thread or operation provides no way for itself to be interrupted, then you cannot interrupt it - it is assumed to do so would be unsafe.
If you runnable is literally
public void run() {
doSomething();
}
then there is no way to interrupt it. One would hope that if doSomething were a long operation that there might be a way to either interact with it incrementally with something like
public void run() {
while (running) {
MyParser.parseNext();
}
}
or to be able to pass in a variable by reference which indicates whether the thread is interrupted or not, and hopefully the method would interrupt itself at suitable location.
Remember a blocking operation is blocking. There is no way to get around that, you cannot cancel it part way through.
Alternative answer
Use the following code:
MyThread thread; // class field
Create and start the thread as you do it right now.
thread = new MyThread();
thread.start();
When the service is destroyed, "signal" the thread to quit
public void onDestroy() {
// Stop the thread
thread.abort = true;
thread.interrupt();
}
Here is thread implementation
//another class or maybe an inner class
class MyThread extends Thread {
syncronized boolean abort = false;
//ugly, I know
public void run() {
try {
if(!abort) doA();
if(!abort) doB();
if(!abort) doC();
if(!abort) doD();
} catch (InterruptedException ex) {
Log.w("tag", "Interrupted!");
}
}
}
You might want to read the following:
How do you kill a thread in Java?
Thread Primitive Deprecation as already pointed by Claszen
http://www.devx.com/tips/Tip/31728 - based my code from here, but there are some issues with the code!
I think that you could rely on catching the exception and not check abort but I decided to keep it that way.
UPDATE
I've seen this sample in codeguru:
public class Worker implements Runnable {
private String result;
public run() {
result = blockingMethodCall();
}
public String getResult() {
return result;
}
}
public class MainProgram {
public void mainMethod() {
...
Worker worker = new Worker();
Thread thread = new Thread(worker);
thread.start();
// Returns when finished executing, or after maximum TIME_OUT time
thread.join(TIME_OUT);
if (thread.isAlive()) {
// If the thread is still alive, it's still blocking on the methodcall, try stopping it
thread.interrupt();
return null;
} else {
// The thread is finished, get the result
return worker.getResult();
}
}
}
Did you check the Java Thread Primitive Deprecation Documentation which is referenced in the Thread API JavaDoc. You will find some hints to handle your problem.
why don't you use an AsyncTask?
A task can be cancelled at any time by
invoking cancel(boolean). Invoking
this method will cause subsequent
calls to isCancelled() to return true.
After invoking this method,
onCancelled(Object), instead of
onPostExecute(Object) will be invoked
after doInBackground(Object[])
returns. To ensure that a task is
cancelled as quickly as possible, you
should always check the return value
of isCancelled() periodically from
doInBackground(Object[]), if possible
(inside a loop for instance.)
I like to take the following approach:
class MyHandler extends Handler {
final Semaphore stopEvent = new Semaphore(0);
#Override
public void handleMessage(Message msg) {
try {
while (!stopEvent.tryAcquire(0, TimeUnit.SECONDS)) {
doSomething();
if (stopEvent.tryAcquire(SLEEP_TIME, TimeUnit.MILLISECONDS)) {
break;
}
}
} catch (InterruptedException ignored) {
}
stopSelf();
}
}
On service onDestroy just release the stopEvent:
#Override
public void onDestroy() {
myHandler.stopEvent.release();
myHandler = null;
super.onDestroy();
}
Better to use global variable stopThread, stop thread once variable changed to true.
btnStop.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0){
stopThread = true;
}
});
public void run() {
while (!stopThread) {
//do something
}
}
I think the best way to create and communicate with another thread is to use an AsyncTask. Heres an example of one:
public class Task extends AsyncTask<Void, Void, Void> {
private static final String TAG = "Task";
private boolean mPaused;
private Runnable mRunnable;
public Task(Runnable runnable) {
mRunnable = runnable;
play();
}
#Override
protected Void doInBackground(Void... params) {
while (!isCancelled()) {
if (!mPaused) {
mRunnable.run();
sleep();
}
}
return null;
}
private void sleep() {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
Log.w(TAG, e.getMessage());
}
}
public void play() {
mPaused = false;
}
public void pause() {
mPaused = true;
}
public void stop() {
pause();
cancel(true);
}
public boolean isPaused() {
return mPaused;
}
}
You can now easily use this class, and start the thread by writing:
Task task = new Task(myRunnable);
task.execute((Void) null);
Along with this you can easily pause or stop the thread from looping:
Example of pausing and playing the thread:
mButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (task.isPaused()) {
task.play();
} else {
task.pause();
}
}
});
Example of stopping and starting the thread:
mButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (task.isCancelled()) {
task = new Task(myRunnable);
task.execute((Void) null);
} else {
task.stop();
}
}
});
I have some TextViews in my app that I want updated automatically each 5 seconds. I have a method for refreshing them, but how do I make a timer that runs the method every 5 seconds? Thanks!
Provide another solution
Handler h=new Handler();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.main);
h.post(new Runnable(){
#Override
public void run() {
// call your function
h.postDelayed(this,5000);
}
});
Look at extending a CountDownTimer, it has an onFinish() method you can overwrite to update your TextView, and restart the timer if you wish to make it repeat. You can also bind to onTick() if you only want to update a finite number of times.
I tried the Handler solution myself, especially after reading this article on the resource pages: http://developer.android.com/resources/articles/timed-ui-updates.html. But I wanted to be able to start and stop the timer much like a stopwatch, and after resuming the timer the Handler solution started updating much less regularly - on the emulator about every five seconds. In the end I found a tip on a blog that suggested the solution with an inner class extending AsyncTask. You can make use of the publishProgress()-onProgressUpdate() functionality in AsyncTask. From onProgressUpdate(), you're allowed to make changes "directly" in your UI thread e.g. myTextView.setText(...). This publishes results much more frequently. Here's a super simple implementation of that inner class:
private class UpdateTimerLabel extends AsyncTask<Integer, Integer, Integer> {
#Override
protected Integer doInBackground(Integer... arg0) {
while (true) {
try {
Thread.sleep(1000);
publishProgress(arg0);
Log.d(tag, "AsyncTask tries to publish");
} catch (InterruptedException e) {
e.printStackTrace();
}if (1 == 0) break; // Silly but necessary I think
}
return null;
}
protected void onProgressUpdate(Integer... progress) {
updateTimerTextView(); // Call to method in UI
}
}