Handler freezes UI when processing while loop inside a runnable task [android] - java

I want to repeat - - -... so on.
The recording (for seconds) stops when its energy reaches at some threshold value and playbacked. After playback, new recording begins. So I have to monitor the energy using buffers and begin new recording after playback time computation. My pseudocode (most simplified form) looks like this :
...
public class MainActivity extends Activity {
private Handler myHandler = new Handler();
....
private Runnable timedTask = new Runnable() {
public void run() {
audiorecorder = new AudioRecord(... initializes
audiorecorder.startRecording();
isRecording = true;
ElapsedTime = 0.0;
while(true) {
ReadByte = audiorecorder.read(buffer, 0, buffersize);
// Write ReadByte onto file (temp.pcm)
EnergyBuffer = <some averaged energy over a period (1 sec or so)>
if(EnergyBuffer > Threshold)
break;
ElapsedTime = ...
}
// audiorecorder.release, stop, and null
// play temp.pcm using AudioTrack
myHandler.postDelayed(timedTask, Elapsedtime);
};
}
and this is triggered by a start and a stop button as follows,
StartButton.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
myHandler.post(timedTask);
}
});
StopButton.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
myHandler.removeCallbacks(timedTask);
}
});
The problem is when audio is recording or playback, no button is working, I have to wait until it finishes the recording. How can I prevent freezing from recording? Is it just because of whileloop? Please help..!
If I run as follows, there is no error.
Thread t = new Thread(timedTask);
t.start();
This is only one-time ok, but after then when handler does in delayed time, it also freezes the UI.

A handler posts runnable tasks into a looper in a thread. It doesn't on it self create a new thread on which to run the runnables on asynchronously.
When you create a handler by calling the constructor new Handler(), the handler will get the looper of the current thread from which the constructor was called on by default. Since you called new Handler() on the UI thread, any runnable given to the handler's post command will just be added to the UI thread.
You need to create a new thread and get it's looper, by doing
HandlerThread readThread = new HandlerThread("");
readThread.start();
myHandler = new Handler(readThread.getLooper());
HandlerThread is a thread that automatically sets up a looper for you to use.
Of course, you will also need to quit the thread once you don't need it
readThread.quit();

You are the genius, works like a charm and it is exactly what I worked for days, thank you so much!!
Here is the answer from my problem :
public class MainActivity extends Activity {
private Handler myHandler;
....
private Runnable timedTask = new Runnable() {
public void run() {
audiorecorder = new AudioRecord(... initializes
audiorecorder.startRecording();
isRecording = true;
ElapsedTime = 0.0;
while(true) {
ReadByte = audiorecorder.read(buffer, 0, buffersize);
// Write ReadByte onto file (temp.pcm)
EnergyBuffer = <some averaged energy over a period (1 sec or so)>
if(EnergyBuffer > Threshold)
break;
ElapsedTime = ...
}
// audiorecorder.release, stop, and null
// play temp.pcm using AudioTrack
myHandler.postDelayed(timedTask, Elapsedtime);
};
....
protected void OnCreate(Bundle savedInstanceState) {
...
HandlerThread readThread = new HandlerThread("");
readThread.start();
myHandler = new Handler(readThread.getLooper());
...
}
}

Related

How to start a thread if a button is idle?

I need a thread to start after 3 seconds of a button being idle, is there a simple way of doing it?
I'm building a counter app, the button triggers two counters, the total counter and the "tapping counter", the tapping counter helps keep track of the actual change of values, showing how many taps the user did, I need it to vanish after some seconds so the user can tap again.
for stuffs like that I usually use a Handler with a Runnable in order to do stuff after X milliseconds the user isn't doing a specific action.
First, create a runnable and a handler
final android.os.Handler handler = new android.os.Handler();
private Runnable runnable;
private final long DELAY = 3000; // how many milliseconds you want to wait
Then add the onClickListener:
myButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
Then, inside onClick event, remove callbacks and istantiate the handler again as follows:
if(runnable != null) {
// in this case the user already clicked once at least
handler.removeCallbacks(runnable);
}
runnable = new Runnable() {
#Override
public void run() {
//this code will run when user isn't clicking for the time you set before.
}
};
handler.postDelayed(runnable, DELAY);
Final result:
final android.os.Handler handler = new android.os.Handler();
private Runnable runnable;
private final long DELAY = 3000; // how many milliseconds you want to wait
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// all your previous stuffs
myButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(runnable != null) {
// in this case the user already clicked once at least
handler.removeCallbacks(runnable);
}
runnable = new Runnable() {
#Override
public void run() {
//this code will run when user isn't clicking for the time you set before.
}
};
handler.postDelayed(runnable, DELAY);
}
});
}
I hope this helps, for any question feel free to ask
Handler may work in this scenario, with a 3000 milisecond delay.
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
// do action
}
}, 3000);
At first, you create a Timer with a TimerTask(with your Thread) and schedule it to run after 3 seconds.
Every time the button is pressed, you reset the timer.
public class MyClass{
private Timer timer=new Timer()
private TimerTask task=new TimerTask(){
public void run(){
//your action
}
};
public void init(){
timer.schedule(task,3000);
}
public void onButtonClick(){
task.cancel();
timer.schedule(task,3000);
}
}

