Best way to play sound on a timed interval? - android

I have an Android app which needs to play a sound resource on a timed interval, say every 120 seconds.
I know how to access the sound resources and play them, however it's time timer part I'm not sure of. What's the best approach?

I ended up ditching the Timer approach and used a Handler instead after stumbling upon an example at android-labs.
So, instead of spawning the Timer and TimerTask in my Activity's onCreate, I declared this private Handler with in-line Runnable:
private Handler _playRandomSoundHandler = new Handler();
private Runnable _playRandomSoundTask = new Runnable() {
public void run() {
SoundManager.playRandom();
_playRandomSoundHandler.postDelayed(_playRandomSoundTask, Prefs.getDelayInMilliseconds(getApplicationContext()));
}
};
Also, I had to add code to my Activity's onResume and onPause:
#Override
protected void onResume() {
super.onResume();
_playRandomSoundHandler.postDelayed(_playRandomSoundTask, Prefs.getDelayInMilliseconds(this));
}
#Override
protected void onPause() {
super.onPause();
_playRandomSoundHandler.removeCallbacks(_playRandomSoundTask);
SoundManager.stop();
}
This approach seems to work great.

Related

Handler postDelay() new Runnables create garbage?

I've been thinking about implementing postDelay() in my game animation to make it more smooth. What I am worried about is that postDelay() creates a new Runnable everytime it is executed. Since my game needs postDelay() to be executed very often, will this create a lot of garbage since it is creating a new Runnable every time? Or even if it does not, does the creation of a new Runnable slow down performance?
So in this case, is it appropriate to use postDelay() in a situation where it is going to be executed very often for a long time?
You can use single Runnable instance for all postDelayed calls.
But I think that a loop is better for games, it's a standard pattern, like in this post: How to appear and disappear an object on screen using game loop for every five second
There's no need to create a new runnanable each time postDely() is executed
private static int LOOP_TIME = 5000;
private Handler handlerWork;
private Runnable runnableWork = new Runnable() {
#Override
public void run() {
//do some work
handlerWork.postDelayed(runnableWork, LOOP_TIME);
}
}
#Override
protected void onResume() {
super.onResume();
if (handlerWork == null)
handlerWork = new Handler();
handlerWork.postDelayed(runnableWork, LOOP_TIME);
}
#Override
protected void onPause() {
super.onPause();
if (handlerWork != null)
handlerWork.removeCallbacks(runnableWork);
}

Running repeating animation in Android using a thread/runnable

My goal is to have a thread running that plays a sound then chooses a random animation and a random image and displays them.
It is currently working, but I was wondering if there is a better way. I have a Hacker's understanding of threading (as in, I only know that this works), so I'd appreciate some feedback. Also, I've been having issues with memory overflow in my app, is there a better way to manage this Activity memory-wise? Thank you so much!
public int[] images = {R.drawable.splat0,R.drawable.splat1,R.drawable.splat2,R.drawable.splat3,
R.drawable.splat4,R.drawable.splat5,R.drawable.splat6,R.drawable.splat7,R.drawable.splat8,
R.drawable.splat9};
public int[] anims= {R.anim.splat0,R.anim.splat1,R.anim.splat2,
R.anim.splat3,R.anim.splat4,R.anim.splat5,R.anim.splat6};
MediaManager mp;
Handler tick_Handler = new Handler();
MyThread tick_thread = new MyThread();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
MainActivity.this.setContentView(R.layout.activity_main);
mp = new MediaManager();
image = (ImageView)this.findViewById(R.id.mainActivitySplat);
tick_Handler.post(tick_thread);
}
#Override
public void onStop(){
tick_Handler.removeCallbacks(tick_thread);
super.onStop();
}
#Override
public void onResume(){
tick_Handler.post(tick_thread);
super.onResume();
}
private class MyThread implements Runnable {
#Override
public void run() {
mp.playSoundClip(MainActivity.this,R.raw.swoosh);
image.setBackgroundResource(images[(int)(Math.random()*splats.length)]);
Animation myAnim=AnimationUtils.loadAnimation(MainActivity.this,splatAnim[(int)(Math.random()*splatAnim.length)]);
splat.startAnimation(myAnim);
tick_Handler.postDelayed(tick_thread, 3500);
}
}
Edit:
I have discovered this is a BAD way of using the Thread. MyThread holds an implicit reference to the Activity, and causes a massive memory leak. By changing the class to private static MyThread I solve the leak, but I have not yet figured out how to get the desired behavior this way. Will update later.
use a flag like
boolean isActibityKilled=true //when in onstop
use it in the runnable to check if activity is running or not if activity is not running , or it is stopped then kill your thread

Automatically start execution upon activity launch

