Android handler not repeating - android

I'm trying to use "handler" to repeat a function (really trying to learn how to use it), but the function is only executed once.
public Runnable runnableCode = new Runnable() {
#Override
public void run() {
if (changeColor) {
myPaint.setColor(Color.BLUE);
Rect r = new Rect(0, 0, widthInPixels * 90, heightInPixels * 90);
myCanvas.drawRect(r, myPaint);
changeColor = false;
} else {
myPaint.setColor(Color.RED);
Rect r = new Rect(0, 0, widthInPixels * 90, heightInPixels * 90);
myCanvas.drawRect(r, myPaint);
changeColor = true;
}
handler.postDelayed(runnableCode, 1000);
}
};
public void play (View view) {
handler.post(runnableCode);
}

You should loop through your handler to repeat itself. But you are just calling it once.
Try this code below:
final Handler handler = new Handler();
int count = 0; //keep track of count
final Runnable runnable = new Runnable() {
public void run() {
if (count++ < 5) { //how many times do you want to repeat?
handler.postDelayed(this, 5000); //repeat handler
}
}
};
//initial trigger
handler.post(runnable);
Let me know if you have any questions. Thanks.

Ensure that your bool changeColor is being modified by making it a final one element array
Try code below:
final Handler handler = new Handler();
final boolean[] changeColor = {false};
Runnable runnableCode = new Runnable() {
#Override
public void run() {
if (changeColor[0]) {
// code here
changeColor[0] = false;
} else {
// other code here
changeColor[0] = true;
}
messageHandler.postDelayed(this, 1000);
}
};
handler.post(runnableCode);

I tried adding a "toast", and that does get repeated; the problem's the drawing for some reason.

I tried firing the function from a button, and it looks like the repetitions accumulate and then fire all at once when I hit the button again.

Still fighting with this. I've also tried a timer, thread.sleep and ScheduledThreadPoolExecutor, and nothing.

Related

Breaking For loop with Handler()

