How to use Handler Postdelayed in queue? - java

I have a situation, I created a button and a function like this.
...
public void BtnOnClick(View view) {
displayMsg();
}
...
private void displayMsg(){
handler.postDelayed(new Runnable() {
#Override
public void run() {
Toast.makeText(this, "TestQueue", Toast.LENGTH_SHORT).show();
}
}, 3000);
}
...
If I click the button once a Toast should appear after a 3 seconds delay.
But if I quickly click the button two or more times then all the Toasts appear at the same time after 3 seconds without delay of 3 seconds between every Toast it's not good. I want a 3 seconds gap/delay between every Toast appearance despite of simultaneous clicks.
Is there any solution?
If there are multiple handlers in a queue then each handler delayed time start after the previous handler delay time end.

You can queue the requests to make sure the toasts are displayed at an interval.
ArrayList<Runnable> requests = new ArrayList<>;
bool inProgress = false;
private void displayMsg(){
Runnable runnable = new Runnable() {
#Override
public void run() {
Toast.makeText(this, "TestQueue", Toast.LENGTH_SHORT).show();
inProgress = false;
if (requests.size() > 0) {
handler.postDelayed(requests.remove(0), 3000 + Toast.LENGTH_SHORT);
}
}
}
if (!inProgress) {
inProgress = true;
handler.postDelayed(runnable, 3000);
} else {
requests.add(runnable);
}
}

Try this:
private final Handler handler = new Handler() {
final int DELAY = 3000;
final int DELAY_MSG = 1;
final Queue<Runnable> pendingRunnables = new ArrayDeque<>();
#Override
public void dispatchMessage(Message msg) {
if (msg.what == DELAY_MSG) {
final Runnable r = pendingRunnables.poll();
if (r != null) {
r.run();
sendEmptyMessageDelayed(DELAY_MSG, DELAY);
}
} else {
pendingRunnables.add(msg.getCallback());
if (!hasMessages(DELAY_MSG)) {
sendEmptyMessage(DELAY_MSG);
}
}
}
};
...
// post action
handler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(this, "TestQueue", Toast.LENGTH_SHORT).show();
}
});

Maybe you can use postAtTime:
AtomicLong previous = new AtomicLong(System.currentTimeMillis());
private void displayMsg(){
handler.postAtTime(new Runnable() {
#Override
public void run() {
Toast.makeText(this, "TestQueue", Toast.LENGTH_SHORT).show();
}
}, previous.updateAndGet(operand -> Long.max(operand + 3000, System.currentTimeMillis() + 3000)));
}

Related

Why is there no delay on Handler?

I have created a handler for an alert that should activate for 4 seconds, stops for 4 seconds, and activates again. When i put it in the if statement, it doesn't work; the alert keeps playing, stops for less than a second and continues activating again without the delay. Wonder if anyone knows why is it happening and what should i do to correct it. Thank you.
private Handler handler2 = new Handler();
private Runnable startalert = new Runnable() {
#Override
public void run() {
alert2.start();
handler2.postDelayed(this, 4000);
}
};
#Override
public void onLocationChanged(Location location) {
if (location == null) {
speedo.setText("-.- km/h");
}
else {
currentSpeed = location.getSpeed() * 1.85f; //Knots to kmh conversion.
speedo.setText(Math.round(currentSpeed) + " km/h");
}
if (currentSpeed <=4.99) {
background.setBackgroundColor(Color.GREEN);
handler2.removeCallbacks(startalert);
} else if(currentSpeed >=5.00 && currentSpeed <=9.99) {
background.setBackgroundColor(Color.YELLOW);
handler2.removeCallbacks(startalert);
} else if(currentSpeed >=10.00) {
background.setBackgroundColor(Color.RED);
startalert.run();
}
}
Instead of 'this', use runnable object.
private Runnable startalert = new Runnable() {
#Override
public void run() {
alert2.start();
handler2.postDelayed(startalert, 4000);
}
};
Another method:
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//Do something after 100ms
alert2.start();
handler.postDelayed(this, 4000);
}
}, 4000);

countdown timer begin first tick after 3 seconds

