I'm really new at java and android and I'm trying to play some sound after a button is pressed. I searched a lot and tried this:
//package and imports
public class Simulador extends Activity {
int contador;
Button somar;
SoundPool som;
boolean loaded;
int comeu, comprou;
protected void onCreate(Bundle primeiroBundle) {
super.onCreate(primeiroBundle);
setContentView(R.layout.activity_primeira_atividade);
contador = 0;
somar = (Button) findViewById(R.id.som);
som = new SoundPool(2, AudioManager.STREAM_MUSIC, 0);
//I removed the whole part from the other button,
//since it's basically the same. So that's why I need to set maxStreams to 2.
comeu = som.load(this, R.raw.comeu, 1);
som.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
public void onLoadComplete(SoundPool som, int sampleId, int status){
loaded = true;
}
});
somar.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (loaded) {
som.play(comprou, 1, 1, 1, 0, 1f);
}
contador += 5;
}
}
});
}
protected void onPause() {
super.onPause();
som.release();
som = null;
}
}
My code is working as it should, but I got the follwing warning:
SoundPool(int, int, int)' is deprecated
So I came here to see how to solve and got this:
This constructor was deprecated in API level 21. use SoundPool.Builder instead to create and configure a SoundPool instance
So I went here but couldn't addapt my code to this new constructor, even reading the reference. Does anyone know how to solve this?
I know this question is a couple years old and You've probably already solved this, but hopefully this answer can help others.
For those whom are concerned about backwards compatibility in android versions and want to have the best of both worlds, here is a possible implementation that I've done.
In the onCreate() function where you instantiate your SoundPool object, write a logic check for the android version and use the respective constructor.
// For ADK versions 21 (Lollipop) or greater
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
sounds = new SoundPool.Builder().build();
// Else use older syntax (deprecated with ADK 21)
} else {
sounds = new SoundPool(1, AudioManager.STREAM_MUSIC, 0);
}
Note: this will technically still throw a warning in your IDE for using the deprecated method, but if you are concerned about APKs bellow 21, this may be the best option for you.
After you have instantiated it, simply load your sound files, and play the sound (call the bellow playSound() method in the onClick() listener on your button):
soundId = sounds.load(context, R.raw.sound, 1);
public void playSound() {
sounds.play(soundId, 1, 1, 1, 0, 1);
}
Related
So I understand the basics of java programming but when I'm trying to use my little knowledge in android studio it make everything harder having classes and different files needing to be referenced. Coming from python, when making a simple game I would define different functions, then run them in a game loop like
while running:
or something similar. I know to define something in java you go like
public void Example() {}
but when I use this in java, when I try to run the program my game either instantly crashes or doesnt load anything.
The code at the moment is
public class MainActivity extends AppCompatActivity {
//Variables
Boolean running = true;
public int years = 0;
//Setup Year Counter
TextView textView = (TextView) findViewById(R.id.year_counter);
//Advance Button
public void advance() {
ImageButton button = (ImageButton) findViewById(R.id.advance);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
years += 1;
textView.setText("" + years + "");
}
});
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Game Loop
while (running) {
advance();
}
}
}
And this results in the app not opening.
Any help at all would mean a lot to me.
Thanks in advance :)
Although I don't actually see a crash, since you didn't really upload one, I can see why you might think your app wont work.
What you are doing constantly in the while loop is that you are only setting the button's click listener over and over again.
public class MainActivity extends AppCompatActivity {
//Variables
Boolean running = true;
public int years = 0;
//Setup Year Counter
TextView textView;
ImageButton button;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// you set up your views once, after the layout is inflated
setUpViews();
// you initialize your buttons functionality
initClickEvents();
//Game Loop
while (running) {
// do other stuff
}
}
private void setUpViews() {
textView = (TextView) findViewById(R.id.year_counter);
button = (ImageButton) findViewById(R.id.advance);
}
private void initClickEvents() {
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
years += 1;
textView.setText("" + years + "");
}
});
}
}
I'd recommend working with a game engine.
If you want to stick with java, libGDX is an option.
But if language (and IDE) doesn't matter, than a better option is Godot. The reason why I recommend Godot over some of the more popular game engines is because it's open source, 100% free and plus GDScript (godot's scripting language) is heavily influenced by python.
If you want to make you own game engine in java check out this: https://java-design-patterns.com/patterns/game-loop/#
Keep in mind that the while loop is calling the advance method. So every loop you are setting the view for button and then setting an OnClickListener for it. Not everything needs to be in the while loop.
You must implement (override) the render method (it is called in the game loop).
I suggest trying a complete example in the documentation.
``
#Override
public void render() {
ScreenUtils.clear(0, 0, 0.2f, 1);
advance();
...
``
I have a custom view (PieView) that is has a rotating animation. Now I would like to play tick tick tick tick... sound synchronously with the rotation speed (that is, when the rotation speed is fast, the tick tick should be fast, when rotation is slow, the tick tick should be slow).
To do this, first I created an mp3 file named magicbox_tick.mp3 that has only ONE (1) tick. Next I tried to play the sound with Animation.setUpdateListener().
First I tried to play music with MediaPlayer but after some 10 or 15 ticks, it stoped. So now I am trying SoundPool to play the music.
The relevant code segment looks like this:
public PieView extends View {
// ... constructors, other methods etc
private SoundPool soundPool;
private int soundId;
void init(){ // called inside those constructors
SoundPool soundPool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);
soundId = soundPool.load(getContext(), R.raw.magicbox_tick, 1);
}
public void rotateTo(){
animate()..setInterpolator(new DecelerateInterpolator())
.setDuration(mDuration)
.setListener(someListener)
.rotation(targetAngle)
.setUpdateListener(animation -> {
myPlaySound(); // <----------------------- This is the sound playing code
})
.start();
}
void myPlaySound(){
soundPool.play(soundId, 1, 1, 0, 0, 1); // this doesnot play the `tick` sound
// previously I used MediaPlayer like this:
/*
MediaPlayer mp = new MediaPlayer.create(getContext(), R.raw.magicbox_tick);
mp.play();
// these 2 line, after some 10 ticks, stopped working.
*/
}
}
I have never done anything like this, and I don't know how to fix this. Can anyone help me?
Please note that I am open to all answers as long as it works. You don't have to use SoundPool. So suppose if you can make it work with android MediaPlayer, I am ok with that.
Special thanks to Mr Mike M for his valuable comment. I was able to fix it using MediaPlayer. MediaPlayer.release() method should be called. And to make the sound synced with the angular motion, I kept an if block that checks if the rotation dTheta is greater than tolerance angle.
So, if anyone needs it, the complete code looks like this:
public PieView extends View{
private float omega0; // holds the previous rotation
/**
* #brief: plays a music using mediaPlayer
* #input:
* #output: void, plays a music
* */
private void myPlayTick() {
float omega1 = Math.abs(getRotation());
float dOmeda = 0;
if(omega1>omega0){
dOmeda = omega1 - omega0;
}else{
dOmeda = omega0-omega1;
}
if(dOmeda > threshold){
omega0 = omega1; // update previous rotation
final MediaPlayer mp = MediaPlayer.create(getContext(), R.raw.magicbox_tick);
mp.start();
mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
releaseMediaPlayer(mp);
}
});
}
}
/**
* #brief: releases mediaPlayer resource so that other mediaPlayers can use sound hardware resources
* #input: MediaPlayer object
* #output: void
* */
private void releaseMediaPlayer(MediaPlayer mediaPlayer) {
try {
if (mediaPlayer != null) {
if (mediaPlayer.isPlaying())
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void rotateTo(){
animate()..setInterpolator(new DecelerateInterpolator())
.setDuration(mDuration)
.setListener(someListener)
.rotation(targetAngle)
.setUpdateListener(animation -> {
myPlayTick();
})
.start();
}
// ... rest of the code, such as constructors, etc
}
Hi guys
I've been looking around but cannot seem to find a suitable answer to integrate into my function. I am basically using the following code currently:
private void sayHello(String timeString) {
textToSpeech.speak(timeString,
TextToSpeech.QUEUE_FLUSH,
null);
}
This code works fine but it's too loud and it can only be controlled by the volume of the device itself. I want to be able to adjust/hardcode/be able to use spinner to control the volume of the TTS but cannot seem to do so accordingly.
Is this functionality available for this library? Is it achievable?
I've also tried to implement the following into my code:
KEY_PARAM_VOLUME
However, I cannot see any examples of this being used and it's showing up with the error to create a function. Any advice?
public class MainActivity extends AppCompatActivity {
int androidAPILevel = android.os.Build.VERSION.SDK_INT;
TextToSpeech tts;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tts = new TextToSpeech(this, new TextToSpeech.OnInitListener() {
#Override
public void onInit(int i) {
start();
}
});
}
private void start() {
if (androidAPILevel < 21) {
HashMap<String,String> params = new HashMap<>();
params.put(TextToSpeech.Engine.KEY_PARAM_VOLUME, "0.5"); // change the 0.5 to any value from 0-1 (1 is default)
tts.speak("This is a volume test.", TextToSpeech.QUEUE_FLUSH, params);
} else { // android API level is 21 or higher...
Bundle params = new Bundle();
params.putFloat(TextToSpeech.Engine.KEY_PARAM_VOLUME, 0.5f); // change the 0.5f to any value from 0f-1f (1f is default)
tts.speak("This is a volume test.", TextToSpeech.QUEUE_FLUSH, params, null);
}
}
}
I have been stuck on this for over an hour now. In my main menu screen, I have a mute button. I want it to call a method in my background service, which mutes all of the MediaPlayer audio.
Here I am calling mute:
public void mute(View view){
mutebutton = (ImageButton) findViewById(R.id.mutebutton);
currentVolume = manager.getStreamVolume(AudioManager.STREAM_MUSIC);
if (currentVolume == 0) {
TwentySeconds.unMute();
Toast.makeText(Main_Menu.this, "UNMUTED", Toast.LENGTH_SHORT).show();
} else {
TwentySeconds.mute();
Toast.makeText(Main_Menu.this, "MUTED", Toast.LENGTH_SHORT).show();
}
Here are the methods in the service:
public static void mute(){
ten.setVolume(0, 0);
three.setVolume(0, 0);
}
public static void unMute(){
ten.setVolume(1, 1);
three.setVolume(1, 1);
}
Here are the actual media players, which play at intervals:
static `MediaPlayer` ten;
static `MediaPlayer` three;
The problem is, I am getting a null pointer exception here:
currentVolume = manager.getStreamVolume(AudioManager.STREAM_MUSIC);
By the way, manager is instantiated like so:
AudioManager manager;
and later on:
manager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
I would really appreciate any feedback (positive or negative)! Thank you so much for all of your help, let me know if you need any more code.
{Rich}
Your "manager" should instantiated like this:
AudioManager manager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
If this is still a nullpoint, add
Context context = this;
before your instantiation. Try it, wish I can help you.
We are trying to use a VideoView to play a video in an Android Activiy.
I've read the MediaPlayer documentation and studied its state diagram.
We get a Media Player error if we call this method:
MediaPlayer.setLooping()
from this listener method:
MediaPlayer.OnPreparedListener.onPrepared()
The error message from LogCat:
error (-38, 0)
Note:
We have tested on two physical devices and this only happens on our Motorola Xoom.
If I comment out this line: mp.setLooping(false); everything works fine on the Xoom.
(see code below)
According to the documentation, setLooping() can be called from the following Media Player states:
Idle
Initialized
Stopped
Prepared
Started
Paused
PlaybackCompleted
Although the documentation also includes this seemingly contradictory statement:
It is a programming error to invoke methods such as getCurrentPosition(), getDuration(), getVideoHeight(), getVideoWidth(), setAudioStreamType(int), setLooping(boolean), setVolume(float, float), pause(), start(), stop(), seekTo(int), prepare() or prepareAsync() in the Idle state...
Question 1:
Why can't we call setLooping() from onPrepared()?
Question 2:
Shouldn't the VideoView be handling the preparation of the underlying MediaPlayer?
Question 3:
Shouldn't the MediaPlayer be in its prepared state when onPrepared() is invoked?
Question 4:
How do I resolve the statements in the documentation that seem to contradict each other?
What really confuses me:
The quote above says none of these methods should be called when the MediaPlayer is in its idle state:
getCurrentPosition()
getDuration()
getVideoHeight()
getVideoWidth()
setAudioStreamType(int)
setLooping(boolean)
setVolume(float
float)
pause()
start()
stop()
seekTo(int)
prepare()
prepareAsync()
This statement (along with our error message) makes me think our error occurs because the MediaPlayer has not been successfully prepared.
But, for some reason there is no problem calling setAudioStreamType().
Question 5:
Why is there a problem with setLooping() but not with setAudioStreamType()?
Both methods are in the list of forbidden methods above.
(That said, I would've thought both are valid in the onPrepared() method...)
What am I missing?
Is there a bug with the Motorola Xoom?
I'd be happy to just get an answer to question 1, but I'm really perplexed by all of this.
I'll admit I'm pretty new to Android development...
Our Xoom is running Ice Cream Sandwich 4.0.4.
Here's some sample code:
class VideoActivity {
VideoView mVidView;
#Override
protected void onCreate(Bundle b) {
mVidView = new VideoView(this);
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(mWidth, mHeight);
mVidView.setLayoutParams(params);
mVidView.setVideoURI(mUri);
mVidView.setZOrderOnTop(true);
mMediaController = new MediaController(this, true);
mMediaController.setAnchorView(null);
mVidView.setMediaController(mMediaController);
mVidView.setOnErrorListener(new MediaPlayer.OnErrorListener() {
public boolean onError(MediaPlayer mp, int what, int extra) {
.
.
.
}
});
mVidView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
.
.
.
}
});
mVidView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
public void onPrepared(MediaPlayer mp) {
mDialog.dismiss();
mMediaPlayer = mp;
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
mp.setLooping(false);
mp.setScreenOnWhilePlaying(true);
mp.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener() {
public void onSeekComplete(MediaPlayer mp) {
mp.start();
}
});
if (mTimecode > 0) {
mp.seekTo(mTimecode * ONE_SEC);
} else {
mp.start();
}
mMediaController.show(0);
}
});
LinearLayout ll = (LinearLayout) this.findViewById(R.id.parentpopup);
ll.addView(mVidView);
}
}