Why does Audio stop playing in app? - java

I have a program that plays a sound every time the user does an action. But after some time none of the audio works.
Sample code :
public void bPressed(View view) {
MediaPlayer mp = MediaPlayer.create(activity.this, R.raw.audio);
mp.start();
}

You need to use mp.release(); When you are done with MediaPlayer:
As an example, consider the problems that could happen if you forgot to release the MediaPlayer when your activity is stopped, but create a new one when the activity starts again. As you may know, when the user changes the screen orientation (or changes the device configuration in another way), the system handles that by restarting the activity (by default), so you might quickly consume all of the system resources as the user rotates the device back and forth between portrait and landscape, because at each orientation change, you create a new MediaPlayer that you never release. (For more information about runtime restarts, see Handling Runtime Changes.)
http://developer.android.com/intl/es/guide/topics/media/mediaplayer.html
add mp.release(); for example in your onStop()

Related

Android: Killing background activities

I have an application that contains many game screens, each is its own activity. Some of these game screens will use timers to initiate some functionality. The problem I am having is when the user backs out of one of these game screens, the timers are still running in the background. I know this because when I leave to the main menu the timer loads up the losing screen because the timer and activity were still running in the background process. I simply want to kill the activity if the user hits the phone back button (Not a button I have created but the devices back button).
This is the current method I use to try and accomplish this:
#Override
public void onBackPressed() {
super.onBackPressed();
this.finish();
}
It does not kill the activity.
EDIT:
I Should mention that stopping the timers does work but for some of my screens the win or lose conditions are done when a variable hits a certain number. For example, I have one screen that when an enemy escapes the view of the player a variable goes up by 1 when this hits 5 the player loses. This is not done on a timer, so because the activity is still running, the variable hits 5 and the losing screen is loaded when I am not on that game screen anymore.
Only the visible Activity will receive that finish() command. You need to start and stop your timers onResume and onPause
First of all, remove
super.onBackPressed();
And add
yourActivity.this.finish();
Let me know if that helps :)

Should I release every time?

I was wondering if releasing my media player before I play a random sound is bad practice:
So I don't usually deal with media output too much, but I am making a simple app that plays a random sound every time a button is clicked (sounds [] is an array filled with raw media files)
public void onClick(View v){
if(mediaplayer != null){
mediaplayer.release();
}
mediaplayer = MediaPlayer.create(this, sounds[randomNum])
mediaplayer.start();
}
So my question is, would releasing my media player every time before creation be considered good/bad practice? Would there be any better way to do this, as releasing and re-initializing the MediaPlayer object seems like it would consume resources...
Thanks,
Ruchir
You typically use release() when you no longer want to use a MediaPlayer any more. Once you call that, it can never be used again. It effectively destroys the native components that back its functionality.
If you do release, you will have to prepare the media all over again the next time you want to play it. This can be a time consuming process. If you want a sound to play responsively to a button press, you probably don't want to have to prepare it each time.

Should I be closing my activities as I go through my app or will this cause Memory Leak? OutOfMemory Errors with drawables in layouts

