SurfaceView and thread already started exception - java

Checking the LunarLander example it uses that code for resume the drawer thread:
public void surfaceCreated(SurfaceHolder holder) {
// start the thread here so that we don't busy-wait in run()
// waiting for the surface to be created
thread.setRunning(true);
thread.start();
}
and this for end:
public void surfaceDestroyed(SurfaceHolder holder) {
// we have to tell thread to shut down & wait for it to finish, or else
// it might touch the Surface after we return and explode
boolean retry = true;
thread.setRunning(false);
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
But when I execute the project, press the home button and resume the application it crashes with
java.lang.IllegalThreadStateException: Thread already started.
at java.lang.Thread.start(Thread.java:1045)
at com.example.android.lunarlander.LunarView.surfaceCreated(LunarView.java:862)
at android.view.SurfaceView.updateWindow(SurfaceView.java:533)
at android.view.SurfaceView.onWindowVisibilityChanged(SurfaceView.java:226)
at android.view.View.dispatchWindowVisibilityChanged(View.java:5839)
at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:945)
at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:945)
at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:945)
at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:945)
I've seen this method for handling the background thread in other examples but it crashes. What is the problem with it?

Your thread is still running, you dont stop it correctly i guess.
You have to interrupt your thread or thats how i solved it. So instead of using setRunning and a boolean to make your thread run you use something like this:
to start it:
public void surfaceCreated(SurfaceHolder holder) {
thread.start();
}
In the thread:
public void run() {
try {
while (true) {
// code here
}
}
catch (InterruptedException e) {
//disable stuff here
}
}
And to stop it:
public void surfaceDestroyed(SurfaceHolder holder) {
thread.interrupt();
}
I just typed this quickly but it should give you an idea.

You can do it like this:
#Override
public void surfaceCreated(SurfaceHolder holder) {
if (!thread.isAlive()) {
thread.start();
}
}

This is how I solved this issue. In the surfaceCreated method, the state of the thread may have changed to TERMINATED. You need to create the thread a new.
#Override
public void surfaceCreated(SurfaceHolder holder) {
bgSurfaceThread = bgSurfaceThread.getState().equals(Thread.State.TERMINATED) ? bgSurfaceThread : new BackgroundSurfaceThread(BackgroundSurfaceView.this);
bgSurfaceThread.setRunning(true);
bgSurfaceThread.start();
}

Related

java update screen in thread

Im writing a script which consists of a thread with a wait. If the thread get executed, it doesn't update the screen. In the script i change a picture to another picture, but it doesn't show it until I press the button again. So the main question is: After setting an different Image Resource, i need to update the screen.
Here is the code:
public void Start(View view) {
Runnable r = new Runnable() {
#Override
public void run() {
int i =0;
while(i<12) {
synchronized (this) {
try {
Setfoto(i);
Thread.sleep(1000);
Log.i(TAG, "Begonnen met loop");
Log.i(TAG, "i = " + i);
i = i +1;
} catch (Exception e) {}
}
}
}
};
Thread buckysThread = new Thread(r);
buckysThread.start();
}
public void Setfoto(int nummer) {
if (nummer == 1) {
een.setImageResource(R.drawable.eerster);
Log.i(TAG, "Foto 1 wordt rood");
} if(nummer ==2) {
twee.setImageResource(R.drawable.eerster);
Log.i(TAG, "Foto 2 wordt rood");
} if(nummer ==3) {
drie.setImageResource(R.drawable.tweer);
Log.i(TAG, "Foto 3 wordt rood");
}
}
You'll need to have some sort of way to run code on the UI thread, which is responsible for updating the contents of the screen and manipulating views.
Activity.runOnUiThread(Runnable) can be called. Any code placed in there will be run on the UI thread.
You can use runOnUiThread, AsyncTask or Thread-Handler to implement your task
Activity.runOnUiThread
runOnUiThread(new Runnable() {
public void run() {
//Do something on UiThread
}
});
Thread-Handler
Communicating with the UI Thread
AsyncTask
AsyncTask Tutorial

how to sleep in for loop until finished loading page android