How to stop while loop after back button is hit

I have tried so many ways of solving my problem, but still no success.I have a method, which returns me a string value and I am using it to update TextView on my screen like this:
outCPU.setText(getCpuInfo());
Which would be fine, but I need to update this TextView until back button was pressed.
I guess i have need a while loop which starts after activity has been created and stops after back button was pressed. This loop should be in a new thread, because:- I have to load the activity first and execute the loop in another thread so the executing won't affect main thread and loading of the activity.
As I've already said, I don't know how to do this properly even though i have spent few hours on it.
Could someone show me an example how to get this done? Thanks...!!
EDITED - WORKING:
private Handler mHandler;
private int i;
#Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_systeminfo);
outCPU = (TextView) findViewById(R.id.outCPU);
outMEM = (TextView) findViewById(R.id.outMEM);
outTASKS = (TextView) findViewById(R.id.outTASKS);
i = 0;
mHandler = new Handler();
mHandler.post(mUpdate);
}
private Runnable mUpdate = new Runnable() {
#Override
public void run() {
outCPU.setText(getCpuInfo());
outMEM.setText(getMemInfo());
outTASKS.setText(getTasksInfo());
i++;
mHandler.postDelayed(this, 1000);
}
};
#Override
public void onBackPressed() {
mHandler.removeCallbacks(mUpdate);
super.onBackPressed();
Log.i("MSG", "Going back");
finish();
}
You can use AsyncTask to perform operations on UI Thread while being in a Thread. Or you can use 'my favorite' , the combination of Thread and Handler. To make sure the thread is stopped when back is pressed, you can use handler.removeCallBacks(Runnable) The following example could solve your problem:
//Global
Handler h = new Handler();
private static boolean flag = true;
public void updateTextView(){
// call thread here
h.post(thread);
}
// take this thread out side so that it can be stopped with handler
Thread thread = new Thread(){
public void run(){
while(flag)
outCPU.setText(getCpuInfo());
}
}
public void onBackPressed(){
flag = false;
h.removeCallBacks(thread);
super.onBackPressed();
}
Use a shared flag somewhere in your app:
private volatile boolean wasPressed = false;
In while loop, check this flag:
while (!wasPressed) {
runOnUiThread(new Runnable() {
#Override
public void run() {
outCPU.setText(getCpuInfo());
}
});
// sleep for a while
}
On button click listener, switch wasPressed to true.

runnable that started on a new thread does not stop when removeCallbacks() is called

I have the following below code.
//This is global for the activity.
Handler handler = new Handler()
{
#Override
public void handleMessage(Message msg)
{
//update the UI
}
};
In my onResume() I am starting a new thread that runs a runnable.
protected void onResume()
{
super.onResume();
Thread t = new Thread(runnable);
t.start();
}
My runnable is as follows :
Runnable runnable = new Runnable()
{
public void run()
{
// some networking stuff
// some db stuff
// whatever
handler.sendEmptyMessage(0);
handler.postDelayed(new Runnable()
{
public void run()
{
new Thread(runnable).start();
}
}, 30000);
}
}
And I have this inside onPause() :
protected void onPause()
{
super.onPause();
handler.removeCallbacks(runnable);
}
At the end I call the handler.sendEmptyMessage(0); so that the handleMessage(Message msg) gets called and I do the UI changes, and I repeat the task but starting a new runnable, which starts a new thread that runs the same runnable as this.
Clarification questions :
I am starting a new Thread inside my onResume(), which means that the runnable is not running on the UI Thread, however, the handler is being created on the UI thread and is naturally attached to the UI thread. How is the UI is being changed flawlessly ?
It is supposed for handler.removeCallbacks(runnable), however, whenever I minized the app, the runnable still keeps on running every 30 seconds. (this might be because it is on a new thread, that is not associated with the Handler created). How can I make it stop ?
public class MainActivity extends Activity {
public static final int UPDATE = 1;
public static final int WORK = 2;
private Handler uiHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case UPDATE:
// Perform UI updates here
....
// UI Updates done, schedule WORK in 30 seconds:
this.sendMessageDelayed(this.obtainMessage(WORK), 30000);
break;
case WORK:
new Thread(doWork).start();
break;
default:
super.handleMessage(msg);
}
}
};
private WeakReference<Handler> handlerRef = new WeakReference<Handler>( uiHandler );
private Runnable doWork = new Runnable() {
#Override
public void run() {
// This will run on a different thread.
// If UI is still around, tell it to update
Handler ui = handlerRef.get();
if( ui != null )
ui.sendEmptyMessage(MainActivity.UPDATE);
}
};
#Override
protected void onPause() {
uiHandler.removeMessages(WORK);
super.onPause();
}
#Override
protected void onResume() {
super.onResume();
// Resume UI updates in 500ms, allowing UI to settle
uiHandler.sendMessageDelayed(uiHandler.obtainMessage(WORK), 500);
}
....
}
This pattern uses a single Handler on the UI thread. Background work is done in the Runnable, which the ui Handler will post to a new Thread, so avoiding NetworkOnMainThreadException and -- more importantly -- unresponsive UI. Further, a new update is scheduled thirty seconds after the background process has completed, to avoid taxing the system with long-running updates. The background thread uses a WeakReference to the ui Handler, so if the Activity is killed while the thread is working, it won't send UI updates to it.