I am currently developing a game with the android development enviornment. And for the past couple of months I've been dealing with a nasty OOM error. My first problem was that I was placing my drawables in the wrong folder (Drawable-xhdpi in drawable folder). But now, the OOM error eventually happens as you go through the game.
It is a rpg, basically compoed of menus in activity layouts with animations and things. and I've tried everything I could to fix it. I've tried the unbindDrawables method:
unbindDrawables(View view) {
if (view.getBackground() != null) {
view.getBackground().setCallback(null);
}
if (view instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
unbindDrawables(((ViewGroup) view).getChildAt(i));
}
((ViewGroup) view).removeAllViews();
}
}
which does help a lot, but it does not fix the issue. And I cannot use any of the bitmap.factory options or anything, since I load my images through xml in my drawables folder. My images aren't that big by the way, as activities have a background of 720x1280, with some smaller images, and the most total images I'll have on screen at a time is around 8.
So this lead me to think that I may have a memory leak. I did ALOT of research, and I found out that use this(the activity context) will cause a leak, and I should use the application context. However, If I make the switch, there is almost no difference.
So I used MAT to figure out what was going on, and most of my memory is going to byte[], android.graphics.bitmap. And if I drill down to find the cause of this, it seems that java.ref.finalizer is causing all of the retained memory in the VM.
The only reason I could think this is happening, is because whenever I start a new activity I use,
Intent fight = new Intent(this, StartScreen.class);
//add this flag to remove all previous activities
fight.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(fight);
finish();
which opens a new activity, but closes the one we were just in. So, I'm guessing the bitmaps are not being recycled correctly whenever I finish an activity? or is closing and starting activities like this bad for memory?
I've been on Google all day trying to find the solution to this problem and I can't find it. Any soulutions are appreciated, thank you for reading this!
P.S if you would like to see any snippets of my logcat or code or anything, I am more than happy to post it.
P.S P.S My game has about 10-12 different activities I switch between. For example If I have activities A,B,C I open A, Open B close A, Open C close B, open B close C, open A close B.
EDIT: As request about my activities. Usually it is a menu, and when you press a button, that activity finishes, and then moves into another activity. Or buttons will do some math for things like selling, or doing damage to an enemy. One thing about my activity architecture, is that since I am closing every activity as I go to a new one, when I go back to the ones I closed, I am re-creating them. So I don't know if the old activities I finished still have memory in the VM that over time causes the Out Of Memory error, since it all builds up and keeps expanding. I explained My call for a new activity above. And the intent flag closes all past activities (if there are any) in the stack.
EDIT EDIT: As per request my oncreate and onDestroy:
OnCreate:
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start_screen);
//setting fonts
//a function that binds views by findview by Id and then sets their typeface
setFont();
//set up the music service
//connects the app to the background music service
playMusic();
//aquire wakelock
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
OnDestroy:
#Override
public void onDestroy()
{
super.onDestroy();
//unbinds the service
unbindService(musicConnection);
//unbind drawables (function above)
unbindDrawables((LinearLayout) findViewById(R.id.container));
}
you should destroy the activities that you don't need anymore it takes place in the memory. or if you dont want your user/player to go back to the recent activity you should finish the activity. and if you will notice. if you dont finish the activity and press the back button several times it is layered.
second you mentioned that it is a game. in android programming you need to consider your bitmap resources so to avoid getting an OOM error in your game make use of sprite sheet it will save a lot of memory and usage of bitmaps in your application. i encountered those kind of situation and bitmaps mainly causes the OOM error.
I will say it depends. but with your problem your answer is right here
Quick quote from the site
Note: In most cases, you should not explicitly finish an activity using these methods.
As discussed in the following section about the activity lifecycle,the Android
system manages the life of an activity for you, so you do not need to finish your own
activities. Calling these methods could adversely affect the expected user experience
and should only be used when you absolutely do not want the user to return to this
instance of the activity.
Read for more info
well i get you lucidly now, but im thinking of what you are tryna do here, so y dont you use FragmentActivity for B and C.. So, Activity A opens B..B is opened as fragment but works like activity-(thats fragmentActivity), and opens C which is most likely a Fragment..which i think would be perfect for your situation..
for more info about FragmentActivity click Here
no more activities back and forth.. and its gonna work like an activity..

Activity can't be resumed

