Android Handler/Timer Request - android

So I have a question, and if it's a stupid one I do apologize up front, I have tried to search for it but not sure what to search for exactly. I am trying to run a delayed task, but only if my int = 0, would this work correctly like I am wanting it to?
public static void runTask(String p)
{
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run()
{
pendingRequest = pendingRequest - 1;
if (pendingRequest == 0)
{
context.startActivity(p);
}
}
}, 4000);
}
}
What I want it to do is only run if pendingRequest is 0, but I have other activities that add to pending request after the runTask() is called. If this doesn't make any sense please let me know and I will try to reword it.

This is a bit of an obscure way to do things so seeing just this snippet I cant tell exactly what the desired behavior is, however, it should work if you make the parameter "p" final. Im also not familiar with a startActivity method that takes a string instead of an intent, but I cant tell if "context" is actually an Android Context object, but I'm assuming it is.
What I'm not sure about is why you would wait 4 seconds BEFORE decrementing pendingRequest. I would think you want to decrement, allow 4 seconds for someone else to add a pending request, and if it's still 0 after the wait start the Activity... but, again, I cant tell from the snippet.

Try this:
private static Object requestLock = new Object();
public static void runTask(final String p)
{
synchronized(requestLock)
{
if (--pendingRequest > 0) // Decrement first
{
// There are more requests
return;
}
}
// Wait 4 sec and if there are still no requests start the activity.
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run()
{
synchronized(requestLock)
{
if (pendingRequest == 0)
{
context.startActivity(p);
}
}
}
}, 4000);
}
}
Note: You will also need to add a synchronized block where you increment the pendingRequests.

Related

What is the correct way to use Handler and Runnable?

I am developing an Android application and I want to call a function every 40ms. To do so, I implemented a Handler and a Runnable. I chose this two objects thanks to the post How to run a method every X seconds. But I am not sure this is the right way to perform what I am doing :
In my application, I am playing a video, I want to "launch" the Handler when starting the video, "put it on hold" when pausing the video, starting it again when resuming the video and so on.
So far, I am using mHandler.removeCallbacks(mRunnable); to detain it. But to start it or resume it, I don't know if I should use mHandler.post(mRunnable); mHandler.postDelay(mRunnable, DELAY) or mRunnable.run();. I succeed making them all work but the behaviour is never as expected...
Here is the code I use to set up the Handler...
public void setUpdatePositionHandler() {
mHandler = new Handler();
mRunnable = new Runnable() {
#Override
public void run() {
if (mVideoView.getCurrentPosition() > mVideoView.getDuration()) {
if (mVideoView.getCurrentPosition() > 1000) {
mVideoView.seekTo(1); // go back to beginning
mVideoView.pause();
mPlayButton.setVisibility(View.VISIBLE);
mStampIndex = 0;
mLastPosition = 0;
Log.i(TAG, "removeCallbacks() from runnable");
mHandler.removeCallbacks(this);
} else {
//mHandler.postDelayed(this, DELAY);
}
} else {
if (!mStamps.isEmpty()) {
onPositionUpdate(mStamps);
}
mHandler.postDelayed(this, DELAY);
}
}
};
Note that I don't feel really sure of what I implemented so far, and that any ressources that would help me understand better would be welcome :) (I already read the documentations of the 2 classes and read several documents or posts on the subjects, but I think I am missing something.)
Thank you for your help
Is it the correct way ?
if it will not produce any problem and it meets your requirements then yes
but your question should be is it the best practice?
i prefer to write it like the following
public void setUpdatePositionHandler() {
mHandler = new Handler();
mRunnable = new Runnable() {
#Override
public void run() {
if (mVideoView.getCurrentPosition() > mVideoView.getDuration()) {
if (mVideoView.getCurrentPosition() > 1000) {
mVideoView.seekTo(1); // go back to beginning
mVideoView.pause();
mPlayButton.setVisibility(View.VISIBLE);
mStampIndex = 0;
mLastPosition = 0;
Log.i(TAG, "removeCallbacks() from runnable");
mHandler.removeCallbacks(this);
} else {
//mHandler.postDelayed(this, DELAY);
}
} else {
if (!mStamps.isEmpty()) {
onPositionUpdate(mStamps);
}
}
}
mHandler.postDelayed(mRunnable, DELAY);
};
be noted the above code will work only once expect if you make CountDownTimer or you can use Thread.sleep() with a normal loop and AsyncTask in order to not block your code because if so the application will not be responding and then your app will be crached

runOnUiThread() no executing when using Thread.sleep()

I'm using code that looks like this :
_thread = new Thread(){
#Override
public void run() {
try {
while (true) {
operate();
Thread.sleep(DELAY);
}
} catch (InterruptedException e) {
// Doesn't matters...
}
}
};
operate function looks like this :
// does things....
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
// adds an ImageView to the screen
}
});
// does other things...
At the bottom line, what i wanted to achieve is an operation that happens once in a while, without interrupting the main thread and the UI, something like a game-loop.
In the first 2 times that operate() runs, it adds the ImageView and everything is alright, but after 2 or 3 times it stops adding the ImageViews, but the UI is still running as usual. When i debugged the problem, i found out that after 3 times the run() method of the Runnable isn't called anymore, even thought the operate function was called.
The wired thing (for me) was that when i removed the Thread.sleep, everything worked fine (much faster of course...). I tried to replace it with a very long for loop (just for checking) and it worked, but of course it is not an appropriate solution to the problem.
I read about the problem, most of the people that asked this question did a thread.sleep or an infinite loop on the main thread, but, as i see it, i didn't do such thing. Many people wrote that you should replace the Thread.sleep with Handler.postDelayed. I tried to do it but it didn't work, maybe I did it wrong. I even tried replacing the runOnUiThread with other options I found on the internet, but all of them gave me the same exact results. I tried to replace the method that I'm adding the view to the activity, but all of them, again, gave the same result.
The waiting is crucial for this application. I got to find a way to wait sometime and then execute a function on the UI thread, cause this pattern returns at least a couple of times in my application.
It sounds like you want a post delay so that you can do the code on the UI thread after some delay. Handler Post Delay.
private static final int DELAY = 500;
private Handler mHandler;
private Runnable mRunnable;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
start();
}
private void start()
{
mHandler = new Handler();
mRunnable = new MyRunnable(this);
mHandler.postDelayed(mRunnable, DELAY);
}
private void stop()
{
mHandler.removeCallbacks(mRunnable);
}
private void doSomething()
{
// Do your stuff here.
// Reschedule.
mHandler.postDelayed(mRunnable, DELAY);
}
Recommended way of creating a Runnable.
private static class MyRunnable implements Runnable
{
private WeakReference<MainActivity> mRef;
// In here you can pass any object that you need.
MyRunnable(MainActivity activity)
{
mRef = new WeakReference<MainActivity>(activity);
}
#Override
public void run()
{
// Safety check to avoid leaking.
MainActivity activity = mRef.get();
if(activity == null)
{
return;
}
// Do something here.
activity.doSomething();
}
}
There could be several reasons why the UI Runnable isn't being executed. Probably the activity variable has something messed up with it or it's referencing the context incorrectly, or as you said the Thread.sleep() could be causing an issue. At this point more parts of the code needs to viewed to better solve the problem.
A better way of implementing your logic is to use a scheduled Timer instead of using an infinite loop with a Thread.sleep() in it. It will execute the code within a background thread. And then use a Handler to update the UI instead of activity.runOnUiThread(). Here's an example:
// Global variable within the activity
private Handler handler;
// Activity's onCreate()
#Override
protected void onCreate(Bundle savedInstanceState) {
handler = new Handler(getMainLooper());
Timer timer = new Timer("ScheduledTask");
// Timer must be started on the Main UI thread as such.
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
operate();
}
}, 0L, DELAY);
}
private void operate() {
// does things in background....
handler.post(new Runnable() {
#Override
public void run() {
// adds an ImageView to the screen from within the Main UI thread
}
});
// does other things in the background...
}

