воспроизвести mp3 с помощью класса MediaPlayer при проблемах с Android

Что не так с моим кодом? У меня есть кнопка переключения, и я хотел бы воспроизвести/остановить mp3. Я предполагаю, что код должен быть следующим:

package com.android.iFocus;


import android.app.Activity;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ToggleButton;

public class iFocusActivity extends Activity implements OnClickListener {
    public int count;
    MediaPlayer mediaPlayer = MediaPlayer.create(this, R.raw.rain);

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        ToggleButton toggleRain = (ToggleButton)findViewById(R.id.toggleRain);

        //Define Listeners
        toggleRain.setOnClickListener(this);

        count = 0;


    }


    @Override    
    public void onClick(View toggleRain) {


        if(count==0){

            mediaPlayer.start();
            count=1;
        } else {
            //MediaPlayer mediaPlayer = MediaPlayer.create(this, R.raw.rain);
                    mediaPlayer.pause();
            mediaPlayer.stop();
                    mediaPlayer.release();
            count=0;
        }

    }

}

проблема в том, что Eclipse не выдает никаких ошибок, но на эмуляторе/телефоне он дает мне исключение и умирает сразу после запуска. вот оно:

10-02 20:28:24.312: INFO/ActivityManager(59): Starting activity: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.android.iFocus/.iFocusActivity }
10-02 20:28:24.392: DEBUG/AndroidRuntime(960): Shutting down VM
10-02 20:28:24.402: DEBUG/dalvikvm(960): Debugger has detached; object registry had 1 entries
10-02 20:28:24.462: INFO/ActivityManager(59): Start proc com.android.iFocus for activity com.android.iFocus/.iFocusActivity: pid=967 uid=10036 gids={}
10-02 20:28:24.502: INFO/AndroidRuntime(960): NOTE: attach of thread 'Binder Thread #3' failed
10-02 20:28:25.822: DEBUG/AndroidRuntime(967): Shutting down VM
10-02 20:28:25.822: WARN/dalvikvm(967): threadid=1: thread exiting with uncaught exception (group=0x4001d800)
10-02 20:28:25.932: ERROR/AndroidRuntime(967): FATAL EXCEPTION: main
10-02 20:28:25.932: ERROR/AndroidRuntime(967): java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.android.iFocus/com.android.iFocus.iFocusActivity}: java.lang.NullPointerException

Что ж, когда я инициализирую mediaPlayer внутри внутреннего класса onClick, это не дает мне никаких ошибок, и приложение не дает мне никаких ошибок для запуска песни. но не останавливается как надо. Итак, когда я нажимаю на toggleButton, он запускается, когда я нажимаю снова, он ничего не делает, но выдает мне ошибку в журнале cat:

Ошибка при первом нажатии кнопки переключения, и песня запускается нормально (но выдает эту ошибку):

10-02 20:39:02.712: INFO/ActivityManager(59): Start proc com.android.iFocus for activity com.android.iFocus/.iFocusActivity: pid=996 uid=10036 gids={}
10-02 20:39:02.782: INFO/AndroidRuntime(989): NOTE: attach of thread 'Binder Thread #3' failed
10-02 20:39:04.432: INFO/ActivityManager(59): Displayed activity com.android.iFocus/.iFocusActivity: 1804 ms (total 640049 ms)
10-02 20:39:08.672: DEBUG/AudioSink(34): bufferCount (4) is too small and increased to 12
10-02 20:39:08.982: WARN/AudioFlinger(34): write blocked for 73 msecs, 2105 delayed writes, thread 0xb3b8
10-02 20:39:09.682: DEBUG/dalvikvm(437): GC_EXPLICIT freed 686 objects / 38192 bytes in 216ms
10-02 20:39:14.502: WARN/AudioFlinger(34): write blocked for 86 msecs, 2110 delayed writes, thread 0xb3b8
10-02 20:39:14.642: DEBUG/dalvikvm(188): GC_EXPLICIT freed 164 objects / 11408 bytes in 176ms
10-02 20:39:19.622: DEBUG/dalvikvm(261): GC_EXPLICIT freed 43 objects / 1912 bytes in 154ms
10-02 20:39:20.352: WARN/AudioFlinger(34): write blocked for 78 msecs, 2119 delayed writes, thread 0xb3b8

Ошибка, когда я снова нажимаю toggleButton, и песня должна остановиться:

