'Thread freezes UI
I have this button that when clicked calls a thead to update user ui:
averageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new Testing().execute();
}
});
The method gets executed but it freezes the UI for 10 seconds. I want to update the UI everytime I call the averageMiles.append(mile) method.
class Testing extends AsyncTask<Void, Void, Void> {
@Override
protected void onPostExecute(Void unused) {
int x = 0;
while (true) {
if (x == 10) {
break;
}
ArrayList<Double> milesList = new ArrayList<>();
if (x == 0) {
averageMiles.setText("mph: ");
}
String mile = milesValue.getText().toString();
if (!isNum(mile)) {
continue;
}
averageMiles.append(mile);
milesList.add(Double.valueOf(mile.trim()));
x++;
if (x == 10) {
averageMiles.append("\nAverage: " + getAverage(milesList));
return ;
} else {
averageMiles.append(", ");
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Solution 1:[1]
Use ThreadPool executor from official oracle and android developer documentations
Oracle Docs - java.util.concurrent.ThreadPoolExecutor
Android Docs - java.util.concurrent.ThreadPoolExecutor
as you have specified you are using java the above two documentation is recommended by google as show below for AsyncTask
This class was deprecated in API level 30. Use the standard java.util.concurrent or Kotlin concurrency utilities instead.
The ultimate objective is the android is saying that, if you want to update UI, simply use runOnUiThread with a new runnable you update the UI, which means for each UI update you may be creating fresh short term thread which only updates the UI and thread finishes and garbage collected
Sample Code
public class MainActivity extends AppCompatActivity {
int count = 0;
Executor ex;
MyThread th;
class MyThread extends Thread implements Runnable {
private boolean running=false;
public void setRunning(boolean running) {
this.running = running;
}
@Override
public void run() {
while(running) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
@Override
public void run() {
count++;
TextView tv = findViewById(R.id.textView);
tv.setText(String.valueOf(count));
}
});
}
}
}
public void onStartClick(View view) {
th = new MyThread();
ex = Executors.newSingleThreadExecutor();
th.setRunning(true);
ex.execute(th);
}
public void onStopClick(View view) {
if(th!=null) {
th.setRunning(false);
}
}
}
all the member variables of the class should be only accessed inside runOnUiThread, for example count++ count is a variable of the MainActivity if you want any value specific to the thread you put only inside the MyThread class
Never try to access any of the MainActivity variable inside the run() method
You can also write MyThread as separate class, and set values similar to th.setRunning before starting the thread.
If you want a callback after the thread is completed use an interface which will give you a callback method in your MainActivity
So it is simply core java
I have created an example with interface
Concurrent Executor Interface Example
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
