I am trying to make a delay after playing the set of sounds in mediaplayer so that it won't overlap. i have tried thread.sleep and it worked but the problem is I have a button for sound to stop but because of the thread.sleep, it is not working so i searched and tried for an alternative way in which i can make a delay without locking the UI and i came up with handler.postDelayed but it is not working. is there anyone who can help me solve this problem? thanks in advance.
here is my code:
protected void managerOfSound() {
int size = tempq.size();
for (int i = 0; i < tempq.size(); i++) {
String u =tempq.get(i);
//WHOLE
if (u.equals("a4")){
mp = MediaPlayer.create(this, R.raw.a4);
mp.start();
final Runnable r = new Runnable() {
public void run() {
handler.postDelayed(this, 2000);
}
};
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
// stuff you wanna delay
}
}, 2000);
The postDelayed(Runnable r, long delayMillis ) causes the Runnable to be added to the message queue, to be run after the specified amount of time elapses. The runnable will be run on the thread to which this handler is attached ( int htis case the UI thread) . The time-base is uptimeMillis(). Time spent in deep sleep will add an additional delay to execution.
Reference : Android API documentation
Related
One part of my activity needs two timers running at once, one of them using Handler and the other using CountDownTimer. The handler portion updates the display every second, while the CountDownTimer counts down to when this part of the code ends. For some reason, I cannot run these both at the same time, and even when I commented out the CountDownTimer portion, the handler portion only ran once, instead of repeating every second. I am at a loss for what to do here. Any ideas? The relevant part of the code is below. For some clarification, the first handler seen here is supposed to run on its own, until a condition is met, at which point it reruns the function and goes to the second if statement. Seen within the second if statement are the details I mentioned at the beginning.
private void statusCheck() {
if (possible = true) {
final Random random = new Random();
final Handler handler1 = new Handler();
final int delay1 = 1000; //milliseconds
handler1.postDelayed(new Runnable() {
public void run() {
runChance = random.nextInt(1000);
if (runChance < 100) {
possible = false;
statusCheck();
}
}
}, delay1);
}
if (possible = false) {
final Handler Handler = new Handler();
final int Delay = 1000; //milliseconds
Handler.postDelayed(new Runnable() {
public void run() {
// code to update every second
}
}, Delay);
new CountDownTimer(ghostDuration, 1000) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
//code to run when finished
}
}.start();
}
}
First of all it's not a good idea to to run timer and tasks under Android that way.
Android will block these timer and tasks because they work against the framework.
If you want to implement it correctly with a WorkManager watch out this video from Google which gives you some fundamentals: Android Jetpack WorkManager
I'm playing around with some basic android, and I'm trying to write a metronome app. The basic idea is that I'm using a runnable in order to trigger a sound after a time period (msPeriod). I've tried to use SoundPool, but it will just log 'sample not loaded', and trying to ititialise a MediaPlayer causes the app to crash on opening. Could you explain to me where I'm going wrong please? Below is my code with MediaPlayer.
//I create the media player first thing inside MainActivity
private Handler handler = new Handler();
int msPeriod = 1000;
MediaPlayer mpHigh = MediaPlayer.create(this, R.raw.hightick);
MediaPlayer mpLow = MediaPlayer.create(this, R.raw.lowtick);
//within an onClick Listener
onClick(View v) { handler.postDelayed(startMetron, msPeriod); }
//the runnable that starts the metronome
private Runnable startMetron = new Runnable( ) {
#Override
public void run() {
if(isRunning){
if (count == 4) {
count = 1;
mphigh.start();
} else {
count++;
mplow.start();
}
}
textCount.setText(String.valueOf(count));
//triggering the next run
handler.postDelayed(this, msPeriod);
}
};
Thanks so much for bearing with me!
You are running a separate thread . The UI element must be updated form the main thread... so..
runOnUiThread(new Runnable(){
public void run() {
textCount.setText(String.valueOf(count));
}
});
This makes sure that the textview is update from the UI thread and your app will not crash.
I'm trying to make a countdown timer in android for use in a small android app. The app will countdown from some number of seconds to 0, upon which it will do some action. I'm using the coundowntimer supplied by android.os.countdowntimer. Here is my code:
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.quizlayout);
new CountDownTimer(30000, 1000) {
TextView tx = (TextView) findViewById(R.id.textView2);
public void onTick(long millisUntilFinished) {
tx.setText("seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
tx.setText("done!");
}
}.start();
}
However, this countdown timer is really slow. It takes like 3 real-time seconds for the timer to countdown by one second. I wonder what's going on? The code I have above is more or less copied straight from google (CountDownTimer)
Can anyone help me as per why my timer is so slow, and offer a way to speed it up a bit?
(EDIT): I am running this on an emulator, the intel atom x86. I am emulating an android 2.3.3 environment.
According to Android documentation for countdown timer
The calls to onTick(long) are synchronized to this object so that one call to onTick(long) won't ever occur before the previous callback is complete. This is only relevant when the implementation of onTick(long) takes an amount of time to execute that is significant compared to the countdown interval.
Take a look at this example for countdown timer
Countdown timer example
Alternately you can spawn a new thread and just get that thread to sleep for the interval you want and take actions when it wakes or vice versa.
You can also timertask
use a handler that will post the same runnable . this will remove the need for extra threads :
Handler handler=new Handler();
handler.postRunnable(... , 1000) ;
in the runnable , call the postRunnable again for the same handler (and add a condition for when to stop) .
CountDownTimer is not efficient regardless to ui updating performances. For a flawless ui update, it is better to create a custom countdown. I did my own so here it is. It is flawless on my app.
public abstract class CountDown {
int totalTime = 0;
int tickTime = 0;
Thread thread;
boolean canceled = false;
public CountDown(int totalTime,int tickTime){
this.totalTime = totalTime;
this.tickTime = tickTime;
}
public abstract void onTick();
public abstract void onFinish();
public void start(){
thread = new Thread(new Runnable() {
#Override
public void run() {
// Do in thread
canceled = false;
for (int elapsedTime = 0; elapsedTime < totalTime; elapsedTime += tickTime) {
if(!canceled){
onTick();
try {
thread.sleep(tickTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
break;
}
}
if(!canceled){
onFinish();
}
}
});
thread.start();
}
public void cancel(){
canceled = true;
}
}
Remember that every time you have to update your ui, call a runOnUiThread, or else you will have an exception, you are not in a handler and not on ui thread.
Here is how to use it in your code, it is identical to CountDownTimer, so you could just rename lines in your code :
CountDown cDown = new CountDown(10000, 20) {
public void onTick() {
// Do something
}
public void onFinish() {
runOnUiThread(new Runnable() {
#Override
public void run() {
myButton.setImageDrawable(drawable);
}
});
}
};
I've got an activity that keeps reading words to the user, and using onUtteranceCompleted with textTospeech to display something when the code is completed.
Inside onUtteranceCompleted I have this code to delay a function with a second:
Runnable task = new Runnable() {
public void run() {
//runs on ui
runOnUiThread(new Runnable() {
public void run() {
readWord();
}
});
}
};
worker.schedule(task, 1, TimeUnit.SECONDS);
This seems like it works well, but I think it is causing a problem.
When I rotate the screen of my phone (I guess this starts a new activity).
I hear some words being read in the background. I guess this is because of runOnUiThread() which makes the activity continue in the background.
How could I avoid 2 activities running ? I would prefer if I don't have to stop the screen from rotating on doing some weird patch!
Thank you
EDIT:
public void readWord() {
if (this.readingOnPause) {
return;
}
txtCurrentWord.setText(currentItem[1]);
this.hashAudio.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID,"word");
this.tts.setLanguage(Locale.US);
this.tts.speak(this.currentItem[1], TextToSpeech.QUEUE_FLUSH,this.hashAudio);
}
EDIT2:
instantiation of worker:
private static final ScheduledExecutorService worker = Executors.newSingleThreadScheduledExecutor();
I would use a Handler instead of runOnUiThread().
For one thing, you're using a Thread that starts another Thread - why?
Secondly, if you create a simple Handler, it should kill itself on the rotate config change. IE:
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
// do your background or UI stuff
}
};
Then later use a Thread to call the handler, which will kick off whatever process you want to run on the UI thread:
new Thread() {
#Override
public void run() {
long timestamp = System.currentTimeMillis();
// thread blocks for your 1 second delay
while (System.currentTimeMillis() - timestamp <= 1000) {
// loop
}
handler.sendEmptyMessage(0);
}
}.start();
Ok so this is a fix I've come up with, if someone has a better solution, I'm listening.
I've added android:configChanges="keyboardHidden|orientation" inside the activity in the androidmanifest
2.
and then a function that is called when the screen is rotate:
#Override
public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
setContentView(R.layout.streaming);
initializeUI(); //contains all the findViewByID etc...
}
Just testing out a simple block of code in my mainActivity's onCreate:
Timer timer2 = new Timer();
TimerTask testing = new TimerTask() {
public void run() {
Toast.makeText(mainActivity.this, "test", Toast.LENGTH_SHORT).show();
}
};
timer2.schedule(testing, 1000);
I get the "force close" error though.
What gives?
Alright for anyone else who runs into this, I fixed the problem by using a Handler and Runnable to do the Toast, which seems to be needed for UI interaction:
final Handler handler = new Handler();
Timer timer2 = new Timer();
TimerTask testing = new TimerTask() {
public void run() {
handler.post(new Runnable() {
public void run() {
Toast.makeText(mainActivity.this, "test", Toast.LENGTH_SHORT).show();
}
});
}
};
timer2.schedule(testing, 1000);
I still don't understand why this is necessary though, perhaps someone could explain? But hey at least this code works lol.
Timer(Tasks) are bad! Do it the Android way: Use a Handler.
As you can see in the code snippet, it’s pretty easy to go that way too:
First we need a Handler that starts the Runnable after 100ms
private Handler handler = new Handler();
handler.postDelayed(runnable, 100);
And we also need the Runnable for the Handler
private Runnable runnable = new Runnable() {
#Override
public void run() {
/* do what you need to do */
foobar();
/* and here comes the "trick" */
handler.postDelayed(this, 100);
}
};
So the “trick” is to tell the handler at the end to start the Runnable again. This way the runnable is started every 100ms, like a scheduleAtFixedRate() TimerTask! If you want it to stop, you can just call handler.removeCallback(runnable) and it won’t start again, until you tell it to
This exact issue is discussed in this article:
http://developer.android.com/resources/articles/timed-ui-updates.html
The app crashes because you are attempting to access elements of the UI thread (a toast) from a different thread (the timer thread). You cannot do this!
You can get round it by either:
Sending a handler message from the timer thread to the UI thread, and then showing the toast in the UI handler function.
OR
In the timer code run use 'runOnUiThread':
#Override
public void run()
{
mainActivity.runOnUiThread(new Runnable() {
public void run() {
// Access/update UI here
Toast.makeText(mainActivity.this, "test", Toast.LENGTH_SHORT).show();
}
});
}
#YoungMoney
It works but only the first time... Did you make it display the Toast message every second??
Mine only worked once...
===
Edit:
Just realised your last line of code is missing the last value which is how often to repeat.
For anyone else concerned, change this:
timer2.schedule(testing, 1000);
to this:
timer2.schedule(testing, 1000, 2000);
If you want to start the timer in 1 second, and update every 2 seconds.
TimerTask task = new TimerTask() {
#Override
public void run() {
//do something
}
};
Timer t = new Timer();
t.schedule(task, 2000);