I have an app that shows a disclaimer at the beginning of the program. I want a button to remain invisible for a set amount of time, and then become visible.
I set up a thread that sleeps for 5 seconds, and then tries to make the button visible. However ,I get this error when I execute my code:
08-02 21:34:07.868: ERROR/AndroidRuntime(1401): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
How can I count 5 seconds, and then make the button visible?
THanks.
Thread splashTread = new Thread() {
#Override
public void run() {
try {
int waited = 0;
while(_active && (!_ok2)) {
sleep(100);
if(_active) {
waited += 100;
if(waited >= _splashTime)
{
turnButtonOn();
}
}
}
} catch(InterruptedException e) {
// do nothing
} finally {
finish();
startActivity(new Intent("com.lba.mixer.Choose"));
}
};
splashTread.start();
public static void turnButtonOn() {
okButton.setVisibility(View.VISIBLE);
}
The problem is that you're not in the UI thread when you call okButton.setVisibility(View.VISIBLE);, since you create and run your own thread. What you have to do is get your button's handler and set the visibility through the UI thread that you get via the handler.
So instead of
okButton.setVisibility(View.VISIBLE)
you should do
okButton.getHandler().post(new Runnable() {
public void run() {
okButton.setVisibility(View.VISIBLE);
}
});
I found this to be a much simpler solution. Visibility on 7 second delay
continuebutton.setVisibility(View.INVISIBLE);
continuebutton.postDelayed(new Runnable() {
public void run() {
continuebutton.setVisibility(View.VISIBLE);
}
}, 7000);
I found this a Better solution to the problem
(button id = but_resend)
define handler
private Handler handler;
call function in extend class
showButtons();
define after class
private void showButtons() {
handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
((Button) findViewById(R.id.but_resend)).setVisibility(View.VISIBLE);
}
}, 20000); // produce 20 sec delay in button visibility
}
and keep in mind to hide the visibility in the.xml file by
android:visibility="invisible"
Related
So I'm attempting to create background task that needs to be run every hour in an Android app. Its a rather heavy task that takes around 5 - 10 minutes to finish, and right now it runs on the UI thread which of course isn't good, because it hangs the whole application. I've attempted the following in my MainActivity onCreate:
new Thread(new Runnable() {
private Handler HeavyTaskHandler = new Handler(Looper.getMainLooper());
public void run(){
final TextView updatedTxt = findViewById(R.id.txt);
updatedTxt.post(new Runnable() {
#Override
public void run() {
updatedTxt.setText("Performing cleanup..");
}
});
HeavyTask(); // <-- This method runs for 5 - 10 minutes
updatedTxt.post(new Runnable() {
#Override
public void run() {
updatedTxt.setText("Done..");
}
});
HeavyTaskHandler.postDelayed(this, HeavyTaskCycle);
}
}).start();
I have two issues with the above
It works fine the first time, and the task is performed in the background well without hanging the UI thread. However, after this first time and the next time(s) it is run, the UI thread hangs again when it is run. What am I missing?
Notice that before the HeavyTask() method is called i try to set a TextViews text to "Performing cleanup.." .. This never shows, only the "Done.." which happens after the HeavyTask() method is done. How can i ensure that the message also appears before?
I ended up doing the following from MainActivity which doesn't hang the application
private void CreateCleanUpThread()
{
CleanUpThread = new Thread(new Runnable() {
public void run(){
try {
while(true) {
performingCleanup = true;
final TextView updatedTxt = findViewById(R.id.updated_txt);
runOnUiThread(new Runnable() {
#Override
public void run() {
updatedTxt.setText("Performing database history cleanup..");
}
});
HeavyTask(); // <-- This method runs for 5 - 10 minutes
runOnUiThread(new Runnable() {
#Override
public void run() {
updatedTxt.setText("Done..");
}
});
performingCleanup = false;
Thread.sleep(CleanUpCycle); // 1 hour wait time
}
} catch(Exception ex) {
System.out.println("Error in CreateCleanUpThread : " + ex.getMessage());
}
}
});
}
// onCreate in MainActivity
...
CleanUpThread.start();
Certainly not the best way, but it works and will do for now. Should be moved to a service instead i think.
I created one handler to repeat a task repeatedly and I also want to destroy it within that handler once a condition has been met.
pinHandler = new Handler();
Now I created two functions separately to start and stop the task.
void startRepeatingPins() {
mPinSetter.run();
}
Runnable mPinSetter = new Runnable() {
#Override
public void run() {
try{
System.out.println("PinIndwx count is :"+pinIndexCount);
if(pinIndexCount==(plist.size()-1))
{
stopUpdatingPins();
pinIndexCount=0;
//pinHandler.removeCallbacks(mPinSetter);
System.out.println("Handler stopped by itself.");
}
else
{
updatePoint(plist.get(pinIndexCount));
pinIndexCount++;
}
}
finally {
pinHandler.postDelayed(mPinSetter, pinInterval);
}
}
};
private void stopUpdatingPins()
{
pinIndexCount=0;
pinHandler.removeCallbacks(mPinSetter);
System.out.println("Called the stop function.");
}
Now, the issue is that, if I call the stopUpdatingPins function , the handler stops but when I try to stop it automatically from within the handler, it just doesn't stop. Although the stopUpdatingPins function does get called.
Change You startRepeatingPins() like this, You should not directly call the run. If your run like this then there is no point of removing this from Handler. So attach Runnable with Handler.
void startRepeatingPins() {
pinHandler.post(mPinSetter);
}
You added post delay in finally that means you are stopping at first if loop and starting again in finally, So it's never stopping. So Change your runnable like this,
Runnable mPinSetter = new Runnable() {
#Override
public void run() {
System.out.println("PinIndwx count is :"+pinIndexCount);
if(pinIndexCount==(plist.size()-1))
{
stopUpdatingPins();
pinIndexCount=0;
//pinHandler.removeCallbacks(mPinSetter);
System.out.println("Handler stopped by itself.");
}
else
{
updatePoint(plist.get(pinIndexCount));
pinIndexCount++;
pinHandler.postDelayed(mPinSetter, pinInterval);
}
}
};
I've got a listView that gets populated from a server. In the onClick of the ListItem, I display a button for a x number of seconds and I make it invisible again. How can I reset the time every time the onClick is called?
Here is my listItem onClick:
private void displayInCallButton() {
mButton.setEnabled(true);
if (canDisplayInCallControlls) {
canDisplayInCallControlls = false;
fadeInAnimation(mButton);
mButton.setEnabled(true);
mFrontView.postDelayed(new Runnable() {
public void run() {
fadeOutAnimation(mButton);
mButton.setEnabled(false);
hasAnimationEnded = true;
canDisplayInCallControlls = true;
}
}, 5000);
}
}
Thank you in advance.
You have to remove the callbacks and set it once again with the new one with the reset time.
first, set the call back like
Runnable myRunnable = new Runnable() {
#Override
public void run() {
fadeOutAnimation(mButton);
mButton.setEnabled(false);
hasAnimationEnded = true;
canDisplayInCallControlls = true;
}
};
then set it to mFrontView like,
mFrontView.postDelayed(myRunnable,5000)
If you want to reset, do it like
mFrontView.removeCallbacks(myRunnable);
mFrontView.postDelayed(myRunnable, 2000);
How can I reset the time every time the onClick is called?
There is no built-in mechanism to accomplish that.
You can, however, keep a reference to the Runnable you post, remove it and then repost it again to restart at the original delay.
The result would look somewhat like this in its most simple form:
Runnable mDelayedRunnable = new Runnable() {
#Override public void run() {
fadeOutAnimation(mButton);
mButton.setEnabled(false);
hasAnimationEnded = true;
canDisplayInCallControlls = true;
}
};
private void displayInCallButton() {
mButton.setEnabled(true);
if (canDisplayInCallControlls) {
canDisplayInCallControlls = false;
fadeInAnimation(mButton);
mButton.setEnabled(true);
mFrontView.removeCallbacks(mDelayedRunnable);
mFrontView.postDelayed(mDelayedRunnable, 5000);
}
}
You can safely call removeCallbacks() with a Runnable that was never posted in the first place (or even null).
If you don't want to keep an explicit reference to the Runnable, you could also opt to tag the view with it. Just don't forget to clean up on i.e. orientation changes and the like.
I would like to set a background of a table to blink with the collors red + white every 500 millisec for start.The ideea is I want it to implement in this loop inside the program and I don't know how.
if(Integer.parseInt(feedback.getText().toString()) == 0)
{
showup.setText("0");
btnbool.setBackgroundColor(Color.RED);
btnbool.setText("FALSE");
}
I have searched on previous topics but I couldn't find something that work in my code, I don't know how to use a handler to make this happen.There won't be a problem if I call a function to do this.
In top of your Activity class implement these:
// isRed flag to set bg to red or white
boolean isRed = true;
Handler handler = new Handler();
MyThread thread = new MyThread();
private class MyThread implements Runnable {
public void run() {
showup.setText("0");
if (isRed){
btnbool.setBackgroundColor(Color.WHITE);
isRed=false;
}
else{
btnbool.setBackgroundColor(Color.RED);
isRed=true;
}
btnbool.setText("FALSE");
// will run every 500 milliseconds or whatever you wish
handler.postDelayed(thread, 500);
}
}
run your thread in your onCreate() :
handler.post(thread);
to start/stop thread onClick of Button:
on top of your activity:
boolean threadStart = true;
inside your onclick event:
if (threadStart){
handler.removeCallbacks(thread);
threadStart=false;
}
else{
handler.post(thread);
threadStart=true;
}
Timer or ScheduledExecutorService.
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
when you want to launch it
executorService.schedule(blinkRunnable, 500, TimeUnit.MILLISECONDS);
the runnable to execute:
private Runnable blinkRunnable = new Runnable(){
#Override
public void run() {
if(Integer.parseInt(feedback.getText().toString()) == 0)
{
showup.post(new Runnable() {
#Override
public void run() {
showup.setText("0");
btnbool.setBackgroundColor(Color.RED);
btnbool.setText("FALSE");
}
});
}
executorService.schedule(blinkRunnable, 500, TimeUnit.MILLISECONDS); // start again
}
}
P.S You could put the colors in an array, use an index and make something more flexible.
I simply want to change the bitmap image of an imageview on a set interval ( 2 seconds)
I have tried this but the app crashes:
private void prefromRadarInterval() {
int delay = 1000; // delay for 0 sec.
int period = 1000; // repeat every 1 seconds.
timer = new Timer();
timer.scheduleAtFixedRate(new SampleTimerTask(), delay, period);
}
public class SampleTimerTask extends TimerTask {
#Override
public void run() {
//MAKE YOUR LOGIC TO SET IMAGE TO IMAGEVIEW
imageview_radarcurrent.setImageBitmap(radar_animation[flag]);
flag++;
if(flag > 9) {
flag = 0;
}
}
}
The log cat prints this:
01-12 04:51:51.688: E/AndroidRuntime(19688): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
Help and explanation would be appreciated!
Your problem is that the UI can only be modified buy the UI thread, and your TimerTask is running on it's own thread. The easiest way to solve this is probably by posting through a handler to the UI thread.
Take a look at this thread:Android timer updating a textview (UI)
You should call the setImageBitmap() from the UI thread.
For example:
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
// Write your code here
}
});
... or post it with a Runnable:
imageview_radarcurrent.post(new Runnable() {
#Override
public void run() {
}
});