Java sleep commands ignore commands before the sleep - java

I have a button on an activity, when I click it I want the button to change colour, wait some time and then change colour again.
I have tried the following two versions of the sleep:
Attempt 1:
public void buClick(View view) {
Button buCard = (Button) view;
buCard.setBackgroundColor(Color.GREEN);
TimeUnit time = TimeUnit.SECONDS;
try {
time.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
buCard.setBackgroundColor(Color.RED);
}
Attempt 2:
public void buClick(View view) {
Button buCard = (Button) view;
buCard.setBackgroundColor(Color.GREEN);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
buCard.setBackgroundColor(Color.RED);
}
With both methods the result is the same:
button is clicked
button's background remains as the default
the app waits for 2 seconds
the button's background changes to red
At no point does the button turn green; what am I doing wrong?
Thanks

Do not block your UI thread. Use a handler instead.
If you are trying to block your main thread the whole UI thread would stop causing your app to freeze, once your sleep is over you are calling setBackgroundColor(Color.RED). And the red color gets applied that is why you are not able to see the change of green color.
If you use a handler like the below case which wont block the UI thread you should be able to see the color change.
Read about why you should not block your UI thread here https://developer.android.com/guide/components/processes-and-threads.html
Button buCard = (Button) view;
buCard.setBackgroundColor(Color.GREEN);
Handler handler = new Handler();
Runnable r=new Runnable() {
public void run() {
buCard.setBackgroundColor(Color.RED);
}
};
handler.postDelayed(r, 2000);

Related

How to use Android's Looper in a drawing thread

I'm trying to make a simple airplane game to build my skills and have some fun. But I've hit a roadblock with Threads, Loopers, and message queues when trying to pass a message from an onTouch event of a TextView to the Thread drawing my airplanes. I'm going to try to include only the essential bits of code below and use "..." to indicate omitted lines.
I'm drawing in a separate, good old-fashioned android thread. Here's the constructor of the Thread:
public class BenThread extends Thread {
...
public BenThread(SurfaceHolder surfaceHolder, Context context,
BenSurfaceView surfaceView) {
this.surfaceHolder = surfaceHolder;
this.context = context;
this.surfaceView = surfaceView;
this.isRunning = false;
Bitmap planeImage = BitmapFactory.decodeResource(
context.getResources(), R.drawable.fighters);
airplane = new Airplane(50, 50, 2, 0, planeImage);
}
Before I show the run method, note that there's a SurfaceView that creates and starts the Thread when the SurfaceChanged() is called. In the onCreate() of my main Activity, I create a final instance of my custom SurfaceView:
final BenSurfaceView surfaceView = (BenSurfaceView) findViewById(R.id.surfaceView);
In the UI layout, there a TextView sitting at bottom center with an OnTouchListener hooked up. In onTouch(), for MotionEvent.ACTION_DOWN, the following line is called:
surfaceView.thread.handler.sendEmptyMessage(1);
Back to the thread class, the handler for this empty message is created in the run method, along with the Looper creation:
public void run() {
super.run();
Looper.prepare(); // Creates a Message Queue for the thread
MessageQueue queue = Looper.myQueue();
queue.addIdleHandler(new IdleHandler() {
#Override
public boolean queueIdle() {
Looper.myLooper().quit();
return false;
}
});
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
Log.i("HANDLING", "SOMETHING");
}
};
Looper.loop();
while (isRunning) {
currentTime = System.currentTimeMillis();
// spin in a while loop for a while
while ((currentTime - previousTime) < REFRESH_RATE) {
currentTime = System.currentTimeMillis();
}
airplane.move();
canvas = surfaceHolder.lockCanvas();
if (canvas != null) {
surfaceView.draw(canvas);
airplane.draw(canvas);
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
Now if I run as is, I get a nice little animation of airplanes moving across the screen.
But, when I click the Button at the bottom, I see from the log that I sent a message to a dead thread. Well, I guess I killed it in the IdleHandler. So now let me comment out the quit method:
// Looper.myLooper().quit();
Now my app looks considerably less exciting:
But, when I click the Button at the bottom and look at the log, there is proof that my message has been handled! So the big question is, how can I run the message loop and still see my animation?
After you call Looper.loop(), it should not return until the thread is ready to stop. Having your game loop after the Looper.loop() call doesn't make sense. At that point the thread is "dead" in the sense that the Looper is no longer listening for messages.
If you want your thread to run in while (isRunning), do that. If you want it to be message-driven, do that. Don't try to do both in the same thread. (And please don't spin on the CPU -- eats up battery quickly on a mobile device.)
You can find some notes about game loops, and about SurfaceView and threading, in appendices A and B of this article. There are various examples of animated rendering using Handler in Grafika. For example, the "record GL app" activity uses Choreographer to send a message to the render thread whenever it's time to draw.
It is because of the IdleHandler(). It is executed immediately quitting you looper. I commented your code:
public void run() {
super.run();
Looper.prepare();
MessageQueue queue = Looper.myQueue();
queue.addIdleHandler(new IdleHandler() {
// This is executed immediately when the looper is idle.
// So this looper is quitted
// and thread starts to execute "while" loop
#Override
public boolean queueIdle() {
Looper.myLooper().quit();
return false;
}
});
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
Log.i("HANDLING", "SOMETHING");
}
};
Looper.loop(); // Take into account that this function is blocking
// This "while" loop is executed after the looper is quitted from IdleHandler
// So why your game is running
// When you click your button it tries to send message to quitted looper
// and you get the corresponding error message
while (isRunning) {
currentTime = System.currentTimeMillis();
// spin in a while loop for a while
while ((currentTime - previousTime) < REFRESH_RATE) {
currentTime = System.currentTimeMillis();
}
airplane.move();
canvas = surfaceHolder.lockCanvas();
if (canvas != null) {
surfaceView.draw(canvas);
airplane.draw(canvas);
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
When you commented the IdleHandler the thread executes Looper.loop() (it is blocking) method so the while loop is not being reached.
After the clarification from #fadden and #armansimonyah13, I dropped the misguided attempt to send messages between threads. In the main Activity, rather than sending a message to the thread like so:
surfaceView.thread.handler.sendEmptyMessage(1);
and trying to handle it in the thread, I simply update public data in the thread (from within the TextView's onTouch handler):
surfaceView.thread.airplane.setVelocity(8);
Now when you click the TextView at the bottom, the planes speed up. That's the kind of UI-thread to rendering-thread interactivity I was going for.
By the way, now the run loop looks like:
#Override
public void run(){
while (isRunning) {
airplane.move();
canvas = surfaceHolder.lockCanvas();
if (canvas != null) {
surfaceView.draw(canvas);
airplane.draw(canvas);
surfaceHolder.unlockCanvasAndPost(canvas);
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

How to simulate client-side delay on Android without hanging the UI?

I have an Androd application that talks to a back-end web service. As part of the testing, I need to simulate different lengths of client-side delay when a submit button is pressed.
Right now, I am using a Thread.sleep() in my OnClickListener for my submit button, but sleeping the UI thread like this has the unintended consequence of causing the app to appear to "freeze" completely - the button stays highlighted until the thread wakes up and my ProgressBar is likewise completely frozen. Here is my code:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_checkout);
pBar = (ProgressBar) findViewById(R.id.progressBar1);
pBar.setVisibility(View.INVISIBLE);
Button submitButton = (Button) findViewById(R.id.btnSubmit);
submitButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
pBar.setVisibility(View.VISIBLE);
try {
Thread.sleep(3000); //eventually this delay will be random
//right now it obviously hangs the UI
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
performMyAppSpecificWorkHere();
pBar.setVisibility(View.INVISIBLE);
CheckoutActivity.this.finish();
}
});
}
I'm looking for ways I could simulate a delay without hanging the entire UI. Any ideas are welcome. Thanks!
edit
Some clarification here! Part of what I need to do is make simulate a delay and allow the user interface to handle it cleanly (which is what's NOT happening now).
ie...if there is a delay on either the client or the web service, the client should handle it by letting the spinner spin while it waits. The ability to simulate a back-end delay is already done and that works the way I want it to, but I want to simulate a delay on the client without hanging the UI thread.
here we go:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_checkout);
pBar = (ProgressBar) findViewById(R.id.progressBar1);
pBar.setVisibility(View.INVISIBLE);
Button submitButton = (Button) findViewById(R.id.btnSubmit);
submitButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Thread t=new Thread(new Runnable(){
#Override
public void run(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
performMyAppSpecificWorkHere();
runOnUiThread(new Runnable() {
#Override
public void run() {
pBar.setVisibility(View.INVISIBLE);
CheckoutActivity.this.finish();
}
}
}
});
pBar.setVisibility(View.VISIBLE);
t.start();
}
});
}
So, you are starting a new thread in the onClick event. This new thread should do the application work after sleeping for 3 seconds. After that, you want to update some ui objects, and you can not do that from inside a thread that isn't the UI Thread. That's why there is a runOnUiThread(..) after performing the work. Hope it helps!
First of all, don't block the main thread (the ui-thread), or else the gui will be freezed! Instead, use AsyncTask, where you put Thread.sleep(3000) inside doInBackground(), and then do whatever you want inside onPostExecute() (onPostExecute() is running in the main thread). Check my last answer on related question.
I think you should clarify here, you want to simulate server side delays and not the client side delay. You should put the sleep code in your server side code and not the client side code.
If it is not so, you can use asyncTask and execute the application code. You can put the sleep code inside it to simulate a client side delay.