Over the past months I have been developing a versatile real-time game engine, and I have learned a lot, but I still feel very naive when it comes to the application life cycle. Specifically, I am trying to implement an Activity which can be shuffled in to the background by the user, then properly resumed.
My current architecture is as such: I have a an XML menu launcher activity which can create a real-time Game activity using intent. Relevant data in this Game activity is referenced through static data structures and variables. The Game activity creates worker threads in the onSurfaceCreate() callback of my SurfaceView object.
When a user presses the back button, the activity is destroyed, and they are sent back to the XML menu in the launcher activity. Fine, good for now. When the user presses the home button, the Activity is sent to the background. OK, great. My problems arise when the user tries to find their way back in the Game activity once is has been sent to the background. When the user touches the launcher icon, the Game is destroyed and the menu is re-launched. Also, when the user resumes the game through the task manager, the onSurfaceCreate() callback fires and the worker threads are started, but the game is frozen.
So, I have two questions. First, how do I resume my activity through the launcher icon, instead of re-launching the game? Second, when I resume my activity, what actions are necessary to restart my worker threads while persisting the game data?
Thanks!
EDIT: By request, I am including some code below. My onSurfaceCreate is a little bit complicated, it sends a message to another thread, which then implements the callback. I have verified that this implementation function fires when the Game activity is resumed.
protected void surfaceCreate()
{
Log.e(TAG, "surfaceCreate");
Thread gameThread = createGameThread();
gameThread.start();
}
protected final void onResume()
{
super.onResume();
resume();
}
protected final void onPause()
{
super.onPause();
pause();
}
These cryptic pause() and resume() methods simply set a boolean variable which prevents some game logic from being executed, they do nothing to hinder the worker threads, which should continue looping.
EDIT: Thanks Mohammad, for solving my first (although smaller) problem. It turns out that the launcher icon behaves differently when not connected by USB to the IDE. The second problem remains unresolved.
EDIT: All working! The second problem turned out to be an issue unique to my code, I apologize for that. I hope that this question can still be useful for those dealing with the launcher and IDEs.
There are multiple possible problems/solutions listed in this post. This includes misunderstanding of activity lifecycle and launchMode settings.
First, how do I resume my activity through the launcher icon, instead
of re-launching the game?
You are most likely missing definition for your onResume() and onPause() methods. Examples are here:
http://developer.android.com/training/basics/activity-lifecycle/pausing.html
Straight from the API:
onPause() Called as part of the activity lifecycle when an
activity is going into the background, but has not (yet) been killed.
onResume() Called after onRestoreInstanceState(Bundle),
onRestart(), or onPause(), for your activity to start interacting with
the user.
Check the Android Activity Lifecycle out:
http://developer.android.com/reference/android/app/Activity.html
One theory on your issue may be is that you're most likely going to onStop() (by hitting the home button) and the Android OS is looking for your onRestart(), but can't find it hence freezing/restarting.
Second, when I resume my activity, what actions are necessary to
restart my worker threads while persisting the game data?
Careful how you use the word restart. You want to pause and resume the application (not restart). Save data in onPause() (use a database or any other save feature you'd like). Load data in onResume(). Although, the activity should resume as normal if you just fill up these methods.
Now, if you want to save state for when you restart the application, you should save states in onStop() and/or onDestroy(). You should load states in onStart(). In order to save states, you can check this out:
https://stackoverflow.com/a/151940/2498729
For those using Eclipse (or any other IDE to run/test your application):
From what have you described you probably have overridden
android:launchMode in AndroidManifest.xml or if you are testing by
"run as" from Eclipse try exiting the application after installing and
auto-starting. Then start again from the emulator and test the Home
button behavior. I suppose this is because Android does not put
Activities on the OS stack when started from Eclipse and then the Home
button behavior is not as usual. If this does not solve your problem,
try reading
http://developer.android.com/guide/topics/fundamentals.html#lmodes.
I had launchMode set in my StartupActivity. THen I removed that (it
was set to "singleTask", it behaves like I want it; the app is
"resumed" to the Activity I expect, ie not StartupActivity but
MainActivity.
Source:
https://stackoverflow.com/a/1619461/2498729
http://developer.android.com/guide/topics/manifest/activity-element.html
According to this:
https://stackoverflow.com/a/3002890/2498729
You should change your andoird:launchMode to "Standard" (or "default").
Standard: A > B > HOME > B (what you want)
SingleTask: A > B > HOME > A (what you don't want)

Stop Media Player After starting new intent

Here's my problem: I start a media player, and if I start a new intent, or leave the app and go back to it..
mp.stop;
..wont work (mp is my media player variable).
is there anyway to fix this?
Bonus to whoever can tell me how to link it up to a widget.
You always must call mp.release() in your Activity's onDestroy(). It is also recommended to at least call mp.pause() in on onPause() Activity's method.
If you want playback to continue outside of Activity lifecycle (after onPause()/onStop()/onDestroy()) you have to create Service and play audio content from there.

Categories

Resources