How can I reset the time of a postDelayed runnable in onClick?

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.

Android Creating a variable that increments once per second

In Java for Android, I want to create a variable that increases by 1 every second, in other words, it counts, that way I can check to see if a function has been called in the past 3 seconds, and if not, I want it to do something different than if it had been.
Is there any built-in way to do this? I'm familiar with the Timer class, but it doesn't seem to work the way I would want it to.. is there anything else?
tl;dr: I want to create a variable that increases by 1 every second, so I can use it to treat a function differently based on how long it has been since its last call. Is there an easy way to do this? If not, what is the hard way to do this?
Why not store the last time the method was called instead, then check it against the current time?
private long timeLastCalled;
public void someMethod() {
timeLastCalled = SystemClock.elapsedRealTime();
}
public boolean someMethodCalledRecently() {
return (SystemClock.elapsedRealTime() - timeLastCalled) > 3000;
}
final int[] yourVariable = new int[1];
yourVariable[0] = 0;
updateVariableTimer = new CountDownTimer(howLongYouWantTimerToLast, 1000) {
#Override
public void onTick(long l) {
yourVariable[0] += 1;
}
}.start();
Or Alternatively to do it with a flag instead of keeping track of variable counting:
final boolean functionCalledRecently = false;
hasFunctionBeenCalledRecentlyTimer = new CountDownTimer(3000, 1000) {
#Override
public void onTick(long l) {
functionCalledRecently = true;
}
#Override
public void onFinish() {
functionCalledRecently = false;
}
}.start();
If you just need to see if the method has been called within the last 3 seconds you can use a Handler and a Boolean flag to acomplish this.
private Handler mHandler = new Handler();
private boolean wasRun = false;
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
if(wasRun){
//whatever you want to do if run
}
mHandler.postDelayed(this, 3000);
}
},3000); //3 sec
In this example the Handler will run on a 3 second delay. Each time it runs it will check to see if the other method was perviously called by evaluating if(wasRun). This way you can change what happens if the method was/was not called. The handler will then start iself again on another 3 second delay. All you have to do then is update the wasRun flag to be true if your method was called, or false if it was not. .

Avoid loop causing overload

I am developing an android game where I have a loop (not a game loop). This loop reacts if one of my booleans is changed. The problem is that when the boolean is changed, it calls the void inside the loop untill the app crashes of an overload. The void I am calling is suronded with a try-catch and it has to be, unless I have to remake the rest of my game. The code for the loop is like so:
private void listenerVoid(){
int timeBetweenChecks = 100;
final Handler h = new Handler();
h.postDelayed(new Runnable(){
public void run(){
//Do something if myBool returns true, otherwise loop again
if (myBool==false){
listenerVoid();
} else {
//Check if the listener has reacted to a change before
if(firstStart!=false){
firstStart = false;
theTryCatchVoid();
Log.i("MyClass","Boolean is changed");
}
else{
//Already started
Log.i("MyClass","Already started");
}
}
}
}, timeBetweenChecks);
};
And my try-catch void is similar to this:
private void tryCatchVoid(){
try{
//Try to do something that soemtimes causes a crash
}
catch(Exception e){
//Do nothing
}
}
I can not increase the timeBetweenChecks time, because it will then cause a long waiting time in my game. How can I make the tryCatchVoid only be called once?

Categories

Resources