10-02 20:43:22.412: ERROR/MediaPlayer(1032): pause called in state 8
10-02 20:43:22.412: ERROR/MediaPlayer(1032): error (-38, 0)
10-02 20:43:22.412: ERROR/MediaPlayer(1032): stop called in state 0
10-02 20:43:22.412: ERROR/MediaPlayer(1032): error (-38, 0)
10-02 20:43:22.612: WARN/MediaPlayer(1032): mediaplayer went away with unhandled events
10-02 20:43:22.612: WARN/MediaPlayer(1032): mediaplayer went away with unhandled events
10-02 20:43:22.622: WARN/MediaPlayer(1032): mediaplayer went away with unhandled events
10-02 20:43:22.622: WARN/MediaPlayer(1032): mediaplayer went away with unhandled events

person Pabluez    schedule 02.10.2011    source источник


Ответы (3)


Прежде всего, мой анализ: 1. Вы не инициализировали MediaPlayer внутри onCreate():

MediaPlayer mediaPlayer = MediaPlayer.create(this, R.raw.rain);

'this' ‹--- this имеет значение NULL, поэтому у вас есть исключение NullPointerException во время выполнения, время первой загрузки приложения.
2. При втором нажатии на кнопку вы позвонили

mediaPlayer.release();

И в следующий раз, когда вы нажмете, исключение в состоянии MediaPlayer

Что ж, исправление довольно простое, вам нужно учитывать лучшие практики программирования для Android:

package pete.android.study;

import android.app.Activity;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ToggleButton;

public class Main extends Activity implements OnClickListener {
        // declare controls
        public int count = 0;
        MediaPlayer mediaPlayer = null;  
        ToggleButton toggleRain = null;
        /*
         * (non-Javadoc)
         * @see android.app.Activity#onCreate(android.os.Bundle)
         */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            // load layout
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            // load controls
            toggleRain = (ToggleButton)findViewById(R.id.toggleRain);
            // init player
            mediaPlayer = MediaPlayer.create(this, R.raw.rain);
            // set click event handler
            toggleRain.setOnClickListener(this);
            // init state for playing
            count = 0;
        }

        /*
         * (non-Javadoc)
         * @see android.view.View.OnClickListener#onClick(android.view.View)
         */
        @Override    
        public void onClick(View toggleRain) {
            if(count == 0){
                mediaPlayer.start();
                count = 1;
            } else {
                mediaPlayer.pause();                
                count = 0;
            }
        }

        /*
         * (non-Javadoc)
         * @see android.app.Activity#onDestroy()
         */
        @Override
        protected void onDestroy() {
            if(mediaPlayer != null) {
                mediaPlayer.stop();
                mediaPlayer.release();
                mediaPlayer = null;
            }
        }

}

Конечно, это работает как шарм ^^! Однако есть много способов улучшить это простое приложение, я думаю, вы можете узнать об этом, просмотрев справочную документацию разработчиков Android :)

person Pete Houston    schedule 03.10.2011
comment
Работал как шарм! Я сделал только одно улучшение: добавил super.onDestroy() в protected void onDestroy(){} (причина сбоя непосредственно перед закрытием с помощью кнопки «Назад»). я буду продолжать улучшать это, на самом деле это мое первое приложение. :) - person Pabluez; 03.10.2011

Пробовали ли вы перемещать инициализацию внутри onCreate, а не только внутри тела класса? Это будет лучшее место, чтобы сделать это.

Если вы инициализируете внутри onClick, ожидаемая ошибка, которую вы показываете. Это связано с тем, что при каждом щелчке создается новый экземпляр MediaPlayer.

person ghempton    schedule 02.10.2011
comment
да, я пробовал это, но компилятор говорит, что не может разрешить объекты mediaPlayer внутри onClick(). Думаю, мне следует сделать mediaPlayer глобальным (потому что eclipse говорит, что локальный mediaPlayer не используется. Ну, я пробовал много вещей, например, помещать слово mediaPlayer в качестве аргумента onClick (но eclipse говорит, что VariableDeclaratorId ожидается после этого токена). как я могу это сделать ? - person Pabluez; 03.10.2011

Ваша проблема связана с оператором release() здесь:

if(count==0){
    mediaPlayer.start();
    count = 1;
} else {
    //MediaPlayer mediaPlayer = MediaPlayer.create(this, R.raw.rain);
    mediaPlayer.pause();
    mediaPlayer.stop();
    mediaPlayer.release();
    count = 0;
}

Есть несколько способов изменить это, в зависимости от желаемого результата. Если вы просто хотите воспроизвести / приостановить, как вы сказали, вам нужно только удалить вызовы stop() и release(). ОСОБЕННО release(). Этот вызов освобождает аудиоресурсы обратно в систему, а это означает, что вам нужно будет вернуть их в подготовленное состояние, прежде чем вы сможете использовать их снова.

Я настоятельно рекомендую ОЧЕНЬ внимательно прочитать этот справочный документ. Класс MediaPlayer довольно сложен, и такие ошибки легко и часто возникают, когда состояния не управляются должным образом.

person Kevin Coppock    schedule 03.10.2011