Using the java timer

Until now I have been using the Timer that's in javax.swing.timer - all I had to do was to choose the speed and have a method with a specific name that executes what I want the timer to do every time.
I have now started programming an Android application recently and I have faced a couple of problems...
It wouldn't let me use or import javax.swing.timer
I tried using java.util.timer but I couldnt figure out how it works
All I want my timer for is so I can display my logo for 3 seconds and then proceed to the main menu - even if there is an easier solution for this, I'd still like to know how to use the timer
For the person who told me to try using a thread - here is my code - it doesnt paint the first screen at all, it just stays blank for 3 seconds then moves on to the next line of code...
public class logo extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
setContentView(R.layout.logoview);
Thread.sleep(3000);
}
catch (InterruptedException e){
e.printStackTrace();
}
setContentView(R.layout.main);
}
public void startup (View view){
Intent intent0 = new Intent (this,ExpiramantingActivity.class);
startActivity(intent0);}
}
}
in onCreate() function of your SplashActivity class, schedule a handler to display your main menu activity after 3 seconds. this should be done after setContentView(R.layout.splashscreen);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
startActivity(new Intent(SplashActivity.this,
YourMainMenuActivity.class));
finish();
}
}, 3000);
I believe that what you are trying to do is similar to the exhibition Splash Screen. If so, please check this Oracle tutorial.
try this:
// logo
Thread timer = new Thread(){
public void run(){
try{
sleep(3000);
} catch (InterruptedException e){
e.printStackTrace();
}
};
};
timer.start();
//next code
Maybe you can use a Thread? I think it's the simplest way to do what you want:
Where you display your logo:
try {
//show your logo here
Thread.sleep(3000); //3 seconds
} catch (InterruptedException e) {
e.printStackTrace();
}
Surrounding the code in a try/catch block is very important, because of the posibility of an Exception.

