How to run repetitive task in Handler Thread? - android

How to repeat same task in Handler Thread in specified time delay and update the view in Main thread also.
I need to run this code in background thread repetitively in a interval of 30 seconds and update the result in Main thread as this will block the UI thread if executed here.
final Handler handler = new Handler();
handler.post(new Runnable() {
#Override
public void run() {
int hours = mSeconds/3600;
int mins = (mSeconds%3600)/60;
int secs = mSeconds%60;
String timeElapsed = "";
if (hours>0){
timeElapsed = String.format("%02d:%02d",hours,mins);
}else{
timeElapsed = String.format("%02d:%02d",mins,secs);
}
// there are some other networking stuff also which will be executed here
if(mRunning){
mSeconds++;
}
// update the view as well
handler.postDelayed(this, 3000);
}
});

When you want it to execute.
mToastRunnable.run()
Fucntion
private val mToastRunnable = object : Runnable {
override fun run() {
Handler().postDelayed({
// Do Something.
}, 7000) //Delay in the running of this function
mHandler.postDelayed(this, 10000) //Iteration of 10 Sec
}
}

Don't use a Handler for this - it isn't suitable. Without any more information, I'd recommend an ExecutorService:
Executors.newSingleThreadScheduledExecutor().schedule(() -> {
//Run scheduled background task here. Call onto the main thread with
// new Handler(Looper.getMainLooper()).post(() -> { /*task to execute */ });
}, 30, TimeUnit.SECONDS);
RxJava is another good candidate if you want to know how much time has elapsed. This syntax is for RxJava 1.x but it will be very similar for RxJava 2.x (I think you'd just swap Observable for Flowable):
Observable.interval(30, TimeUnit.SECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(interval -> { /* Task. "Interval" is the time elapsed so far */});

Related

Android - Run TimerTasks in Sequence

I want to run multiple timers in sequence. When one timer completes the next should start. I thought of using the Handler class however this has the effect of running the timers in parallel. As can be seen by the output below.
Is there a way to make the Timer operation block the thread until its complete or is there a better way to achieve this? Maybe with Futures or Kotlin Coroutines?
I'm new to Android. On iOS I have been able to do this with OperationQueue/Operation(set isAsynchronous = true).
class SequentialTimerTasks {
private val handlerThread: HandlerThread = HandlerThread("HandlerThread")
private lateinit var threadHandler: Handler
class TimerCountTask(private val id: Int) : TimerTask() {
private val TAG = "TimerCountTask"
var count = 0
override fun run() {
Log.d(TAG, "Runnable $id RUNNING TIMER $count")
count++
if (count >=10) {
Log.d(TAG, "Runnable $id CANCEL TIMER $count")
this.cancel()
}
}
}
class RunnableTask(private val id: Int) : Runnable {
private val TAG = "RunnableTask"
override fun run() {
Log.d(TAG, "Runnable $id run() called")
val timer = Timer()
timer.schedule(TimerCountTask(id), 0, 1000)
}
}
fun start() {
handlerThread.start()
threadHandler = Handler(handlerThread.looper)
threadHandler.post(RunnableTask(1))
threadHandler.post(RunnableTask(2))
}
}
OUTPUT
Runnable 1 run() called
Runnable 2 run() called
Runnable 1 RUNNING TIMER 0
Runnable 2 RUNNING TIMER 0
Runnable 2 RUNNING TIMER 1
Runnable 1 RUNNING TIMER 1
Runnable 2 RUNNING TIMER 2
Runnable 1 RUNNING TIMER 2
Runnable 2 RUNNING TIMER 3
Runnable 1 RUNNING TIMER 3
Runnable 2 RUNNING TIMER 4
Runnable 1 RUNNING TIMER 4
Runnable 2 RUNNING TIMER 5
Runnable 1 RUNNING TIMER 5
Runnable 2 RUNNING TIMER 6
Runnable 1 RUNNING TIMER 6
Runnable 2 RUNNING TIMER 7
Runnable 1 RUNNING TIMER 7
Your usage of HandlerThread is superfluous — this class does not do anything useful in your code, and it's Thread is no better than any random Thread you started yourself or the threads created by other libraries. Sure, it has a Looper/Handler, but you are not doing anything useful with Handler to justify it's presence.
Timer is ancient legacy from Java versions prior to Java 5. It's existence predates Android and nobody should use it these days. Citing from Timer's documentation:
Java 5.0 introduced the java.util.concurrent package and one of the concurrency utilities therein is the ScheduledThreadPoolExecutor which is a thread pool for repeatedly executing tasks at a given rate or delay. It is effectively a more versatile replacement for the Timer
The biggest mistake in your code is using 2 separate thread pools: a single-threaded HandlerThread "pool" and a hidden thread pool internally used by Timer. In general you should always minimize usage of multi-threading in your code and isolate "normal" code from multi-threaded artifacts. Using multiple types of threads (other than Android main thread) goes contrary to that purpose.
In theory it is possible to fix your original code to work as intended, but because of the reasons above I suggest to abandon both HandlerThread and Timer and switch to single thread pool, based on ScheduledThreadPoolExecutor:
final int PERIOD = 1000;
final int SECOND_TASK_DEADLINE = 10000;
final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
final Runnable firstTask = new Runnable() {
int count = 0;
public void run() {
count++;
Log.d(TAG, "Runnable 1 RUNNING, timer " + count);
}
};
final Runnable secondTask = new Runnable() {
int count = 0;
public void run() {
count++;
Log.d(TAG, "Runnable 2 RUNNING, timer " + count);
}
};
final Future<?> firstFuture = executorService.scheduleAtFixedRate(firstTask, 0, PERIOD, TimeUnit.MILLISECONDS);
executorService.schedule(new Runnable() {
public void run() {
firstFuture.cancel(false);
executorService.scheduleAtFixedRate(secondTask, 0, PERIOD, TimeUnit.MILLISECONDS);
}
}, SECOND_TASK_DEADLINE, TimeUnit.MILLISECONDS);
Unlike your original code, the code above runs your business logic exclusively on 1 thread — the thread of ScheduledThreadPoolExecutor.
This allows you to take advantage of natural mutual exclusion: despite performing no explicit thread synchronization, your code never races or runs concurrently with itself... because there is only 1 thread.

How to reset a variable after 3 seconds in Android?

I am trying to create a Service. In this Service I ahve this variable:
String command="Go"
I want to design a function that does this:
Within 3 seconds, the command will return value "Go"
If the time is bigger than 3 seconds, the command will be reset to "".
My current solution is using a Thread. Do you think it is a safe and good solution?
public String command;
public String getValue(){
command="GO";
try {
Thread.sleep(3000);
command="";
} catch (InterruptedException e) {
e.printStackTrace();
}
return command;
}
As you are doing it at MainThread the app will not response to user and it's the worst thing can happen! I suggest you to use RXJava and be aware of blocking UI Thread!
Observable.just(comment)
.delay(3, TimeUnit.SECONDS)
/*for doing at background*/
.subscribeOn(Schedulers.io())
/*for responsing at maint thread*/
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<String>() {
#Override
public void call(String s) {
comment = "";
// and other stuffs you wand after resetting the val
}
});
A good approach(based on you having a thread already) would be this:
long elapsed = (System.nanoTime()-startTime)/1000000;
if(elapsed>3000) {
//reset your variable
//Allow this to repeat:
startTime = System.nanoTime();
}
In order to initialize, do startTime = System.nanoTime(); where you would initialize the activity.
Now this method has a big drawback: You have to use it with a thread. It cannot be used alone as a listener if you want it to update after 3 seconds and not after 3 seconds on a button press.
Using a thread is a good idea if you want something done repeatedly, but beware of background memory hogging. You may want to create an async thread
A better approach would be to use handlers and postDelayed instead of Thread.sleep().
postDelayed puts the Runnable in the handler thread's message queue. The message queue is processed when control returns to the thread's Looper.
Thread.sleep() blocks the thread.
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//Do stuff every 3000 ms
handler.postDelayed(this, 3000);
}
}, 1500);

