I have a loading screen, I want to display the loadingMessage1 for 3 secs than shows loading message 2. I only want loading message 2 to appear once, but when I tried to do it, loading message 2 kept getting appended in an endless loop.
So i tried put a count variable to increases after every loading message 2 append, but it doesnt work. where am i going wrong, is there another solution to this?
final TextView loadingMessage1 = (TextView)this.findViewById(R.id.loadingMessage1);
int count = 0;
final Handler handler = new Handler();
if (count == 0){
handler.post(new Runnable(){
#Override
public void run(){
loadingMessage1.append("Loading Message 2");
handler.postDelayed(this, 3*1000L);
}
});
count++;
}
You are making a mistake on the following line:
handler.postDelayed(this, 3*1000L);
Here you send to this Runnable object to the handler while handling this. That means when you fist execute the Runnable, on the end you add it again to the handler's message loop. Thus you obtained an infinite loop. Something of the like will solve your problem:
final TextView loadingMessage1 = (TextView)this.findViewById(R.id.loadingMessage1);
int count = 0;
final Handler handler = new Handler();
handler.postDelayed(new Runnable(){
#Override
public void run(){
loadingMessage1.append("Loading Message 2");
}
}, 3*1000L);
EDIT:
To make all this stuff flexible, do the following:
// inner class
class TextChanger implements Runnable {
private final String message;
public TextChanger(String message) {
this.message = message;
}
#Override
public void run() {
loadingMessage1.append(message);
}
}
and then somewhere in your code:
public static final long TIME_CONSTANT = 3*1000L;
final TextView loadingMessage1 = (TextView)this.findViewById(R.id.loadingMessage1);
int count = 0;
final Handler handler = new Handler();
handler.postDelayed(new TextChanger("Whatever 1"), TIME_CONSTANT);
handler.postDelayed(new TextChanger("Whatever 2"), 2 * TIME_CONSTANT);
and so on. The trick is not to reference this as you did before, because it creates an infinite loop.
You need to avoid posting another event after each execution. Perhaps something more like this:
void showMessage1() {
// ... code to show message 1 ...
handler.postDelayed(new Runnable(){
#Override
public void run(){
showMessage2();
}
}, 3*1000L);
}
void showMessage2() {
// ... code to show message 2 ...
}
Note that message-showing code only executes once per message.
Related
One part of my activity needs two timers running at once, one of them using Handler and the other using CountDownTimer. The handler portion updates the display every second, while the CountDownTimer counts down to when this part of the code ends. For some reason, I cannot run these both at the same time, and even when I commented out the CountDownTimer portion, the handler portion only ran once, instead of repeating every second. I am at a loss for what to do here. Any ideas? The relevant part of the code is below. For some clarification, the first handler seen here is supposed to run on its own, until a condition is met, at which point it reruns the function and goes to the second if statement. Seen within the second if statement are the details I mentioned at the beginning.
private void statusCheck() {
if (possible = true) {
final Random random = new Random();
final Handler handler1 = new Handler();
final int delay1 = 1000; //milliseconds
handler1.postDelayed(new Runnable() {
public void run() {
runChance = random.nextInt(1000);
if (runChance < 100) {
possible = false;
statusCheck();
}
}
}, delay1);
}
if (possible = false) {
final Handler Handler = new Handler();
final int Delay = 1000; //milliseconds
Handler.postDelayed(new Runnable() {
public void run() {
// code to update every second
}
}, Delay);
new CountDownTimer(ghostDuration, 1000) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
//code to run when finished
}
}.start();
}
}
First of all it's not a good idea to to run timer and tasks under Android that way.
Android will block these timer and tasks because they work against the framework.
If you want to implement it correctly with a WorkManager watch out this video from Google which gives you some fundamentals: Android Jetpack WorkManager
I need that a button can run automatically every 1-2 seconds, and, when the if condition (that i have in the method which is used by the button) is fulfilled, this function must be stopped.
I've tried this but it wasn't what i wanted because with this code the button only runs one time:
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
Consulta.performClick();
}
}, 1000);
onClick of my button:
public void consultaBD(View view)
{
DB db = new DB(getApplicationContext(),null,null,1);
String buscar = text_view.getText().toString();
String[] datos;
datos=db.buscar_reg(buscar.trim());
db.infraccion(buscar.trim());
if(datos[2] =="Encontrado")
{
App.matricula=buscar;
startActivity(new Intent(getApplicationContext(), MatriculasActivity.class));
Toast.makeText(getApplicationContext(),datos[2],Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(getApplicationContext(),datos[2],Toast.LENGTH_SHORT).show();
}
}
Another method would be to use Timers to initiate the button click every x seconds. However, in this answer I'll stick with the method you're using. Your handler appears to be incorrect, try something like this instead:
Replace your handler with:
private Handler handler = new Handler();
private Runnable runnable = new Runnable() {
#Override
public void run() {
Consulta.performClick();
handler.postDelayed(this, 1000);
}
};
And initiate it with: (where 1000 is the time (in milliseconds) between each execution)
handler.postDelayed(runnable, 1000);
UPDATE:
You have also requested that the event is fired when the text inside of a textbox is changed. To do this, you need to create a new event listener (make sure you replace field1 with the actual reference to your textbox):
field1.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
/* Add the Handler Call here */
handler.postDelayed(runnable, 1000);
}
});
whatever context I understood, here is the raw code which may help you.
Handler handler = new Handler();
//initialize this method once by either clicking on button or as the activity starts
void checkAndPerformClick(boolean conditionFulfilled) {
if (conditionFulfilled) {
handler.removeCallbacksAndMessages(null);
return;
}
handler.postDelayed(new Runnable() {
#Override
public void run() {
Consulta.performClick();
checkAndPerformClick(datosEqualsEncontrado());
}
}, 1000);
}
boolean datosEqualsEncontrado() {
// apply your logic here as the name suggests
return false;
}
I need to delete a value from SharedPreferences after 5 minutes or when the user finished to do something . So when I add that value I start this:
Activity A
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
mySharedPreferences.removeValue(mContext, Utils.MY_VALUE);
}
}, Utils.TIME_BEFORE_DELETE);
and in the case users finished all I do this:
Activity B
mySharedPrefernces.removeValue(mContext, Utils.MY_VALUE);
But how can I stop the Handle into second activity?? Or is there another way to do it??
you can you boolean variable if you want to cancel this.
create public static boolean to check if the task is cancelled or not.
public static boolean isCanceled = false;
Use this in run() method
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
if (!isCanceled)
mySharedPreferences.removeValue(mContext, Utils.MY_VALUE);
}
}, Utils.TIME_BEFORE_DELETE);
if you want to cancel then set:
isCanceled = true;
Runnable run = new Runnable() {
#Override
public void run() {
mySharedPreferences.removeValue(mContext, Utils.MY_VALUE);
}
};
Handler handler = new Handler();
handler.postDelayed(run, Utils.TIME_BEFORE_DELETE);
//to dismiss pending runnable
handler.removeCallbacks(run);
A better way to do: Example code
publc static final Handler handler = new Handler();
public static final Runnable runnable = new Runnable() {
public void run() {
try {
Log.d("Runnable","Handler is working");
if(i == 5){ // just remove call backs
handler.removeCallbacks(this);
Log.d("Runnable","ok");
} else { // post again
i++;
handler.postDelayed(this, 5000);
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
//now somewhere in a method
b1.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
handler.removeCallbacks(runnable);
handler.postDelayed(runnable, 5000);
}
});
You can use handler.removeCallbacksAndMessages(null);. More information link
In this case you can use service with sticky flags. So you start service with intent "start_handler" and start handler also. When you need cancel handler you send the intent to stop handler and service. Or when time is passed and handler calls your code you should also stop service.
Using service with sticky flag provides possibility restoring handler. Also you need add some logic saving time when handler was run for correct restoring handler.
For that you can't use direct Runnable inside handler, you need to take one instance of it then you can do this like below,
Runnable myRunnable = new Runnable(){};
Then assign this in handler
handler.postDelayed(myRunnable);
And on no need use below line
handler.removeCallbacks(myRunnable);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
//add your code hare
finish();
}
}, 10000);
by using this way you can stop your runnable in a fix time
Hi im trying to do an app that searchs bluetooth devices that are near every 5-10 seconds, so I tried to do an endless loop but the app is getting stuck when I press the button that starts the loop:
int stopInt=2;
serachB.setOnClickListener(
new Button.OnClickListener() {
public void onClick(View v) {
do {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
listAdapter.clear();
getPairedDevices();
startDiscovery();
}
}, 4000);
} while (stopInt>1);
}
private final Handler mMyhandler = new Handler();
private final Runnable checkBluetoothRunnable = new Runnable() {
public void run() {
//Do your work here
mMyHandler.postDelayed(this, 5000);
}
};
serachB.setOnClickListener(
new Button.OnClickListener() {
public void onClick(View v){
mMyhandler.post(checkBluetoothRunnable);
}
}
}
Change it this way:
serachB.setOnClickListener(
new Button.OnClickListener() {
public void onClick(View v) {
final Handler handler = new Handler();
handler.post(new Runnable() {
#Override
public void run() {
while(true){
listAdapter.clear();
getPairedDevices();
startDiscovery();
Thread.sleep(4000);
}
}
});
}}
You are continually creating new instances of Handler in your while loop which is going to eat up memory. I wouldn't be surprised if you were getting an OutOfMemoryError which is causing the termination. Try creating a single instance outside of your loop.
The Runnable passed to Handler runs on the UIThread since it was created on that thread. This should be avoided for lengthy operations and instead delegated to another thread.
When you create a new Handler, it is bound to the thread / message
queue of the thread that is creating it
Also, rather than using the Handler class you could potentially swap it out to use ScheduledThreadPoolExecutor which will give you a pool of threads which can then periodically execute your device discovery code.
Firstly create a ScheduledExecutorService:
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
Create an instance of your Runnable:
MyRunnable deviceDiscovery = new MyRunnable();
Then in your onClick method you kick off with scheduleAtFixedRate:
ScheduledFuture<?> future = scheduledExecutorService.scheduleAtFixedRate(deviceDiscovery, 0, 1, TimeUnit.MINUTES);
Then when you want to stop it running you need to call cancel on the ScheduledFuture:
future.cancel(true); // Set to true to say it can interrupt if already running
I have a code like this:
time = 5;
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
#Override
public void run() {
if(time == 0)
time = 0;
else {
time --;
}
handler.postDelayed(this, 1000);
}
};
My application contains a button which needs to collect value of the 'time' but the problem is when I click the button, value of the 'time' is always 5 no matter when I click the button. I tested it and 'time' really decreases by one but I can't get that value.
How can I get real value of the 'time' variable after I click a button?
Create a thread for your handler to handle. Have the thread run in the background, but have it pass it's information back to your handler via a message bundle. Something like this
private class HandlerThread extends Thread{
private Handler handler;
public HandlerThread(Handler uiHandler){
handler = uiHandler;
}
public void run(){
int time = 5;
Bundle b;
for(int i = 0; i < time; i++){
b = new Bundle();
b.putInt("time_key", time);
Message message = handler.obtainMessage();
message.setData(b);
handler.postDelayed(this, 1000);
handler.sendMessage(message);
}
}
}
And then have your handler handle the message
final Handler handler = new Handler(){
public void handleMessage(Message msg){
Bundle b;
b = msg.getData();
mainUiTime = b.getInt("time_key",0))
}
};
You can start your background thread like this
HandlerThread handlerThread = new HandlerThread(handler);
handlerThread.start();
As a note, you will also need to figure out a way of canceling your thread once it is done running. This is usually done by creating a boolean variable, something like keepRunning, and put it in your run() method as a while loop; while(keepRunning). Then in your mainUi change the variable to false when you are out of buttons so that it essentially terminates the running portion of the thread.