I am making an app to do something in webview automatically.
I want to make a pause between two lines inside (for-loop) until page finished loading without using Thread.sleep because it freezing my application.
this is my code:
webview.loadUrl("http://**********");
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
for(int i=1;i<10;i++){
evaluateJavascript( "document.getElementById('select').value=" + i)
evaluateJavascript("document.getElementById('Search').click();")
//wait until finished loading
while( isloading() ){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
evaluateJavascript( "document.getElementById('any_select').value=5")
.
.
.
.
}
public boolean isloading(){
boolean isloading;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
webview.evaluateJavascript("(function() { return document.getElementById(\"Loading\").style.display; })();", new ValueCallback<String>() {
#Override
public void onReceiveValue(String s) {
if(s.equals("none")){
isloading=false;
}else{
isloading=true;
}
}
});
}
if(isloading=true)return true;
if(isloading=false)return false;
}
If you don't want to use Thread.sleep then the alternative is to use AsyncTask in your application.
You can do your loading task in doInBackground() method of AsyncTask and call it using new AsyncTaskClass.execute();
You can go through it from here : http://developer.android.com/reference/android/os/AsyncTask.html
You can do something similar (instead of AsyncTask):
Edit:
Timer timer = new Timer();
while( isloading() ){
try {
timer.schedule( new TimerTask(){
public void run() {
//
}
}, delay);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
If you want to achieve, what i understand, that once your second line is called you want to stop there and when after 1000 ms you want to continue. You can do one thing, copy all the code after your second line and put that in run method of below code:
new Handler().postDelayed(new Runnable()
{
#Override
public void run() {
}
}, 1000);
It will execute you code after 1000ms
If you want to execute sequentially actions happening on UIThread and in backgrounds threads you should be looking for the Bolt Library by Parse/Facebook.
It apply Javascript promises to Android application.
You can go through it from here : https://github.com/BoltsFramework/Bolts-Android

Avoid Thread has already been started exception (Android)

java.lang.IllegalThreadStateException: Thread already started
at java.lang.Thread.checkNotStarted(Thread.java:849)
at java.lang.Thread.start(Thread.java:1059)
at com.name.MainActivity$MenuView$1.surfaceCreated(MainActivity.java:496)
How can I avoid this? I have an inner class MenuView which extends SurfaceView. It updates a canvas on a thread. onSurfaceCreated() I start the thread, and onSurfaceDestroyed() I call thread.join() to stop the thread. However, if the Google Play Sign in window pops up, and I press the home button while it is in focus, and reopen the app. I get a force close error and the exception that I posted above.
holder.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
allow_thread_to_run = true;
boolean retry = true;
while (retry) {
if (t!=null && !t.isAlive()) {
t.start();
retry = false;
}
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
allow_thread_to_run = false;
boolean retry = true;
if(t!=null && t.isAlive()) {
while (retry) {
try {
t.join();
retry = false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
});
}
So why does this Google Play window coming into focus cause my thread to start twice. From what I see, my setup has the necessary check isAlive() to make sure to avoid this!
I agree with #adelphus's view.If you care for the code of Thread calss,you will find that.Every Thread object has a flag that reflects whether this Thread has already been started.
boolean hasBeenStarted = false;
Once you invoke start() method,it will check the state and change if it is false,otherwise throw an exception like what you have got.see,
public synchronized void start() {
checkNotStarted();
hasBeenStarted = true;
nativeCreate(this, stackSize, daemon);
}
later,the state will never be changed. When you invoke start() again,it will throw an exception.

Start an Activity from Splash Screen, should I use run() or runOnUiThread()?

I have a Splash Screen (Logo Activity) to show the company name for 3 seconds before app starts. I start Main Activity from a thread, here is the code:
public class Logo extends Activity {
Thread t;
public boolean dead = false;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.logo);
t = new Thread() {
public void run() {
try {
Intent i = new Intent(Logo.this, Main.class);
Thread.sleep(3000);
if (!dead) {
startActivity(i);
}
finish();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
t.start();
}
The Main Activity is called from a worked thread, is this correct? What are the differents with this code (using runOnUiThread)?
...
if (!dead) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Intent i = new Intent(Logo.this, Main.class);
startActivity(i);
}
});
}
...
I see no difference with this code in debug mode (The same threads, the same operation, etc.). Which is correct?
Starting an intent I think is not an UI operation. runOnUI thread runs UI operation on UI thread. So you can use either of thread (runOnUI or normal). May be normal thread will be good in this situation. But I would like to suggest you use timer instead.
To be honest, I don't like the Thread.sleep. PLease take a look at my solution:
new Timer().schedule(new TimerTask() {
#Override
public void run() {
// Do your work here like... startActivity...
}
}, SPLASH_DURATION); // SPLASH_DURATION IS IN MILLISECONDS LIKE 3000
Also you can block the user to prevent the back key like this:
#Override
public void onBackPressed() {
// do nothing! disable user interaction!
}
You should use AsyncTask in "doInBackground" background thread and than sleep your thread(this thread not UIThread) "PostExecute" run on UI Thread than start your new activity
private class mSplashViewer extends AsyncTask<Void,Void,Void>{
protected void doInBackground(Void params){
Thread.currentThread().sleep(3000);
return null;
}
protected void onPostExecute(){
startActivity(...);
}
}

How can I restart a thread in java/Android from a button?

I have a thread in java/Android like this:
Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
update_i();
}
};
#Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
Thread myThread = new Thread(new Runnable() {
public void run() {
while (true) {
try {
handler.sendMessage(handler.obtainMessage());
Thread.sleep(timer);
} catch (Throwable t) {
}
}
}
});
myThread.start();
}
The thread works fine when I run my application. But I want to start/restart the thread with a button.
Button.OnClickListener StartButtonOnClickListener = new Button.OnClickListener() {
#Override
public void onClick(View v) {
//start/restart the thread
}
};
If I copy the thread into the button I just make a new thread every time the user clicks on the button. I want to run the thread when the user first time click on the button, "kill it" and start from the beginning if the user click on the button a second time (I don’t want to start a second thread).
I think that Colin is wright you can´t just restart you need to make a new instance, and the interrupt function will stop the running thread if it is still running.
I recommend you make an inner class, instand of an inline implementation, it will make it easier to understand.
if(myThread.isAlive()){
myThread.interrupt();
}
myThread = new MyThread();
myThread.start();
hope this helps
You can't restart a Thread.
From the documentation :
Throws IllegalThreadStateException
if the Thread has been started before
You can kill the previous thread, but in the end you will have to create a second instance of your thread.
Resources :
Javadoc Android - Thread.start()

Categories