How to repeat a task after a fixed amount of time in android?

I want to repeatedly call a method after every 5-seconds and whenever I wish to to stop the repeated call of the method I may stop or restart the repeated call of the method.
Here is some sample code that whats really I want to implement. Please help me in this respect I would be very thankful to you.
private int m_interval = 5000; // 5 seconds by default, can be changed later
private Handler m_handler;
#Override
protected void onCreate(Bundle bundle)
{
...
m_handler = new Handler();
}
Runnable m_statusChecker = new Runnable()
{
#Override
public void run() {
updateStatus(); //this function can change value of m_interval.
m_handler.postDelayed(m_statusChecker, m_interval);
}
};
public void startRepeatingTask()
{
m_statusChecker.run();
}
public void stopRepeatingTask()
{
m_handler.removeCallbacks(m_statusChecker);
}
Set repeated task using this:
//Declare the timer
Timer t = new Timer();
//Set the schedule function and rate
t.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
//Called each time when 1000 milliseconds (1 second) (the period parameter)
}
},
//Set how long before to start calling the TimerTask (in milliseconds)
0,
//Set the amount of time between each execution (in milliseconds)
1000);
and if you wanted to cancel the task simply call t.cancel() here t is your Timer object
and you can also check comment placed below your answer they have given brief information about that.
Use a Handler in the onCreate() method. Its postDelayed() method causes the Runnable to be added to the message queue and to be run after the specified amount of time elapses (that is 0 in given example). Then this will queue itself after fixed rate of time (1000 milliseconds in this example).
Refer this code :
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
android.os.Handler customHandler = new android.os.Handler();
customHandler.postDelayed(updateTimerThread, 0);
}
private Runnable updateTimerThread = new Runnable()
{
public void run()
{
//write here whaterver you want to repeat
customHandler.postDelayed(this, 1000);
}
};
use TimerTask to call after specific time interval
Timer timer = new Timer();
timer.schedule(new UpdateTimeTask(),1, TimeInterval);
and
class UpdateTimeTask extends TimerTask {
public void run()
{
// do stufff
}
}
Do it in Android's way with the help of Handler.
Declare a Handler which does not leak Memory
/**
* Instances of static inner classes do not hold an implicit
* reference to their outer class.
*/
private static class NonLeakyHandler extends Handler {
private final WeakReference<FlashActivity> mActivity;
public NonLeakyHandler(FlashActivity activity) {
mActivity = new WeakReference<FlashActivity>(activity);
}
#Override
public void handleMessage(Message msg) {
FlashActivity activity = mActivity.get();
if (activity != null) {
// ...
}
}
}
Declare a runnable which handle your task
private Runnable repeatativeTaskRunnable = new Runnable() {
public void run() {
new Handler(getMainLooper()).post(new Runnable() {
#Override
public void run() {
//DO YOUR THINGS
}
};
Initialize handler object in your Activity/Fragment
//Task Handler
private Handler taskHandler = new NonLeakyHandler(FlashActivity.this);
Repeat task after fix time interval
taskHandler.postDelayed(repeatativeTaskRunnable , DELAY_MILLIS);
Stop repetition
taskHandler .removeCallbacks(repeatativeTaskRunnable );
You have to put this code inside the activity you want to call every 5 seconds
final Runnable tarea = new Runnable() { public void run() {
hola_mundo();//the operation that you want to perform }};
ScheduledExecutorService timer = Executors.newSingleThreadScheduledExecutor();
timer.scheduleAtFixedRate(tarea, 5, 5, TimeUnit.SECONDS);

Run task after 10 seconds, unless user presses button

In my Android app, I want to schedule a task to run in 10 seconds, unless the user presses a specific button.
What is the best way to do this? Should I use a java.util.Timer, java.util.concurrent.ScheduledThreadPoolExecutor or something else?
Thank you in advance.
A handler is fit for this if you are accessing the UI from your task :
Runnable runnable = new Runnable() {
public void run () {
// Do your stuff here
}
}
Handler handler = new Handler();
handler.postDelayed(runnable, 10000);
in your button action :
handler.removeCallbacks(runnable);
Otherwise, a Timer is fine.
and Handler and its postDelayed method
private Runnable requester = new Runnable() {
#Override
public void run() {
// cpde to execute here
}
};
public void onClick(View v) {
new Handler().postDelayed(requester, 10000);
}
You able to use TimerTask and Handler.

Categories