I'm working on an app that synchronizes some graphic UI events with an audio track. Right now you need to press a button to set everything in motion, after onCreate exits. I'm trying to add functionality to make the audio/graphical interaction start 10 seconds after everything is laid out.
My first thought is, at the end of onCreate, to make the UI thread sleep for 10000 miliseconds using the solution here and then to call button.onClick(). That seems like really bad practice to me, though, and nothing came of trying it anyway. Is there a good way to implement this autostart feature?
Never ever put sleep/delay on UI-thread. Instead, use Handler and its postDelayed method to get it done inside onCreate, onStart or onResume of your Activity. For example:
#Override
protected void onResume() {
super.onResume();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
//do whatever you want here
}
}, 10000L); //the runnable is executed on UI-thread after 10 seconds of delay
}
Handler handler=new Handler();
Runnable notification = new Runnable()
{
#Override
public void run()
{
//post your code............
}
};
handler.postDelayed(notification,10000);
Yes, putting the UI thread to sleep isnt a good idea.
Try this
private final ScheduledExecutorService worker = Executors.newSingleThreadScheduledExecutor();
worker.schedule(task, 10, TimeUnit.SECONDS);

Create timer(Handler) when view appears and stop it when view disappears

I have been developing iOS apps for quite a time and now i have switched to android. I have a requirement in which I have to start timer(In think in Android, I need to use handler) when view appears(onResume) and invalidate timer(stop handler) when view disappears(onPause). I am able to create runnable Handler but not able to stop it.
My code is:
protected void AutoRefresh() {
try{
handler.postDelayed(new Runnable() {
public void run() {
new LongOperation().execute("");
}
AutoRefresh();
}, 60000);
}
catch(Exception ex){
}
}
Now, how can I stop this this handler thread when view disappears. Please also comment, if its not the right way to do timer implementation in android.
when view appears(onResume) and invalidate timer(stop handler) when
view disappears(onPause). I am able to create runnable Handler but not
able to stop it.
Keep a reference to the Runnable you use:
private Runnable mRefresh = new Runnable() {
public void run() {
new LongOperation().execute("");
}
AutoRefresh();
}
//...
protected void AutoRefresh() {
handler.postDelayed(mRefresh, 60000);
}
and in onPause remove it like this:
handler.removeCallbacks(mRefresh);
Keep in mind that this will not remove the currently Runnable that is being executed(if any) so in the LongOperation's onPostExecute method you might want to check if the Activity is still available before refreshing the UI or doing any other interaction with the Activity.
Please also comment, if its not the right way to do timer
implementation in android.
You seem to need to do an action at a certain interval of time and using a Handler is the way to do it, I don't think a timer is what you need.

Using a Service with A Timer to Update a View

I'm not sure if this is the correct way to go about but I will try and explain what I want to do.
I have an Activity which creates a fragment called TemporaryFragment with a label. What I want to do is create and start a service with a Timer in it and that Timer then updates the time in that TextView.
The way I am thinking of going is somehow, when the Service is started, passing the TextView from the Activity to the Service and then the Service keeping a reference to it.
Another possible way is to make the Activity become a listener of the Service and then calling a method in the Service to update the TextView.
Any thoughts would be great and maybe some options.
Thanks in advance.
ADDITION
I'm sorry, I should also specify that I need this timer to run in the background. So when the application is sent to the background, I need the timer to carry on and only stop when I tell it to.
Service is not ideal for such minor task like this, moreover, Service can be run independently of activity. Also spawning new thread or using timer which introduces new thread into the application is not ideal for this relatively minor reason if you are thinking in the terms of mobile applications.
Instead use Handler in your fragment.
create handler in your fragment
private Handler mHandler = new Handler();
to execute your defined task call
mHandler.postDelayed(mUpdateTask, 1000);
or
mHandler.post(mUpdateTask);
and define your task in the fragment
private Runnable mUpdateTask = new Runnable() {
public void run() {
Toast.makeText(getActivity(), "hello world", Toast.LENGTH_SHORT).show();
mHandler.postDelayed(this, 1000);
}
};
If you are showing time-like information instead of countdown-like one, use
mHandler.removeCallbacks(mUpdateTimeTask);
in onPause() method to stop executing your task if the activity is not visible as updating UI isn't relevant and it saves battery (you start task again in onResume() method)
Basically, the idea behind the timer is eventually I am going to add some tracking into my application and therefore need it to continue running even if the application isn't in the foreground – Disco S2
Based on this comment I suggest you to use a local service which resides in the background, doing it's stuff (start a thread from Service#onStart), until it gets stopped by stopService(..).
Activities on the other hand may bind and unbind to that service (see: bindService(..)) to get notified about updates or to communicate with the service in any way.
I would use a more simple approach by using a Thread:
public class MainActivity extends Activity implements Callback {
private static final int MSG_UPDATE = 1;
private static final long INTERVAL = 1000; // in ms
private final Handler handler = new Handler(this);
private Thread worker;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_UPDATE:
updateView();
return true;
}
return false;
}
private void updateView() {
// TODO tbd
}
#Override
protected void onStart() {
super.onStart();
// start background thread
worker = new Thread(new Runnable() {
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
Thread.sleep(INTERVAL);
} catch (InterruptedException e) {
break;
}
// send message to activity thread
handler.sendEmptyMessage(MSG_UPDATE);
}
}
});
worker.start();
}
#Override
protected void onStop() {
super.onStop();
// stop background thread
worker.interrupt();
try {
worker.join();
} catch (InterruptedException e) {
}
worker = null;
}
}
You can use the TimerTask Class for this. Override the TimerTask.run() method and then add that TimerTask to Timer class.
Also check this question: controlling a task with timer and timertask

Categories

Resources