I'm have a game that's uses SurfaceView implementation to display the objects.
I have a thread which draws the SurfaceView time-to-time to the screen.
The game is running completely.
Unfortunately, it needed to have a pause function whenever the game is interrupted.
Well, I know that I need to manipulate onResume and onPause.
But I can't get it right. The error points me back to surfaceCreated where I start the thread telling me that the thread has started already. I tried using the resume and suspend on the onResume and onPause respectively but nothing changed.
How can I achieve this?
I have already done how the objects location would be save using File-I/O handling.
Thanks in advance.
This is what I did:
#Override
public void surfaceCreated(SurfaceHolder arg0) {
if (thread.getState() == Thread.State.TERMINATED){
CreateThread(getHolder(),getContext());
}
thread.setRunning(true);
thread.start();
}
In CreateThread you should have the thread = new MyThread(...);
the setRunning (boolean mRun) use a boolean to start/stop the run function (I think I was inspired by the LunarLander);
If you want to use properly the onPause/onResume don't put the variables used by your thread inside the thread (as done in LunarLander). I suggest you to do like that:
// Variables declarations
public MyGameThread CreateThread(...){
thread = new MyGameThread(holder, context, new Handler() {
// and so on....
});
}
When you pass through the onPause/onResume, your thread will be destroyed and reneweled but if you put your variables outside it, you can continue to use them after.
If you have something important to preserve, use one of this options:
SharedPreferences: an xml will be created and saved locally with variables that persist even after the end of the app;
a SQL db if you would manage more than 5-10 variables because in this case the use of the former option would be difficult.
Actually it's not recommended to stop a thread by yourself, the stop() method is deprecated. The simplest solution is to use a flag in your while loop inside the thread's run() method. When you need to "stop" the thread, you just drop the flag to false and the thread won't do anything anymore, despite it will keep running. Android will stop your thread when it's needed. Hope this helps.
Without knowing the ins and outs of your code.
To "Pause" a thread you can implement functionality like so:
while(! this.isInterrupted())
if(!paused)
{
... Do something ...
} else { try { Thread.sleep(100) } catch (InteruptedException ie) {} }
This is depending if Do something is invalidating your surface view or otherwise controlling progression in your app. An accessor to paused should allow you to pause and resume your thread without getting caught up in any other bit of architecture.
I'm unsure if you've got one or two threads in this question, I'm assuming 2. You need to do three things when you call onPause:
1 - Save the state of the application (all game variables, states, etc)
2 - Kill the surfaceView by calling suspend.
3 - Kill the other thread (we'll call it Thread B).
Killing of Thread B is your problem I think. You want to interrupt the thread and tell it to quit, or else when you call onPause your thread will still be doing its thing. Then, when you go back into the game, the thread will try to be created again which causes the problem. There are 2 ways to kill a thread properly:
In the while() loop of your thread, have a boolean 'run' which while(run) will execute the code. When you change run to false, the thread exits.
If your thread sleeps (I assume it might do since its a game and will be running w.r.t time), catch the InterruptedException and then quit there. When you want to kill the thread, you throw the exception to the thread.
The first one is by far the easiest.
Related
Situation: Android
class GLRenderer implements GLSurfaceView.Renderer
..
void onDrawFrame(GL10 gl) {..}
class MainGLSurfaceView extends GLSurfaceView
..
setRenderer(new GLRenderer());
class MainActivity ..
..
boolean onTouchEvent(MotionEvent event) {..}
MainActivity.onTouchEvent receives and processes events, some of which change state used by onDrawFrame(gl).
Q 1: Is there a way to "put the message queue on hold" until onDrawFrame returns?
NOTE: my onDrawFrame might take up to ~1/3 second on a slow phone. If necessary, I can probably change it so that if it doesn't have information it needs, it can start fetching it in the background, return promptly, and then draw the new frame on a later draw request (triggered by a timer).
Q 1B: Perhaps the events are only interrupting the draw, because of something I'm doing to fetch data. Can events interrupt at any moment (in the middle of onDrawFrame), or is it only when my custom onDrawFrame logic makes certain (system?) calls?
A 1B: Unfortunately, with a breakpoint I caught the event interrupting in the middle of a computation (a VM "init" of a new instance of a small class used to hold a temporary value was all that was required, to be "interruptible"; something almost any java code might do). So I will need to cope with interrupting events, can't side-step them.
Q 2: Or would it be better to examine incoming messages, and somehow decide which ones should be handled immediately, and then ?do what? with other messages, to process them after onDrawFrame returns?
Q 3: I've made an attempt at Q 2, putting messages on to an internal queue. Then I tried processing them at end of the onDrawFrame method. This worked okay until a message which tried to open a confirmation dialog. Result: RuntimeException: Can't create handler inside thread that has not called Looper.prepare(). Yeah, I didn't think I should be doing it that way. Can i somehow shove those messages back on to the main message queue?
(I didn't want to create yet another thread, so at end of onDrawFrame I tried "new Handler().postDelayed(new Runnable() .." inside of which I was going to do something with those events. Oops - that has the same problem - can't create handler on the thread that onDrawFrame is running on.)
So the basic idea is that I seek a way to not pull the rug out from under the current draw frame. I'd rather not have to make all the event-triggered logic work on one set of data, then "freeze" that data (copy it), so that draw frame can work on a frozen set.
Q&A's that I looked at before asking this:
Message queue in android
This talks about creating a looper and a handler, including a link to another article. I might adapt this to create a handler attached to the main thread's looper. So instead of having to inject back into the MessageQueue, I just need to pass my secondary queue to this handler, and start it running. But I'm on the wrong thread at the time I want to start the handler, so not sure how to proceed. Hmm, maybe make a custom event, that I somehow trigger on the main thread?
How to pause the activity?
shows how to use a flag to pause a worker thread. Since I have multiple types of events I wish to defer, instead of that approach, it is easier to hold (copies of) those events on a separate queue. Then I just need to know how to "inject" them back into the main MessageQueue. I'm trying to avoid creating another thread, to minimize system resources.
How to pause a Thread's Message Queue in Android?
Alternate approaches (not using looper) when creating one's own thread, e.g. a worker thread. Doesn't help for my situation, which is UI events coming in to existing looper.
And in case there is some completely different way to tackle this:
isn't this a situation that everyone who uses GLSurfaceView rendering would encounter eventually?
Is there any example of a robust way to deal with gl drawing and asynchronous GUI events?
The final piece to my solution to "Q 3":
public class MainActivity ...
// Call this, if not already on UI thread.
public static void processQueuedEventsOnUIThread() {
try {
Runnable runnable = new Runnable() {
#Override
public void run() {
... process the deferred UI events, which I have stored on a private queue ...
}
};
MainActivity.mMainActivity.runOnUiThread(runnable);
} catch (Exception e) {
Log.e("MainActivity", "processQueuedEventsOnUIThread", e);
}
}
The last statement in my GLRenderer.onDrawFrame() is now
MainActivity.processQueuedEventsOnUIThread();
The exceptions no longer occur, even if the processed events cause a dialog window (with its own handler) to open. activity.runOnUiThread(runnable) is the essential step.
I am running into a strange problem...
My application is meant to do some webservice calls on a separate thread. Once the webservice call is finished, it would navigate user to a different activity.
In the case when user press the home button or exit current activity it should terminate the webservice if the webservice call thread is still running. Hence I put a thread termination method in the OnPause state.
Here is the method block that is running inside the thread:
private Thread _webserviceThread;
void WebserviceCallThread(){
WebRestult result= WebserviceCall();
if(!result.containsError()){
RunOnUIThread(delegate{
transitionToActivityXYZ();
});
}
}
void RunThreadAction(){
_webserviceThread = new Thread(new ThreadStart(WebserviceCallThread));
_webserviceThread.Start();
}
protected override void OnPause(){
if(_webserviceThread != null && _webserviceThread.IsAlive){
_webserviceThread.Abort();
}
}
After the webservice call is done and begin the transition to another page, It gets to the OnPause state. However, in some strange cases, it would think that the thread is not finished in the OnPause state, even though the activity transition is the last line of the method.
Has anyone ran into this problem before? If so, how did you solve this problem?
Thanks!
I always use AsyncTask for this kind of thing. Not only does it abstract away the explicit thread handling and provide hooks to do everything you want here; it's also a nice way to represent a unit of work that can be used from other activities.
There's a simple example in this post part way down, but it doesn't use the generic parameters which are quite handy.
Why not use Task Parallel Library,
It is standard .NET, and with AsyncTask, it is only recommended for tasks that take less than few seconds. see the Documentation
AsyncTasks should ideally be used for short operations (a few seconds
at the most.) If you need to keep threads running for long periods of
time, it is highly recommended you use the various APIs provided by
the java.util.concurrent
Below is an example for how to use Task Parallel Library, taken from here
private void loginWithTaskLibrary()
{
_progressDialog.Show();
Task.Factory
.StartNew(() =>
_loginService.Login("greg")
)
.ContinueWith(task =>
RunOnUiThread(() =>
onSuccessfulLogin()
)
);
}
I am having a real hard time finding a way to start, stop, and restart a thread in Java.
Specifically, I have a class Task (currently implements Runnable) in a file Task.java. My main application needs to be able to START this task on a thread, STOP (kill) the thread when it needs to, and sometimes KILL & RESTART the thread...
My first attempt was with ExecutorService but I can't seem to find a way for it restart a task. When I use .shutdownnow() any future call to .execute() fails because the ExecutorService is "shutdown"...
So, how could I accomplish this?
Once a thread stops you cannot restart it. However, there is nothing stopping you from creating and starting a new thread.
Option 1: Create a new thread rather than trying to restart.
Option 2: Instead of letting the thread stop, have it wait and then when it receives notification you can allow it to do work again. This way the thread never stops and will never need to be restarted.
Edit based on comment:
To "kill" the thread you can do something like the following.
yourThread.setIsTerminating(true); // tell the thread to stop
yourThread.join(); // wait for the thread to stop
Review java.lang.Thread.
To start or restart (once a thread is stopped, you can't restart that same thread, but it doesn't matter; just create a new Thread instance):
// Create your Runnable instance
Task task = new Task(...);
// Start a thread and run your Runnable
Thread t = new Thread(task);
To stop it, have a method on your Task instance that sets a flag to tell the run method to exit; returning from run exits the thread. If your calling code needs to know the thread really has stopped before it returns, you can use join:
// Tell Task to stop
task.setStopFlag(true);
// Wait for it to do so
t.join();
Regarding restarting: Even though a Thread can't be restarted, you can reuse your Runnable instance with a new thread if it has state and such you want to keep; that comes to the same thing. Just make sure your Runnable is designed to allow multiple calls to run.
It is impossible to terminate a thread unless the code running in that thread checks for and allows termination.
You said: "Sadly I must kill/restart it ... I don't have complete control over the contents of the thread and for my situation it requires a restart"
If the contents of the thread does not allow for termination of its exectuion then you can not terminate that thread.
In your post you said: "My first attempt was with ExecutorService but I can't seem to find a way for it restart a task. When I use .shutdownnow()..."
If you look at the source of "shutdownnow" it just runs through and interrupts the currently running threads. This will not stop their execution unless the code in those threads checks to see if it has been ineterrupted and, if so, stops execution itself. So shutdownnow is probably not doing what you think.
Let me illustrate what I mean when I say that the contents of the thread must allow for that thread to be terminated:
myExecutor.execute(new Runnable() {
public void run() {
while (true) {
System.out.println("running");
}
}
});
myExecutor.shutdownnow();
That thread will continue to run forever, even though shutdownnow was called, because it never checks to see if it has been terminated or not. This thread, however, will shut down:
myExecutor.execute(new Runnable() {
public void run() {
while (!Thread.interrupted()) {
System.out.println("running");
}
}
});
myExecutor.shutdownnow();
Since this thread checks to see whether or not it has been interrupted / shut down / terminated.
So if you want a thread that you can shut down, you need to make sure it checks to see if it has been interrupted. If you want a thread that you can "shut down" and "restart" you can make a runnable that can take new tasks as was mentioned before.
Why can you not shut down a running thread? Well I actually lied, you can call "yourThread.stop()" but why is this a bad idea? The thread could be in a synchronized (or other critical section, but we will limit ourselves to setions guarded by the syncrhonized key word here) section of code when you stop it. synch blocks are supposed to be executed in their entirity and only by one thread before being accessed by some other thread. If you stop a thread in the middle of a synch block, the protection put into place by the synch block is invalidated and your program will get into an unknown state. Developers make put stuff in synch blocks to keep things in synch, if you use threadInstance.stop() you destroy the meaning of synchronize, what the developer of that code was trying to accomplish and how the developer of that code expected his synchronized blocks to behave.
You can't restart a thread so your best option is to save the current state of the object at the time the thread was stopped and when operations need to continue on that object you can recreate that object using the saved and then start the new thread.
These two articles Swing Worker and Concurrency may help you determine the best solution for your problem.
As stated by Taylor L, you can't just "stop" a thread (by calling a simple method) due to the fact that it could leave your system in an unstable state as the external calling thread may not know what is going on inside your thread.
With this said, the best way to "stop" a thread is to have the thread keep an eye on itself and to have it know and understand when it should stop.
If your task is performing some kind of action in a loop there is a way to pause/restart processing, but I think it would have to be outside what the Thread API currently offers. If its a single shot process I am not aware of any way to suspend/restart without running into API that has been deprecated or is no longer allowed.
As for looped processes, the easiest way I could think of is that the code that spawns the Task instantiates a ReentrantLock and passes it to the task, as well as keeping a reference itself. Every time the Task enters its loop it attempts a lock on the ReentrantLock instance and when the loop completes it should unlock. You may want to encapsulate all this try/finally, making sure you let go of the lock at the end of the loop, even if an exception is thrown.
If you want to pause the task simply attempt a lock from the main code (since you kept a reference handy). What this will do is wait for the loop to complete and not let it start another iteration (since the main thread is holding a lock). To restart the thread simply unlock from the main code, this will allow the task to resume its loops.
To permanently stop the thread I would use the normal API or leave a flag in the Task and a setter for the flag (something like stopImmediately). When the loop encountered a true value for this flag it stops processing and completes the run method.
Sometimes if a Thread was started and it loaded a downside dynamic class which is processing with lots of Thread/currentThread sleep while ignoring interrupted Exception catch(es), one interrupt might not be enough to completely exit execution.
In that case, we can supply these loop-based interrupts:
while(th.isAlive()){
log.trace("Still processing Internally; Sending Interrupt;");
th.interrupt();
try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
There's a difference between pausing a thread and stopping/killing it. If stopping for you mean killing the thread, then a restart simply means creating a new thread and launching.
There are methods for killing threads from a different thread (e.g., your spawner), but they are unsafe in general. It might be safer if your thread constantly checks some flag to see if it should continue (I assume there is some loop in your thread), and have the external "controller" change the state of that flag.
You can see a little more in:
http://java.sun.com/j2se/1.4.2/docs/guide/misc/threadPrimitiveDeprecation.html
May I ask why you want to kill the thread and restart it? Why not just have it wait until its services are needed again? Java has synchronization mechanisms exactly for that purpose. The thread will be sleeping until the controller notifies it to continue executing.
You can start a thread like:
Thread thread=new Thread(new Runnable() {
#Override
public void run() {
try {
//Do you task
}catch (Exception ex){
ex.printStackTrace();}
}
});
thread.start();
To stop a Thread:
thread.join();//it will kill you thread
//if you want to know whether your thread is alive or dead you can use
System.out.println("Thread is "+thread.isAlive());
Its advisable to create a new thread rather than restarting it.
I'm trying to write a game engine in Android, but I don't have much familiarity with threads.
My thread has an attribute, mSurfaceHolder, which holds the surface that I'll be drawing to. The run() method for my thread looks like this:
public void run() {
// We're running now
setState(STATE_RUNNING);
// Keep looping while the game is running or paused
while (mState == STATE_RUNNING || mState == STATE_PAUSED) {
synchronized (mSurfaceHolder) {
// If the game is running, update physics etc.
if (mState == STATE_RUNNING) {
updateGame();
}
// Draw the game even if it's paused
drawGame();
}
}
}
STATE_RUNNING represents the state when the activity is in the foreground and the game should be running.
STATE_PAUSED represents the state when another activity has come into the foreground. I'm not completely sure why I need to still draw while it's paused, but that's what I seem to have gathered from the LunarLander example.
What I'm hoping is that while I'm looking at the activity, the game will update and draw (which I test by using LogCat). And then when I go back to the home screen or another activity appears over the top, it will just draw.
Well it does draw and update while I'm watching the activity, so the game loop itself works. But when I leave the activity, it has no effect. Here is the thread's pause() method that is called from the activity's onPause():
public void pause() {
Log.d("Game","Here");
synchronized (mSurfaceHolder) {
Log.d("Game","There");
// If the thread is running, pause it
if (mState == STATE_RUNNING) {
setState(STATE_PAUSED);
}
}
}
As you can see, to test this method I have logged some messages. Now what I find when I leave the activity is that "Here" is logged, but "There" is not. Now with my limited knowledge of threads (I hardly know what synchronized actually does), I believe this will happen because my thread can't get synchronized with the surface holder. But I don't know WHY it doesn't synchronize. A few seconds after I've left the activity, I see the following warning in LogCat:
Activity pause timeout for HistoryRecord
Any idea why this would happen? There are no problems if I try to start the activity again, the thread just keeps running as it was.
Thanks very mucho.
EDIT: Just discovered something else. The thread pauses just fine if I leave the activity within about a second of having started it. And then it will resume and pause again with no problems at all while the same task is still running. I have no idea why for a short period of time it will work, but if I leave it too long, it won't.
EDIT 2: Okay... I fixed it. But I don't think I'm supposed to do what I've done. I've basically removed any synchronization with mSurfaceHolder from both the pause() and the setState() methods (which is used by pause()). No it works as it's supposed to, but I'm thinking the synchronization is there for a reason.
Perhaps the best question for me to ask is this:
WHEN should you synchronize a thread with an object by use of a synchronized block? And in this case, what is the purpose of synchronizing with the SurfaceHolder?
The synchronize keyword in Java makes sure that two threads cannot touch the same object at the same time, preventing race conditions. In other words, it implements locking.
Most likely, you're encountering deadlock here. Another thread is probably using mSurfaceHolder, and is therefore holding the lock for this object. Your code in synchronized (mSurfaceHolder) will block until that other thread completes, which apparently isn't happening.
However, since you're not actually modifying mSurfaceHolder in any way, there's no reason to hold a lock on it. The only thing you have to keep in mind is that mState might get read between the time pause() gets called and you update it's value. If that's a problem, then synchronize on mState.
I have a class that extends the Thread class and has its run method implemented as so.
public void run(){
while(!terminate){
if(paused){
Thread.yield();
}else{
accummulator++;
}
}
}
This thread is spawned from the onCreate method.
When my UI is hidden (when the Home key is pressed) my onPause method will set the paused flag to true and yield the tread. However in the DDMS I still see the uTime of the thread accumulate and its state as "running".
So my question is. What is the proper way to stop the thread so that it does not use up CPU time?
It is actually bad practice to keep a thread running after onPause. The reason is that after onPause your application may drop out of memory at any time without your being able to know, therefore you will not be able to clean up after yourself.
The proper way to do it is stopping the thread onPause and recreating it onResume. If you need state you can use Android's built in saveState methods or settings or whichever to keep that.
Even though you're calling thread.yield(), you're inside of a while() loop which is probably looping thousands of time per second, each time calling .yield() but the fact that it's looping out of control means that it's using up resources. If you put a Log.d message in there you'll see what I mean.
I recommend using a Thread.sleep() instead of Thread.yield(). The reason being, while a thread is sleeping it is yielded. Plus with the sleep you get the added benefit of slowing down the while() and not using up resources. A sleep interval of 500ms should be sufficient =)
Your paused variable is most likely being cached thread-locally. This is because it's only being read and not changed in the loop. So what is happening is that compiler/interpreter/jitter optimizes by only reading the variable once and then only executing the else branch. You need to mark that field as volatile for the pause variable to be read every iteration through the loop. Check out the documentation of the volatile keyword. Here's some info about threading and some info about synchronization and concurrency.