Android: Wait() the main thread while a dialog gets input in a separate Thread

I'm writing an activity in Android where the user modifies an SQL Database. The UI consists of an EditText where the user enters the name, and a Seekbar where the user enters how attractive the person is. Underneath there are a bunch of buttons: add, edit, view, delete.
When the user clicks on the "Edit" button, an input dialog is displayed asking the user to input the record number. Once that is done, that record is loaded.
The problem I was having was that the inputdialog would be displayed and while the user entering the record no, the rest of the edit method would carry on so that by the time the user was done entering the input - nothing happened because the function had already been completed.
In order to solve this problem, I decided to use Multi-Threads (which I do not have much experience using). When the edit button is pressed, the main UI Thread is blocked (using wait() - this is because I don't want the UI to be active while the user is entering the record id.) and the input dialog is displayed in a seperate thread.
Once the input has been entered, the thread is notified and the rest of the edit function continues. (The code is below).
The problem is that when I call the wait function on the UI Thread, I get an error that says "object not locked by thread before wait() ". How do I lock the UI Thread?
I know in general one shouldn't block the UI Thread, but I think it's okay in this case because I don't want it to accept any user input.
Thanks for your help.
public class Attractivometer extends Activity implements OnClickListener {
private Button buttonAddRecord, buttonEditRecord, buttonSaveChanges;
private Button buttonDeleteRecord, buttonViewRecord;
private EditText fieldName;
private SeekBar seekbarAttractiveness;
private String inputFromInputDialog=null;
private Thread inputThread;
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.Attractivometer);
buttonAddRecord = (Button) findViewById(R.id.buttonAddRecord);
buttonSaveChanges = (Button) findViewById(R.id.buttonSaveChanges);
buttonEditRecord = (Button) findViewById(R.id.buttonEditRecord);
buttonDeleteRecord = (Button) findViewById(R.id.buttonDeleteRecord);
buttonViewRecord = (Button) findViewById(R.id.buttonViewRecord);
fieldName = (EditText) findViewById(R.id.fieldName);
seekbarAttractiveness = (SeekBar) findViewById(R.id.seekbarAttractiveness);
buttonAddRecord.setOnClickListener(this);
buttonSaveChanges.setOnClickListener(this);
buttonEditRecord.setOnClickListener(this);
buttonDeleteRecord.setOnClickListener(this);
buttonViewRecord.setOnClickListener(this);
}
public void onClick(View clickedItem)
{
switch(clickedItem.getId())
{
case R.id.buttonAddRecord:
//.....
break;
case R.id.buttonSaveChanges:
//...
break;
case R.id.buttonEditRecord:
inputThread = new Thread(new Runnable(){
public void run()
{
showInputDialog("Enter Record ID", InputType.TYPE_CLASS_NUMBER);
}
});
inputThread.start();
try {
Thread.currentThread().wait();
} catch (InterruptedException e) {
Log.e("Attractivometer","Main Thread interrupted while waiting");
e.printStackTrace();
}
try {
inputThread.join();
} catch (InterruptedException e) {
Log.e("Attractivometer","Input Thread interrupted while joining");
e.printStackTrace();
}
int recordId = Integer.parseInt(inputFromInputDialog);
if(recordId!=null)
{
AttractivometerSQLHandler AttractivometerDatabaseHandler = new AttractivometerSQLHandler(this);
AttractivometerDatabaseHandler.openDatabase();
String recordName = AttractivometerDatabaseHandler.getName(recordId);
String recordAttractiveness = AttractivometerDatabaseHandler.getAttractiveness(recordId);
if(recordName==null || recordAttractiveness==null )
{
//no record found.
Toast.makeText(this, "No record with that ID found", Toast.LENGTH_SHORT).show();
}else
{
fieldName.setText(recordName);
seekbarAttractiveness.setProgress( Integer.parseInt(recordAttractiveness) );
recordIsOpen(true);
}
AttractivometerDatabaseHandler.closeDatabase();
}else
//No input.
recordIsOpen(false);
break;
case R.id.buttonDeleteRecord:
//...
break;
case R.id.buttonViewRecord:
//....
}
}
private void showInputDialog(String prompt, int inputType)
{
AlertDialog.Builder inputDialog = new AlertDialog.Builder(this);
inputDialog.setTitle("Record No.");
final EditText fieldInput = new EditText(this);
fieldInput.setInputType(inputType);
fieldInput.setHint(prompt);
inputDialog.setView(fieldInput);
inputDialog.setPositiveButton("OK", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface arg0, int arg1)
{
inputFromInputDialog = fieldInput.getText().toString();
inputThread.notify();
}
});
inputDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface arg0, int arg1)
{
inputFromInputDialog = null;
inputThread.notify();
}
});
inputDialog.show();
}
}
No, no, no! Do not block the UI thread. The system will raise an "Application Not Responding" error. Also, do not try to interact with the user from a non-UI thread.
When the user clicks "edit", don't start the edit method. Just pop up a dialog to collect the required information. Add a DialogInterface.OnClickListener to the positive button and (with the required information now in hand) start the edit method from there.
See the guide topic Dialogs for more information.
First of all, you should not pause the main Thread, because everything will be frozen if you do that, and from an user perspective, that is not good at all.
And second, you should pop up a dialog with 2 buttons, (Done, Cancel) and allow user to go further by pressing one of those buttons. Here you can find out how to display a custom dialog: http://www.helloandroid.com/tutorials/how-display-custom-dialog-your-android-application
First rule of multi-thread programming in Android is that, You should never stop UI thread, and all the long running operations should be made in separate thread. And by long running operations I mean, SQLite database writing/ reading etc.
before invoke wait need get the object lock like this:
synchronized(Thread.currentThread()) { //added
try {
Thread.currentThread().wait();
} catch (InterruptedException e) {
Log.e("Attractivometer","Main Thread interrupted while waiting");
e.printStackTrace();
}
}
but why you want to make main thread wait?

android progressbar on click of Home/Back button

I have implemnted progressbar in my small game like below
gameProgressBar =(ProgressBar)findViewById(R.id.GameProcess);
thrd = new Thread(progressBarThread);
thrd.start();
}
//Progress bar function
private Runnable progressBarThread = new Runnable(){
public void run() {
// TODO Auto-generated method stub
while (GameProgressCount<60){ //60 = 1 minute
try{
myHandle.sendMessage(myHandle.obtainMessage());
Thread.sleep(1000);
}
catch(Throwable t){
}
}
thrd.stop();
}
Handler myHandle = new Handler(){
#Override
public void handleMessage(Message msg) {
GameProgressCount++;
gameProgressBar.setProgress(GameProgressCount);
}
};
My question is that when i click on back/home button of the device, app is getting minimized (or goes previous screen) but the Progress bar thread would be running in the background. is it possible to pause the thread and resume when i minimize/open the app screen.
Thanks
You can pause the Thread in the OnPause method of the Activity and you can resume the Thread on OnResume method of the Activity which is pretty stright forward. Now if you wanted to Keep the GameProgressCount intact and wanted to Resume back from where it has left then you can use SharedPreference to store the value, when you resume back use the same value to start with.

Categories