How can I break the for() loop when 1 validation has return true.
public void printOut (){
final Handler handler = new Handler();
for (final int[] x = {0}; x[0] < Integer.parseInt(spinner.getSelectedItem.toString()); x[0]++) {
handler.postDelayed(new Runnable() {
#Override
public void run() {
//printer for my device
int query = PrinterInterface.queryStatus();
if (query == 1){
// return true
//printing goes here..
}else{
// returns false
x[0] = Integer.parseInt(spinner.getSelectedItem.toString());
}
}
},2000 * x[0]);
}
}
This is my code ATM, If the query value returns not equal to 1, It will go on the else statement and making the variable x[0] to be equal on the Spinner. But the problem is it is still looping. How can I make it stop? Thanks!
UPDATE
I find the problem. its on }, 2000 * loopVariable[0]); how can I interrupt this part?. or stop the Handler()
You have to make var for handle canceled status
For example, by your code.
public void printOut (){
final Handler handler = new Handler();
boolean isCanceled = false
for (final int[] x = {0}; (x[0] < Integer.parseInt(spinner.getSelectedItem.toString()) && !isCanceled); x[0]++) {
handler.postDelayed(new Runnable() {
#Override
public void run() {
//printer for my device
int query = PrinterInterface.queryStatus();
if (query == 1){
isCanceled = true
// return true
//printing goes here..
}else{
// returns false
x[0] = Integer.parseInt(spinner.getSelectedItem.toString());
}
}
},2000 * x[0]);
}
And, if you want to handle result, you need to add callback.
But, I don't understand, why you use poseDelayed, in for you are start all handlers.
Better, If you check query, after that execute logic into Handler
I don't know why you using handler inside for, if your printing code required background processing and update the UI try using AsyncTask, it have doInBackground, onProgressUpdate and onPostExecute so you can handle your code more efficient.
I fix it!. The solution is just one line codes -_- and I also add an variable for Runnable. Thank you for helping especially pskink.
public void printOut (){
final Handler handler = new Handler();
for (final int[] x = {0}; x[0] < Integer.parseInt(spinner.getSelectedItem.toString()); x[0]++) {
handler.postDelayed(new Runnable() {
#Override
public void run() {
//printer for my device
int query = PrinterInterface.queryStatus();
if (query == 1){
// return true
//printing goes here..
}else{
// returns false
x[0] = Integer.parseInt(spinner.getSelectedItem.toString());
handler.removeCallbacksAndMessages(null);
}
}
},2000 * x[0]);
}

Android: Playing MIDI Notes Using Handler and Scrolling RecyclerView Accordingly

I am playing MIDI notes using this library as follows:
handler.postDelayed(new Runnable() {
ShortMessage message;
#Override
public void run() {
{
MidiEvent event = midiEvents.get(index[0]);
if (index[0] < midiEvents.size() - 1) {
delta = midiEvents.get(index[0] + 1).getDelta();
time[0] = timeFactor * midiEvents.get(index[0] + 1).getDelta();
mTotalMidiTime += time[0];
int noteValue;
int NOTE_STATUS;
if (event instanceof NoteOn) {
noteValue = ((NoteOn) event).getNoteValue();
NOTE_STATUS = NOTE_ON;
if (index[0] != 0) {
if (delta != 0) {
Intent intent = new Intent();
intent.setAction(Constants.SCROLL_RECYCLERVIEW);
localBroadcastManager.sendBroadcast(intent);
}
}
} else {
noteValue = ((NoteOff) event).getNoteValue();
NOTE_STATUS = NOTE_OFF;
}
try {
message = new ShortMessage(NOTE_STATUS, 2, noteValue,
127);
} catch (Exception e) {
e.printStackTrace();
}
Intent intent = new Intent();
intent.setAction(Constants.ACTION_SEEK);
localBroadcastManager.sendBroadcast(intent);
if (message != null)
recv.send(message, -1);
index[0]++;
} else {
index[0] = 0;
time[0] = 1;
mTotalMidiTime = mMinimumTime;
delta = 0;
}
handler.postDelayed(this, time[0]);
}
}
}, 0);
With each NoteOn event I am smooth scrolling a RecyclerView and updating a Seekbar using a LocalBroadcastManager
My problem is that playback is fine when UI operations are not performed but playback and UI get completely out of sync as soon as multiple MIDI notes (chords) are played in very quick succession. It would be appreciated if any performance improvements are suggested for the same. I have already tried performing the UI operations in runOnUiThread and also launching a new Handler for UI operations.
My BroadcastReceiver is as follows:
BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String actionType = intent.getAction();
switch (actionType) {
case Constants.SCROLL_RECYCLERVIEW:
Handler handler = new Handler();
handler.post(new Runnable() {
#Override
public void run() {
mNotesRecycler.smoothScrollBy(pixels, 0);
}
});
break;
case Constants.ACTION_SEEK:
Handler seekHandler = new Handler();
seekHandler.post(new Runnable() {
#Override
public void run() {
mPinchSeekBar.setSelectedCentreValue(mTotalMidiTime);
mCurrentTime.setText(timeInMinutes((int) mTotalMidiTime));
}
});
break;
}
}
};
Besides the optimizations you can do, I think the problem itself is RecyclerView's smoothScroll is more a method you call sometimes to do a fancy scroll rather than bomb it with requests that cause it to constantly recompute the running animation.
One thing you can try is to write yourself a simple scroll handler that calls mRecyclerView.scrollTo() that does the scroll without animation but I guess it's going to be more reliable.
Try something like this
Handler mHandler = new Handler();
int mPosition, mTargetPosition;
#IntRange(from = 20, to = 100)
final int INTERVAL = 50; // try with 50 ms or a little lower
Runnable mTimerScroll = new Runnable() {
public void run() {
if (mPosition != mTargetPosition) {
if (mPosition < mTargetPosition) {
mPosition += mDelta;
if (mPosition > mTargetPosition) mPosition = mTargetPosition;
}
if (mPosition > mTargetPosition) {
mPosition -= mDelta;
if (mPosition < mTargetPosition) mPosition = mTargetPosition;
}
mRecyclerView.scrollTo(mPosition, 0);
}
// repeat every 50ms
mTimerScroll.post(mRunnable, INTERVAL);
}
}
And then you start it
void startTimer() {
stop(); // prevent double start
mHandler.post(mTimerScroll);
}
void stopTimer() {
mHandler.removeCallbacks(mTimerScroll);
}
void scroll(int target) {
mTargetPosition = target;
}
void scrollBy(int pixels) {
scroll(mPosition + pixels);
}
I don't know the specifics of your app but it might work.
About optimization, you are using a lot of stuff there that can or cannot be necessary depending on the specifics of your library, etc, but if there are no different threads or services involved you could avoid the LocalBroadcast thing and all the handler.post() as everything is already on the UI thread (handler.post just posts a runnable to the thread where the handler was created, that in your case is the UI thread, so it doesn't do anything)

Why doesn't this update the screen after it is fired?

I am scheduling a simple task that should update a text field in 4 seconds.
However everytime this is called the activity pauses and does not show the value in the text field until I restart the activity.
private void showDelayedValue() {
Runnable longRunningTask = new Runnable() {
public void run() {
int randomVal = randomNumberGenerator.nextInt(30 - -10) - 10; //random number between -10 and 30
String randomValStr = Integer.toString(randomVal);
Log.i(this.getClass().getSimpleName(),
"FIRED startScheduler: " + randomValStr);
theFieldOnScreenTV.setText(randomTempStr);
}
};
//show the value in 2 seconds
scheduledTaskExecutor.schedule(longRunningTask, 4, TimeUnit.SECONDS);
}
The log shows:
FIRED startScheduler: 4
but does not update the TextView theFieldOnScreenTV
Instead onPause is called right after Fired startScheduler: is displayed in LogCat.
Many thanks!
EDIT:
This worked for me following Alex' approach:
private void showDelayedValue() {
int randomX = randomNumberGenerator.nextInt(30 - -10) - 10;
final String randomXStr = Integer.toString(randomX);
final Runnable updateFieldR = new Runnable() {
public void run() {
theFieldOnScreenTV.setText(randomXStr);
}
};
Runnable longRunningTask = new Runnable() {
public void run() {
theFieldOnScreenTV.post(updateFieldR);
}
};
scheduledTaskExecutor.schedule(longRunningTask, 4, TimeUnit.SECONDS);
}
instead of
theFieldOnScreenTV.setText(randomTempStr);
try
theFieldOnScreenTV.post(new Runnable() { theFieldOnScreenTV.setText(randomTempStr); } );
Have a try using Handlers.
Handler handler = new Handler();
handler.post(new Runnable() {
#Override
public void run() {
theFieldOnScreenTV.setText(randomTempStr);
}
});

Android: Time delay in a loop with updating UI

What I'm trying to create is a simple progress bar, that would load for ~10 sec.
So what I want is a for loop like this:
for(int i = 1; i <= 100; i++) {
progressDialog.setProgress(i);
//100ms delay
}
Thanks
You can use Async Task for the purpose
in preExecute() method initialize loop index to 0;
in background process sleep thread for 10 seconds, and then call sendUpdate method to send progress
in postExecute update progress bar to progress get in parameter.
The following code may be helpful for you.
public void startProgress(View view) {
// Do something long
Runnable runnable = new Runnable() {
#Override
public void run() {
for (int i = 0; i <= 10; i++) {
final int value = i;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.post(new Runnable() {
#Override
public void run() {
progressDialog.setProgress(value);
}
});
}
}
};
new Thread(runnable).start();
}
A shorter solution without explicitly creating a new Thread would look like this:
final Handler handler = new Handler(Looper.getMainLooper());
final int sleepMs = 100;
for (int i = 1; i <= 100; ++i) {
handler.postDelayed(() -> progressDialog.setProgress(value), i * sleepMs);
}

android brackets problem

hi to all can any one help me with this problem i have brackets problem there is 1 that is either extra or missing cant find it
thank you
Handler speedHandler = new Handler();
Runnable unitspeedtimer = new Runnable() {
public void run() {
speedTextView=(TextView)findViewById(R.id.speedTextView);
MaxspeedTextView=(TextView)findViewById(R.id.MaxspeedTextView);
//1 m/s = 3.6 km/h
float MySpeed = location.getSpeed() * 3.6;
float MaxSpeed = 75.00;
Timer updateTimer = new Timer("velocityUpdate");
updateTimer.scheduleAtFixedRate(new TimerTask() {
public void run() {
updateGUI();
}
}, 0, 3000);
}
You need one more }; at the end to close the Runnable. Consistent indentation would really help here.
Handler speedHandler = new Handler();
Runnable unitspeedtimer = new Runnable() {
public void run() {
speedTextView=(TextView)findViewById(R.id.speedTextView);
MaxspeedTextView=(TextView)findViewById(R.id.MaxspeedTextView);
//1 m/s = 3.6 km/h
float MySpeed = location.getSpeed() * 3.6;
float MaxSpeed = 75.00;
Timer updateTimer = new Timer("velocityUpdate");
updateTimer.scheduleAtFixedRate(new TimerTask() {
public void run() {
updateGUI();
}
}, 0, 3000);
}
};

Categories

Resources