How to run multiple UI threads in one Activity without ANR? - android

I want to create a monitoring application and their updated UI every second. for example I have 10 textView for display timing and 10 Progress bar to set some progress to display and 6 timers for display time like a stopwatch. all things in the same activity and its run also at the same time.
But When I used ScheduledExecutorService UI stuck and the application going to not respond. how to Implement all things perfectly without ANR?
Here is My code update textView Timer in the thread
private void getLiveUpdate() {
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
MyTimerTask myTimerTask = new MyTimerTask(() -> {
runOnUiThread(() -> {
getSetData();
getTime(binding.tvCurrentDate);
setRv_channels(switchGroup1, Utills.switchModels1, binding.rvChannelsMain);
setRv_channels(switchGroup2, Utills.switchModels2, binding.rvChannelsMain1);
setRv_channels(switchGroup3, Utills.switchModels3, binding.rvChannelsMai2);
if (isOtOn) {
binding.tvOtOffTime.setText(timee(otStartCounter));
otStartCounter++;
}
if (isPatientIn) {
binding.tvPOutTime.setText(timee(patientInCounter));
patientInCounter++;
}
if (isSurgIn) {
binding.tvSugOutTime.setText(timee(surgeonTimeCounter));
surgeonTimeCounter++;
}
if (isAnaeIn) {
binding.tvAnafTime.setText(timee(anaeTimeCounter));
anaeTimeCounter++;
}
if (isSurgeryStart) {
binding.tvSurgeryTime.setText(timee(surgeryTimeConunter));
surgeryTimeConunter++;
}
if (isAnaeStart) {
binding.tvAneTime.setText(timee(anaeStartTimeConunter));
anaeStartTimeConunter++;
}
});
});
scheduler.scheduleAtFixedRate(myTimerTask, 0, 1, TimeUnit.SECONDS);
}
private String timee(int seconds) {
int hours = seconds / 3600;
int minutes = (seconds % 3600) / 60;
int secs = seconds % 60;
return String.format(Locale.getDefault(), "%02d:%02d:%02d", hours, minutes, secs);
}

UI thread is one and only, there is no such thing as "multiple UI thread"
if you are performing some actions in separated thread and want to show (partial) results in GUI you have to run GUI-drawing-related code (e.g. textView.setText(...)) in this one and only UI thread. easiest way is to use Handler with MainLooper - its called "main", because UI thread is one and only mandatory working thread, you may not thread your app/code at all. so you can get access to it by some static refrerences, thus below may be pasted literally anywhere in any thread
Handler(Looper.getMainLooper()).post {
// UI related code
}
still if you want to change text in some TextView, which is created/referenced in UI thread only you have to pass reference to it to this "another thread" and use this reference inside Runnable posted for Handler with main Looper

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.

Android Async task slowing down my UI Thread

I am new to Android Application development and was having a problem with Async tasks.
So I'm trying to create an ECG graphing application that does some background processing while the graphing is happening.
I've defined the following Async task -
private class Erosion extends AsyncTask <Void,Void,Void> {
#Override
protected Void doInBackground(Void...unused ) {
int i,tempIndex;
double[] tempArray = new double[13];
double min = ecgSamples[ecgSampleForErosionIndex] - gArray[0];
while (ecgIncoming)
{
if (ecgSampleForErosionIndex > 179999)
{
ecgSampleForErosionIndex = 0;
}
for(i= 0;i<13;i++)
{
tempIndex = ecgSampleForErosionIndex + i;
if (tempIndex > 179999)
{
tempIndex = (ecgSampleForErosionIndex + i) - 180000;
}
tempArray[i] = ecgSamples[tempIndex] - gArray[i];
if (tempArray[i] < min)
{
min = tempArray[i];
}
}
//min needs to be stored in the erosionFirst Array
if (erosionFirstArrayIndex > 179999)
{
erosionFirstArrayIndex = 0;
}
ecgErosion[erosionFirstArrayIndex] = min;
erosionFirstArrayIndex++;
ecgSampleForErosionIndex++;
}
return null;
}
} //End of Async Task
So all I'm trying to do is modify the content of a particular array in the async task - i dont need to update the UI (at least not for now)
However, when I run this async task my ECG graphing slows down and becomes jerky. When I comment out the "new Erosion().execute();" part in the code where I start the Async task, the graphing becomes normal again.
Isn't an async task supposed to be on a separate thread and so not affecting how things are happening on my UI thread? What am I doing wrong?
Even if you run a heavy piece of code on a background thread it will still affect the CPU load of the device and therefore might cause delays in your UI thread as well, specially if the device has single-core CPU.
It seems like you have a very heavy loop in you doInBackground method, which runs constantly and just use the CPU nonstop, which overloads it. I'm not sure what this loop is for, but if it doesn't have to refresh constantly you might want to consider adding a thread sleep, allowing other threads to get more CPU time :
while (ecgIncoming)
{
... do your thing ...
Thread.sleep(100); // wait for 100 milliseconds before running another loop
}
Obviously the "100" is just a number, if the array can update once a second, make it a 1000, etc...
By any chance are you running new Erosion().execute(); multiple times? That might cause it because you are allocating a new AsyncTask multiple times.

