My Android App works fine, except the end sequence. Its a game and at the end the screen shows the score:
TextView allscores = new TextView(this);
allscores.setText("Your score: "+ mypoints);
Next I want the GUI to slowdown for a few seconds so the user has time to take in the information. Maybe 2 or 3 secs is fine.
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
layout.removeAllViews();
Bear in mind, I'm new to thread programming. All this is done on the UI thread, I have no other threads running.
Next I put in a final splash screen ending:
AnView animator = new AnView(this);
layout.addView(animator);
where AnView is my own extension of View.
All in all it runs great. Problem is the thread sleeps for 3 seconds without showing my final score. I don't know why. I don't know why it doesn't show my final score before sleeping. It actually goes blank, indicating that it removed all views and then slept.
You're not seeing the score because sleeping on the UI thread prevents the layout and drawing operations that make your text changes visible. Never sleep on the UI thread.
Using a new thread for this is overkill. Use a Handler and the postDelayed method to make something happen after a delay.
private final Handler mHandler = new Handler();
Then when you want to do something later,
mHandler.postDelayed(new Runnable() {
public void run() {
doDelayedThing();
}
}, 3000);
As others have pointed out: don't use sleep in the UI thread.
What you should do instead is described here:
http://developer.android.com/guide/appendix/faq/commontasks.html#threading
in section "Handling Expensive Operations in the UI Thread"
It is not recommended to ever sleep the main UI thread. Try something like this:
new Thread(new Runnable(){
//do work here
});
Or you could try using a Toast popup for the score.
You can also use Timer to wait 3 seconds, which will start a new thread after the time runs out.
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
AnView animator = new AnView(this);
layout.addView(animator);
}
}, 3000);
Related
I have a button that plays a rewarded ad, but it takes a few seconds for the ad to load. I want the button text to cycle between "Video loading." "Video loading.." and "Video loading..."
I've used the following runnable for this:
public Runnable CountDown = new Runnable() {
public void run() {
btnVideoStarts.setText("Video loading.");
handler.postDelayed(this, 1000);
btnVideoStarts.setText("Video loading..");
handler.postDelayed(this, 1000);
btnVideoStarts.setText("Video loading...");
if (rewardedInterstitialAd != null) {
btnVideoStarts.setText("Start video");
handler.removeCallbacks(CountDown);
}
}
};
The button shows "Video loading..." the whole time until it changes to "Start video".
Does anyone know why it's only showing those two labels?
I used to have a countdown timer that worked. Here's the code for it:
public Runnable CountDown = new Runnable() {
public void run() {
btnVideoStarts.setText("Video ready in " + String.valueOf(buttonCount)+"s");
buttonCount --;
handler.postDelayed(this, 1000);
if (buttonCount ==0) {
btnVideoStarts.setText("Start Video");
handler.removeCallbacks(CountDown);
}
}
};
The only problem was that the load times varied, so I figured I'd be better off just saying "Video loading..." rather than have the countdown expire before the video was ready.
I don't understand why the old code worked, but the new code doesn't. Can someone show me where I've gone wrong?
I'm not a 100 percent sure, but as fas as I understand handler.postDelayed() from
this explanation
Causes the Runnable r to be added to the message queue, to be run
after the specified amount of time elapses. The runnable will be run
on the thread to which this handler is attached. The time-base is
SystemClock.uptimeMillis(). Time spent in deep sleep will add an
additional delay to execution.
you will just add it to a queue, and execute it after 1000ms, so it won't delay the current execution, but will start the run() method again, after 1000ms.
To break down your code:
public Runnable CountDown = new Runnable() {
public void run() {
btnVideoStarts.setText("Video loading."); // sets the text to "Video loading."
handler.postDelayed(this, 1000); // adds itself to a queue, but won't stop the execution of this run through
btnVideoStarts.setText("Video loading.."); // sets the text to "Video loading.."
handler.postDelayed(this, 1000);
btnVideoStarts.setText("Video loading..."); // Finally sets the text to what you will always see, because the time window, between the text changes is to small
if (rewardedInterstitialAd != null) {
btnVideoStarts.setText("Start video");
handler.removeCallbacks(CountDown);
}
}
};
So essentially, you're generating a loop, with both of you're methods, as both will call themselves (delayed), your second method works, because you don't set the text twice in the method.
If you want to wait inside a Runnable, use Thread.sleep(ms) and a loop, that stops, when the video is loaded
this is how I'm trying to accomplish this:
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("Hello there");
Thread.sleep(1000);
panel.updateUI();
}
});
I set Enter button as the default button so when I keep pressing it the button press maybe 100 times or more but because I'm using Thread.sleep(1000) it takes some time so I have time to type in my JtextField or even close the window but can't do anything.
also, I tried to put btnNewButton.addActionListener() in the run method of a thread but no difference.
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("Hello there");
Thread.sleep(1000);
panel.updateUI();
}
});
}
});
thread.start();
// I used try catch block in real code
can anyone help me to solve the issue?
**I'm creating this application in eclipse using windowsBuilder.
This is because of something that is called EDT - the Event Dispatch Thread.
This special purpose thread is responsible for all the events in your GUI - including drawing (refreshing) and interactions (button click). This means, that exactly the same thread is used to draw your application as the one that is used to execute actionPerformed code. Since you are literally halting that thread for some amount of time, your application will be non responsive for that exact period of time.
Whatever is being executed on user interactions should be short and execute fast for the reason of not blocking the application. If you need to do some heavy stuff, there is a facility for that purpose called SwingWorker that allows you to easily do some processing in the background thread (pool) and schedule UI updates during execution (like update of progress bar)
In your second "thread" snippet, your thread is not doing anything beside adding actionListener to the button, and then it terminates (probably after less than 1ms ;)) - action callback is still executed by the EDT. If you would start that custom thread from inside of run method - then it would be indeed in parallel and GUI would not be frozen - but again, SwingWorker is the way to go here.
Not entirely sure what your code is supposed to do, but if you want to press the button and then 1000ms later it will check your field you should do something like this:
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
System.out.println("before 1000ms");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("after 1000ms");
System.out.println("Reading the text field ...");
}
});
thread.start();
System.out.println("after the thread");
Output:
after the thread
before 1000ms
after 1000ms
Reading the text field ...
All this is in the same class and onCreate method:
String arrayExtra[] = {"1"};
for(int x = 0; x < arrayExtra.length; x++){
Thread thread = new Thread(new Runnable(){
#Override
public void run(){
try{
final EditText etAbun = (EditText) findViewById(R.id.etIsoAbunNum);
synchronized(this){
wait();
allExtraiso.add(etAbun.getText().toString());
}
}catch(Exception e){
e.printStackTrace();
}
}
});
Thread thread2 = new Thread(new Runnable(){
#Override
public void run(){
try{
synchronized(this){
Thread.sleep(1000);
final Button bNext = (Button) findViewById(R.id.bIsoAbunSave);
bNext.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View arg0){
notify();
}
});
}
}catch(Exception e){
e.printStackTrace();
}
}
});
thread.start();
thread2.start();
try{
thread.join();
}catch(InterruptedException e){
e.printStackTrace();
}
try{
thread2.join();
}catch(InterruptedException e){
e.printStackTrace();
}
}
What this code should do, is create 2 threads, wait for a button click, then when the button is clicked, do notify(), then continue the remaining code. What this does is though is just freeze the screen. The for loop should not be running forever, but I am not sure.
You are starting the separate threads and the call join() on them right away. The call join() is executed by your main thread (since you are in onCreate). What this method does is tell your current thread to wait until the other thread is finished. So your main thread gets blocked until the other thread dies.
But your threads are waiting for the user to click a button. User events are processed by the UI thread, which is currently blocked in join(). So the click is not processed, the event handler will never be called and you have a deadlock situation.
Multi-threading should be avoided whenever possible, because it adds a lot of complexity to your program and often does not add any benefits. It is necessary when doing something time consuming in android and you don't want to block the UI thread with that task.
You should probably remove the threads and find some other way to achieve what you want.
Update
There is actually another problem with your code, that would also prevent it from working: you are synchronizing, waiting and notifying on different objects. So the call to notify() would never reach the thread in wait() even if the click event was processed.
You seem to be doing the major part of your work inside the Main Thread (UI thread) I don't think you want to use join here. A reentrant Lock with a Condition object is probably what your are looking for if you want to keep this mechanic. with this you will be able to await inside you thread Object when you want to block and signal when the button is pushed.
http://developer.android.com/reference/java/util/concurrent/locks/ReentrantLock.html
but unless you wanted to do processing before the button was pushed, creating the thread lazily upon the action occurring might be a good approach. AsyncTask might also be very good to look at.
I want to do something very simple. I have a progress-bar and a textView that I want to dynamically update on a button click, but more than once during the function call.
I want it to change to 'A' then wait a second, then switch to 'B' ... for example.
I understand that my function blocks the UI/main thread, which is what if I setText() ten times, I only see the tenth text appear when the function completes.
So I've tried handlers/runnables in the UI thread, invalidating (and postInvalidating) to encourage refreshing and runOnUiThread() and they all just update when they've finished running leaving me only with the final state.
public void requestPoint(View v) {
textProgress.setText("Requesting A Point");
waiting(200);
progressBar.setProgress(5);
textProgress.setText("Request Received!");
waiting(500);
....
}
I think I've turned nearly all the similar question links purple and wasted way too much time on this simple thing (although I did learn a lot about threading on Android) but I feel I must be missing something crucial, this doesn't seem like that hard of task.
Any help would be greatly appreciated.
Assuming you really do just want to waste time with your waiting method. This is assuming a 200ms delay followed by a 500ms delay like in your example.
public void requestPoint(View v) {
textProgress.setText("Requesting A Point");
handler.postDelayed(new Runnable(){
public void run(){
progressBar.setProgress(5);
textProgress.setText("Request Received!");
}
}, 200);
handler.postDelayed(new Runnable(){
public void run(){
....
}
}, 700);
....
}
I'd like to accomplish something which I would think to be simple, but is turning out to be a hassle.
I have a loading screen with a picture, and I'd like for it to fade in and out as the application is loading. I decided to accomplish this by changing it's opacity frequently relative to the sine value of a counter. My code is as follows:
ImageView loadingRaven; //loading raven at the start of the app
Timer timer; //timer that we're gonna have to use
int elapsed = 0; //elapsed time so far
/*
* the following is in the onCreate() method after the ContentView has been set
*/
loadingRaven = (ImageView)findViewById(R.id.imageView1);
//fade the raven in and out
TimerTask task = new TimerTask()
{
public void run()
{
elapsed++;
//this line causes the app to fail
loadingRaven.setAlpha((float)(Math.sin(elapsed)+1)/2);
}
};
timer = new Timer();
timer.scheduleAtFixedRate(task, 0, 50);
What is the problem that's causing my program to fail? Am I correctly using Timer and TimerTask? Or is there perhaps a better way to update the opacity of the image frequently so it eases in and out smoothly?
Thanks
TimerTask runs on a different thread. So update ui on the main ui thread. Use runonuithread
TimerTask task = new TimerTask()
{
public void run()
{
elapsed++;
runOnUiThread(new Runnable() //run on ui thread
{
public void run()
{
loadingRaven.setAlpha((float)(Math.sin(elapsed)+1)/2)
}
});
}
};
TimerTask runs on a different thread. You can use Handler and postDelayed as suggested by
pskink