I have a count down timer that must run for 30 seconds with a tick interval of 3 seconds.
But it seems the first tick happens as soon as the timer starts. I want the first tick to happen after 3 seconds.
And the next tick every 3 seconds. How can I do this?
Here is my code -
if (!timerRunning && timer == null) {
timer = new CountDownTimer(300000, 3000) {
#Override
public void onTick(long l) {
timerRunning = true;
Log.e(TAG,"Tick every 3 seconds");
}
#Override
public void onFinish() {
timerRunning = false;
}
}.start();
}
One possible solution is using a handler like below:
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//Do something after 3000ms
}
}, 3000);
So this code can help you:
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
if (!timerRunning && timer == null) {
timer = new CountDownTimer(300000, 3000) {
#Override
public void onTick(long l) {
timerRunning = true;
Log.e(TAG,"Tick every 3 seconds");
}
#Override
public void onFinish() {
timerRunning = false;
}
}.start();
}
}
}, 3000);

Execute function after 5 seconds in Android

I am new in android development and now my launcher activity show only 5 seconds and after that I want to check the user is logged in or not function and perform the actions.
here is my code.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
exactPreferences = getSharedPreferences("ExactPreference",MODE_PRIVATE);
setContentView(R.layout.activity_landing_page);
session = exactPreferences.getString(Model.getSingleton().SHARED_SESSION_ID,null);
Log.i("Session Id",session);
displayData(); // I want to perform this function after 5 seconds.
}
private void displayData() {
if(session.equals("")){
Intent loginIntent = new Intent(LandingPage.this,
LoginActivity.class);
startActivity(loginIntent);
Log.i("User Logged In", "False");
}
else
{
Intent objIntent = new Intent(LandingPage.this,
IndexPageActivity.class);
startActivity(objIntent);
Log.i("User Logged In", "True");
}
}
You can use the Handler to add some delay.Call the method displayData() as below so that it will be executed after 5 seconds.
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
displayData();
}
}, 5000);
Note : Do not use the threads like Thread.sleep(5000); because it will block your UI and and makes it irresponsive.
Assign millisDelayTime variable with the milliseconds you desire to cause a delay. mActivity is an object of Activity for providing Application Context. In your case millisDelayTime should be initialized with 5000
mActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//your code here
}
}, millisDelayTime);
}
});
Use a CountDownTimer
// There's a TextView txtCount in Main Activity
final int secs = 5;
new CountDownTimer((secs +1) * 1000, 1000) // Wait 5 secs, tick every 1 sec
{
#Override
public final void onTick(final long millisUntilFinished)
{
txtCount.setText("" + (int) (millisUntilFinished * .001f));
}
#Override
public final void onFinish()
{
txtCount.setText("GO!");
finish();
// Time's up - Start the Login Activity
final Intent tnt =
new Intent(getApplicationContext(), LoginActivity.class);
startActivity(tnt);
}
}.start();
Since, Handler is now deprecated so use this code :
new Handler(Looper.myLooper()).postDelayed(new Runnable() {
#Override
public void run() {
//do what you want
}
}, 5000);
Try this, code create CountDownTimer with one tick
timer = new CountDownTimer(5000, 5000)
{
public void onTick(long millisUntilFinished)
{
}
public void onFinish()
{
displayData();
}
};
timer.start();
long delay = 1000;
long period = 50000;
Timer task = new Timer();
task.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
getDriver(sessionManager.getKEY(), ride_id);
}
}, delay, period);
For kotlin way
Handler().postDelayed({
//do something
}, 5000)
When possible, try to avoid using postDelayed. It is a bad practice, since it can lose the reference to the objects that you want to draw on your screen and cause a NPE. Use a Handler instead. First of all, create a global variable Handler in which you will have to "handle" the logic for your code. Do so by using the function handleMessage.
Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
if(msg.what == 1){
// your code here
}
}
};
Then, wherever you want to execute it, just call the function:
// 1 is the ID of your process
handler.sendEmptyMessageDelayed(1, 5000);
Please remember that in the onDestroyView method (in a Fragment) or the onDestroy (in an Activity) you will have to call
handler.removeMessages(1)
The best option to achieve this is using a Handler:
int TIME = 5000; //5000 ms (5 Seconds)
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
function(); //call function!
}
}, TIME);

Handler with ProgressBar

