web-dev-qa-db-fra.com

Android MediaPlayer - setDataSource and Release - IllegalStateException

J'ai écrit ma propre classe MediaPlayer pour lire des fichiers sur un chemin spécifique et pour lire des fichiers du dossier des ressources. Voici la classe:

public class CMediaPlayer extends MediaPlayer{

public void play(String audioPath){

   this.setOnCompletionListener(new OnCompletionListener() {
        @Override
        public void onCompletion(MediaPlayer mp) {
            mp.release();
        }
    });

    File f = new File(audioPath);
    if(f.exists()){
        try{
            FileInputStream fis = new FileInputStream(f);
            FileDescriptor fileD = fis.getFD();
            this.setDataSource(fileD);
            this.prepare();

        }catch(IOException e){

        }
       this.start();
}
}

    public void play(AssetFileDescriptor descriptor){

        this.setOnCompletionListener(new OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
               mp.release();
            }
        });
        try {
            this.setDataSource(descriptor.getFileDescriptor(), descriptor.getStartOffset(), descriptor.getLength());
            descriptor.close();
            this.prepare();
        }catch (IOException e){

        }
        this.start();
    }

}

Je veux jouer plusieurs sons avec cette classe d'une activité. Voici mon code:

public class playGame extends Activity {

//a lot of variables

    CMediaPlayer mediaPlayer; //declare my mediaplayer

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK ) {
            //release??????
            Intent myIntent = new Intent(getBaseContext(), startView.class);
            startActivity(myIntent);
        }
        return super.onKeyDown(keyCode, event);
    }

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_play_question2);

        mediaPlayer = new CMediaPlayer(); //define my mediaplayer

       //stuff
    }

    //more variables

    public void playQuestion(File question){

        //stuff

        TextView myTextView = (TextView) findViewById(R.id.textViewQuestion);
        //stuff
        myTextView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
            mediaPlayer.play(pathSoundQuestion); //play sound when clicked
            }
        });

    //stuff

        myImageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
               mediaPlayer.play(pathSoundQuestion); //play sound when clicked
            }
        });

        //stuff
        mediaPlayer.play(pathSoundQuestion); //plays sound immediatly, first played sound (works fine)

        //button1
        Button myButton = (Button) findViewById(R.id.button1);
        //stuff
        myButton.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(lastClickedButton == v){
                   //stuff
                    return;
                }
                //stuff
                mediaPlayer.play(pathAudio1); //play sound when clicked (error)
            }
        });

        //button2
        myButton = (Button) findViewById(R.id.button2);
       //stuff
        myButton.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(lastClickedButton == v){
                    //stuff
                    return;
                }
                //stuff
                mediaPlayer.play(pathAudio2); //play sound, same problem
            }
        });

       //goes on like this some more times...
    }

    public void logIn(View v, String right){
        //stuff

        if(right.equals("true")){
           //stuff
            try {
                AssetFileDescriptor descriptor = getAssets().openFd("Right");
                mediaPlayer.play(descriptor); //play sound from assets
                Intent myIntent = new Intent(getApplication(), playGame.class);
                startActivity(myIntent);
            }catch (IOException e){
            }
        }else{
          //stuff
            try {
                AssetFileDescriptor descriptor = getAssets().openFd("Wrong");
                mediaPlayer.play(descriptor); //play sound from assets
                Intent myIntent = new Intent(getApplication(), playGame.class);
                startActivity(myIntent);
            }catch (IOException e){
            }
        }
    }
}

L'application lit le premier son comme mentionné dans mes commentaires dans mon code. Lorsque je clique sur un bouton qui devrait déclencher un autre son, le message d'erreur suivant s'affiche:

03-16 23:07:38.478  13646-13646/com.example.cello.myownquiz E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Java.lang.IllegalStateException
            at Android.media.MediaPlayer.setDataSource(Native Method)
            at Android.media.MediaPlayer.setDataSource(MediaPlayer.Java:1005)

Ma classe MediaPlayer est-elle correcte ou manque-t-il quelque chose en fonction de l'état? Cette classe est-elle le seul endroit où appeler la libération ou dois-je la mettre quelque part dans mon activité aussi?

Est-ce que quelqu'un voit mon erreur? Ce problème avec le mediaPlayer m'a pris toute une journée d'essayer, j'espère que vous pourrez m'aider ...

11
user3534643

remplacez mp.release(); par mp.reset(); 

public void reset () 

Réinitialise le MediaPlayer à son état non initialisé. Après avoir appelé cette méthode, vous devrez l'initialiser à nouveau en définissant la source de données et en appelant la méthode prepare ().

libération publique publique () 

Libère les ressources associées à cet objet MediaPlayer. Il est recommandé d’appeler cette méthode lorsque vous avez terminé d’utiliser MediaPlayer. En particulier, chaque fois qu’une activité d’une application est suspendue (sa méthode onPause () est appelée) ou arrêtée (sa méthode onStop () est appelée), cette méthode doit être appelée pour libérer l’objet MediaPlayer, sauf si l’application a un besoin particulier de garder l'objet autour . En plus des ressources inutiles (telles que la mémoire et les instances de codecs), l’impossibilité d’appeler cette méthode immédiatement si un objet MediaPlayer n’est plus nécessaire peut également entraîner une consommation de batterie continue pour les périphériques mobiles et une défaillance de lecture pour d’autres applications si aucune plusieurs instances du même codec sont prises en charge sur un périphérique. Même si plusieurs instances du même codec sont prises en charge, une dégradation des performances peut être attendue lorsque plusieurs instances inutiles sont utilisées en même temps. 

Vous devez garder l'objet autour.

Vous pouvez le faire d'une manière simple 

        MediaPlayer mediaPlayer = new MediaPlayer();
        mediaPlayer.setDataSource(context, ringtone);
        mediaPlayer.setAudioStreamType(AudioManager.STREAM_MEDIA);
        mediaPlayer.prepare();
        mediaPlayer.start();
27
Amir

moi aussi j'ai ce problème mais j'ai utilisé:

public void play(String name){
    try {
        AssetFileDescriptor afd = getAssets().openFd(name);
        if(myPlayer == null){
            myPlayer = new MediaPlayer();
        }
        myPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
        myPlayer.prepare();
        myPlayer.start();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

et pour arrêter:

public void stopPlayer(){
    if(myPlayer!= null && myPlayer.isPlaying()){
        myPlayer.stop();
        myPlayer = null;
    }else{
        myPlayer = null;
    }
}
0
Omar Othman