Running a Method for a Certain Number of Time

So I have this method called PredictionEngine(int) that I want to run a certain number of time with a certain time-delay between each run. The method goes like this:
private void PredictionEngine(int delay) throws Exception {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
enableStrictMode();
String val = null;
try {
if (tHighPass == 0 && tLowPass == 0 && tKalman == 1) {
//Magic
} else {
//Magic
}
} catch (Exception e) {
e.printStackTrace();
}
enableStrictMode();
new DropboxTask(side_output, "Result", val).execute();
}
}, delay);
}
As obvious, I am running a network operation in the main thread as this is a research app and no client is ever going to use it.
I want this whole function to run for say a 100 times with a certain delay, say 2 seconds. The initial thought was to do this:
for(loop 100 times){
PredictionEngine(int)
Thread.sleep(2000); //sorry for StackOverflow programming.
}
However I don't want to block the main thread as I am reading some sensor data there. Any ideas for the same would be very helpful!
Thanks.
The best way to solve this is by using rxJava library, because it allow to create, modify and consume streams of events. You can implement everything in a few lines of code and modify it so operatioin will be performed in background as well.
Observable.interval(1, TimeUnit.SECONDS)
.take(100)
// switch execution into main thread
.subscribeOn(AndroidSchedulers.mainThread())
.subscribe(t -> {
doSomethingOnMainThread();
});
On the other hand, there is another solution- you can use Handler, which is usually bein used for thread communication. It has method .postDelayed() allowing you to postpone execution of task. Handler can be conveniently used along with HandlerThread. But, rxJava is more convenient and simple way to solve your problem.
While creating your Handler, you can provide a looper as one of the constructors parameters that is based on different thread then the main thread:
HandlerThread thread = new HandlerThread("Thread name", android.os.Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
Looper looper = thread.getLooper();
Handler handler = new MyHandler(looper);
Messages received by MyHandler will be processed on a separated thread, leaving the UI thread clear from interferences.
To loop on the task periodically, use something like:
for (int i=0; i<100; i++){
handler.postDelayed(new Runnable(){
...
...
...
}, i*delay);
}
This way, in case you decide that the periodic tasks need to be canceled, you will always be able to invoke:
handler.removeCallbacksAndMessages(null);
I tried to solve the issue as follows without blocking the main Thread
I created the worker thread for looping and still running the predictionEngine() on main thread
MyThread t = new MyThread(2000, 3000); // delay and sleep
t.startExecution();
Worker thread class looks as follows
class MyThread extends Thread{
private int delay;
long sleep;
MyThread(int delay, long sleep){
this.delay = delay;
this.sleep = sleep;
}
#Override
public void run() {
for(int i = 0; i < 100; i++){
try {
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
predictEngine(delay);
}
});
Log.i("Mtali","About to pause loop before next predict");
sleep(sleep);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
void startExecution(){
start();
}
}
Hop this helps!

Issues run code periodically updating button colors on the UI

I'm trying to run a piece of code periodically every 3 seconds that can change the color of a button.
So far I have:
ScheduledExecutorService scheduleTaskExecutor = Executors.newScheduledThreadPool(2);
// This schedule a runnable task every 2 minutes
scheduleTaskExecutor.scheduleAtFixedRate(new Runnable() {
public void run() {
queryFeedback2(); // display the data
}
}, 0, 3, TimeUnit.SECONDS);
This code will run the piece of code but will not update my UI with the results.
Firstly, what code be cause my UI updating issues?
And secondly, is this the way I should be running my code periodically? Is there a better way?
Yes, there are few options available.
Thread
Runnable
TimerTask
As stated by alex2k8 in their answer here:
final Runnable r = new Runnable()
{
public void run()
{
tv.append("Hello World");
handler.postDelayed(this, 1000);
}
};
handler.postDelayed(r, 1000);
Or we can use normal thread for example (with original Runner):
Thread thread = new Thread()
{
#Override
public void run() {
try {
while(true) {
sleep(1000);
handler.post(r);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
You may consider your runnable object just as a command that can be
sent to the message queue for execution, and handler as just a helper
object used to send that command.
More details are here
http://developer.android.com/reference/android/os/Handler.html
You can update the UI from
handler. Tutorial for using handler, thread is available here.
Selecting between above mentioned option is really based on what kind of functionality you need. If you only need to do something at few interval then any of the above should be fine.

How to change a TextView every second in Android

I've made a simple Android music player. I want to have a TextView that shows the current time in the song in minutes:seconds format. So the first thing I tried was to make the activity Runnable and put this in run():
int position = 0;
while (MPService.getMP() != null && position<MPService.duration) {
try {
Thread.sleep(1000);
position = MPService.getSongPosition();
} catch (InterruptedException e) {
return;
}
// ... convert position to formatted minutes:seconds string ...
currentTime.setText(time); // currentTime = (TextView) findViewById(R.id.current_time);
But that fails because I can only touch a TextView in the thread where it was created. So then I tried using runOnUiThread(), but that doesn't work because then Thread.sleep(1000) is called repeatedly on the main thread, so the activity just hangs at a blank screen. So any ideas how I can solve this?
new code:
private int startTime = 0;
private Handler timeHandler = new Handler();
private Runnable updateTime = new Runnable() {
public void run() {
final int start = startTime;
int millis = appService.getSongPosition() - start;
int seconds = (int) ((millis / 1000) % 60);
int minutes = (int) ((millis / 1000) / 60);
Log.d("seconds",Integer.toString(seconds)); // no problem here
if (seconds < 10) {
// this is hit, yet the text never changes from the original value of 0:00
currentTime.setText(String.format("%d:0%d",minutes,seconds));
} else {
currentTime.setText(String.format("%d:%d",minutes,seconds));
}
timeHandler.postAtTime(this,(((minutes*60)+seconds+1)*1000));
}
};
private ServiceConnection onService = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder rawBinder) {
appService = ((MPService.LocalBinder)rawBinder).getService();
// start playing the song, etc.
if (startTime == 0) {
startTime = appService.getSongPosition();
timeHandler.removeCallbacks(updateTime);
timeHandler.postDelayed(updateTime,1000);
}
}
what about this:
int delay = 5000; // delay for 5 sec.
int period = 1000; // repeat every sec.
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask()
{
public void run()
{
//your code
}
}, delay, period);
Use a Timer for this (instead of a while loop with a Thread.Sleep in it). See this article for an example of how to use a timer to update a UI element periodically:
Updating the UI from a timer
Edit: updated way-back link, thanks to Arialdo: http://web.archive.org/web/20100126090836/http://developer.android.com/intl/zh-TW/resources/articles/timed-ui-updates.html
Edit 2: non way-back link, thanks to gatoatigrado: http://android-developers.blogspot.com/2007/11/stitch-in-time.html
You have to use a handler to handle the interaction with the GUI. Specifically a thread cannot touch ANYTHING on the main thread. You do something in a thread and if you NEED something to be changed in your main thread, then you call a handler and do it there.
Specifically it would look something like this:
Thread t = new Thread(new Runnable(){
... do stuff here
Handler.postMessage();
}
Then somewhere else in your code, you do
Handler h = new Handler(){
something something...
modify ui element here
}
Idea its like this, thread does something, notifies the handler, the handler then takes this message and does something like update a textview on the UI thread.
This is one more Timer example and I'm using this code in my project.
https://stackoverflow.com/a/18028882/1265456
I think the below blog article clearly gives a very nice solution. Especially, if you are a background service and want to regularly update your UI from this service using a timer-like functionality.
It really helped me, much more than the 2007 blog link posted by MusiGenesis above.
https://www.websmithing.com/2011/02/01/how-to-update-the-ui-in-an-android-activity-using-data-from-a-background-service/

Categories

Resources