Im am trying to create a delayed action, when I touch the Display for more than 5 Seonds.
I am using a Handler and a Runnable for this, using handler.postDelayed(runnable, 5000);
I also want a ProgressBar, to show, when the Handler will kickoff. From researching i found, that i have to Override the handleMessage() method.. this is what i tried.
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
progress.setProgress(progress.getProgress() + 100);
sendEmptyMessageDelayed(0, 100);
}
};
private Runnable runnable = new Runnable() {
public void run() {
playAlarm();
}
};
...
progress = (ProgressBar) findViewById(R.id.progressBar1);
...
#Override
public boolean onTouchEvent(MotionEvent e) {
if (e.getAction() == MotionEvent.ACTION_DOWN) {
// Execute Runnable after 5000 milliseconds = 5 seconds.
progress.setProgress(0);
handler.postDelayed(runnable, 5000);
mBooleanIsPressed = true;
}
if (e.getAction() == MotionEvent.ACTION_UP) {
if (mBooleanIsPressed) {
mBooleanIsPressed = false;
progress.setProgress(0);
handler.removeCallbacks(runnable);
}
}
return true;
}
It is not crashing. But the ProgressBar is simply not showing anything.
if you want to use a handler there some things missing, this should work (not tested):
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
progress.setProgress(progress.getProgress() + 100);
if (mBooleanIsPressed)
sendEmptyMessageDelayed(0, 100);
}
};
private Runnable runnable = new Runnable() {
public void run() {
playAlarm();
}
};
...
progress = (ProgressBar) findViewById(R.id.progressBar1);
...
#Override
public boolean onTouchEvent(MotionEvent e) {
// only start your handler if the view isn't touched
if (e.getAction() == MotionEvent.ACTION_DOWN && !mBooleanIsPressed) {
// Execute Runnable after 5000 milliseconds = 5 seconds.
progress.setProgress(0);
handler.postDelayed(runnable, 5000);
// send the first empty message, which will be handled...
sendEmptyMessageDelayed(0, 100);
mBooleanIsPressed = true;
}
if (e.getAction() == MotionEvent.ACTION_UP) {
if (mBooleanIsPressed) {
mBooleanIsPressed = false;
progress.setProgress(0);
handler.removeCallbacks(runnable);
}
}
return true;
}
feel free to ask if you have any questions

How to stop code from running (with timer on ) until a button presses

Is there a way I can do this without having to create new timers and tasks? My code basically scans for wifi signals every 10 seconds. To ensure that the scan returns new results, I used another support class. Can someone verify that there aren't any obvious errors with this as well?
//Inside Button to start scanning
final int DELAY = 10000;
final Handler handler = new Handler();
chkScan.setOnClickListener(new View.OnClickListener() {
final Handler handler = new Handler();
ReceiverWifi = new WifiReceiver();
WIFI_Manager = new wifiScanner();
registerReceiver(receiverWifi, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
final Timer timer = new Timer();
final TimerTask task = new TimerTask() {
public void run() {
handler.post(new Runnable() {
public void run() {
mainWifi.startScan();
if ((WIFI_Manager.resultsAvailable())) {
processResults();
}
// to ensure results come from latest scan
// say there are no new results as of now
WIFI_Manager.waitForNextScan();
}
}
);
timer.schedule(task, 0, DELAY);
}
}
});
}
public void processResults() {
results = mainWifi.getScanResults();
WIFI_Manager.pause() //stop getting wifi results
//continue to process here
//
//
//I wish to put a button here, but and wait for user input before continuing
//but scans continue..
chkLabel.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
}
//more code
// ...
WIFI_Manager.resume();
}
class WifiReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context c, Intent intent) {
WIFI_Manager.getNewResults();
}
}
public class wifiScanner {
public wifiScanner() {
Pause = false;
new_results = false;
}
public boolean resultsAvailable() {
return new_results;
}
public void waitForNextScan() {
new_results = false;
}
public void getNewResults() {
new_results = true;
}
public boolean onPause() {
return Pause;
}
public void pause() {
unregisterReceiver(receiverWifi);
Pause = true;
}
public void resume() {
registerReceiver(receiverWifi, new IntentFilter(
WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
Pause = false;
}
// pause: false- access to scan results are allowed
// pause: true- cannot access scan results
private boolean Pause;
// new_results: false- no new WIFI_resuls
// new_results: true - there are new results to be processed
private boolean new_results;
}
Instead of using a Timer, create a boolean field named stop, and use a while(!stop) loop with Thread.sleep(1000) at the end of an iteration. Your processResults() method will do stop = true; and in your restart button's listener do a stop=false;
But I think it's dirtier than use a Timer ;)

Categories

Resources