Creating a stopwatch that updates in UI thread Android

I have been trying to figure out how to make a custom chronometer that is precise down to a hundredth of a second. I have looked at a lot of the other similar questions and decided to try it using a thread and handler.
This is my custom handleMessage method:
public void handleMessage(Message msg) {
String timeText = msg.getData().getString("time");
watch.setText(timeText);
}
The watch object is just a TextView that is initialized in onCreate().
And this is the main chunk of my run method:
while(true) {
long timeElapsed = System.currentTimeMillis() - startTime;
int hundreths = (int)((timeElapsed % 1000) / 10);
int seconds = (int)((timeElapsed % 60000) / 1000);
int minutes = (int)(timeElapsed / 60000);
Bundle bundle = new Bundle();
bundle.putString("time", String.format("d:%02d.%02d", minutes, seconds, hundreths));
Message msg = handler.obtainMessage();
msg.setData(bundle);
handler.handleMessage(msg);
}
I realize that the whole idea behind using a handler is that only the UI thread can update elements on the screen, but I am still getting a CalledFromWrongThreadException with the message that only the original thread that started created the View hierarchy can call methods on it. I am confused as to what exactly I am doing wrong.
I think your error is because you are using handleMessage instead of sendMessage.
A simpler approach might be to use runOnUiThread method and give up the handler.
http://developer.android.com/reference/android/app/Activity.html#runOnUiThread(java.lang.Runnable)

How to run some code for 20 seconds in android

I want to run some code for 20 seconds precisely. It is similar to a loop but instead of having a variable I have time (in seconds).
I should have a time condition like this:
do
{ variable++ }
while (sec < 20)
How it is possible to do this in Android??
My application should run this 20 sec code after the user presses a button.
You can use the Handler class in Android on a runnable and then use the postDelayed() method. That way you will be able to update the UI during that 20 seconds on the progress of the thread. A good example of this is hear. Your code might look something like this ...
Handler handler = new Handler();
final Runnable r = new Runnable(){
public void run() {
//Do thing after 20 sec
}
};
handler.postDelayed(r, 20000);

Runnable is executing slower than expected

I'm using a runnable in my Android app to update a countdown timer, as shown in the code below. It appears to work but I noticed my timer takes a few seconds longer than expected. For example, if it's supposed to count down 3 minutes, it takes 3 minutes and 5 seconds. I tried using a timer in a service to manage the countdown display in the main activity. The timer/service worked as expected.
Why doesn't runnable/postDelayed() run for the correct amount of time? Is postDelayed() timing reliable? The runnable decrements a variable then uses it to update an EditText with setText(). Does setText() take too long (a small fraction of a second), so the runnable really runs every 1.x seconds?
Handler handler = new Handler();
Runnable r = new Runnable() {
public void run() {
// decrement the time remaining and update the display
handler.postDelayed(this, 1000);
}
};
...
// start the runnable
handler.postDelayed(r, 1000);
Your code is kinda sorta designed to be inaccurate because you are not accounting for the time taken by the guts of the runnable. You might get improved results by doing something like
public void run(){
startTime = System.currentTimeMillis();
// compare expectedTime to startTime and compensate
// <guts of runnable goes here>
// now wrap it up...
delay = 1000 - (System.currentTimeMillis() - startTime);
if (delay < 0)
delay = 0;
expectedTime = System.currentTimeMillies() + delay;
handler.postDelayed(this, delay);
}
What about using CountDownTimer? I used this for same tasks several times and haven’t met this kind of problem.

Categories

Resources