Как воспроизводить аудио непрерывно при изменении ориентации в Android?

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

вот мой код:

public class Audio_Activity extends Activity {


MediaPlayer mp = null;


    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        if(isLaunched)
        {
            setContentView(R.layout.audio);
        }

        SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
        length = settings.getInt("TheOffset", 0);
        init();
        prefs = PreferenceManager.getDefaultSharedPreferences(this);
        mp = MediaPlayer.create(getApplicationContext(), R.raw.subhanallah);
        playMusic();


        mp.setOnCompletionListener(new OnCompletionListener() 
        {

            @Override
            public void onCompletion(MediaPlayer arg0) 
            {
                // TODO Auto-generated method stub

            }
        });


    }

    private void playMusic() 
    {
        httpGetAsynchTask httpGetAsyncTask = new httpGetAsynchTask();
        httpGetAsyncTask.execute();
    }



    class httpGetAsynchTask extends AsyncTask<String,Integer, Void>
    {

        protected void onPreExdcute()
        {

        }

        @Override
        protected Void doInBackground(String... arg0)
        {
            // TODO Auto-generated method stub

            final SharedPreferences.Editor prefsEdit = prefs.edit();

            Log.e("Song is playing", "in  Mediya Player ");

            mp.setLooping(false);
            mp.start();
            int millisecond=mp.getDuration();
            Log.e("Song is playing", "in  Mediya Player " + millisecond);

            prefsEdit.putBoolean("mediaplaying", true);
            prefsEdit.commit();
            //btnChapter.setEnabled(false);

            return null;

        }

        protected void onPostExecute(Void result)
        {
            super.onPostExecute(result);
            btnChapter.setEnabled(false);
        }

    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);

        Configuration config=getResources().getConfiguration();
        if(config.orientation == Configuration.ORIENTATION_PORTRAIT)
        {
            setContentView(R.layout.audio);
        }
        else if(config.orientation == Configuration.ORIENTATION_LANDSCAPE)
        {
            setContentView(R.layout.audio);
        }
    }

    @Override
    public void onPause() {
        super.onPause();


        SharedPreferences.Editor prefsEdit = prefs.edit();
        boolean isPlaying = prefs.getBoolean("mediaplaying", false);
        if (isPlaying)
        {
            mp.pause();
            int position = mp.getCurrentPosition();
            Log.e("Current ", "Position -> " + position);
            prefsEdit.putInt("mediaPosition", position);
            prefsEdit.commit();
        }
    }

    @Override
    protected void onResume() {

        super.onResume();

        mp.start();

        boolean isPlaying = prefs.getBoolean("mediaplaying", false);
        if (isPlaying) {
            int position = prefs.getInt("mediaPosition", 0);
            mp.seekTo(position);
            // mp.start();


        }
    } 

}

и я сделал некоторые изменения в манифест.XML-файл.

< android:configChanges="orientation|screenSize|keyboard" >

и создать папку layout-land .

Почему играет музыка дважды?

10 ответов


когда мы объявляем mediaplayer как статическую переменную, тогда будет существовать только один экземпляр mp. Предположим, что наша ориентация активности изменяется сейчас, все будет воссоздано при изменении ориентации, но переменная Mp не будет воссоздана из-за статического свойства. Таким образом, мы просто делаем условие

if(mp!=null && !mp.isPlaying()){ 
    mp = MediaPlayer.create(getApplicationContext(), R.raw.subhanallah);
    playMusic(); 
} 

в нашем методе onCreate() это проверит, играет ли музыка уже или нет, если ее воспроизведение, то если условие не позволит приложению запустить музыкальный плеер снова. и если музыка не играет, то если условие позволит приложению перезапустить музыку.


вот ваш код обновления:

public class Audio_Activity extends Activity {


static MediaPlayer mp = null;


    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        if(isLaunched)
        {
            setContentView(R.layout.audio);
        }

        SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
        length = settings.getInt("TheOffset", 0);
        init();
        prefs = PreferenceManager.getDefaultSharedPreferences(this);
        if(mp == null) 
        {
            initializeMP();
        }
        if(!mp.isPlaying())
        {
             playMusic();
        }

        mp.setOnCompletionListener(new OnCompletionListener() 
        {

            @Override
            public void onCompletion(MediaPlayer arg0) 
            {
                // TODO Auto-generated method stub

            }
        });


    }

    private void playMusic() 
    {
        httpGetAsynchTask httpGetAsyncTask = new httpGetAsynchTask();
        httpGetAsyncTask.execute();
    }

    public void initializeMP()
    {
          mp = MediaPlayer.create(getApplicationContext(), R.raw.subhanallah);

    }

    class httpGetAsynchTask extends AsyncTask<String,Integer, Void>
    {

        protected void onPreExdcute()
        {

        }

        @Override
        protected Void doInBackground(String... arg0)
        {
            // TODO Auto-generated method stub

            final SharedPreferences.Editor prefsEdit = prefs.edit();

            Log.e("Song is playing", "in  Mediya Player ");

            if(mp == null)
            {
                initializeMP()
            }
            mp.setLooping(false);
            mp.start();
            int millisecond=mp.getDuration();
            Log.e("Song is playing", "in  Mediya Player " + millisecond);

            prefsEdit.putBoolean("mediaplaying", true);
            prefsEdit.commit();
            //btnChapter.setEnabled(false);

            return null;

        }

        protected void onPostExecute(Void result)
        {
            super.onPostExecute(result);
            btnChapter.setEnabled(false);
        }

    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);

        Configuration config=getResources().getConfiguration();
        if(config.orientation == Configuration.ORIENTATION_PORTRAIT)
        {
            setContentView(R.layout.audio);
        }
        else if(config.orientation == Configuration.ORIENTATION_LANDSCAPE)
        {
            setContentView(R.layout.audio);
        }
    }

    @Override
    public void onPause() {
        super.onPause();


        SharedPreferences.Editor prefsEdit = prefs.edit();
        boolean isPlaying = prefs.getBoolean("mediaplaying", false);
        if (isPlaying)
        {
            if(mp!=null)
            {
                 mp.pause();
            }
            int position = mp.getCurrentPosition();
            Log.e("Current ", "Position -> " + position);
            prefsEdit.putInt("mediaPosition", position);
            prefsEdit.commit();
        }
    }

    @Override
    protected void onResume() {

        super.onResume();
        if(mp == null)
        {
            initializeMP();
        }
        mp.start();

        boolean isPlaying = prefs.getBoolean("mediaplaying", false);
        if (isPlaying) {
            int position = prefs.getInt("mediaPosition", 0);
            mp.seekTo(position);
            // mp.start();


        }
    } 

}

простой ответ на этот вопрос.

@Override
protected void onSaveInstanceState(Bundle outState) 
{
    outState.putInt("possition", mpbg.getCurrentPosition());
    mpbg.pause();
    super.onSaveInstanceState(outState);
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) 
{
    int pos = savedInstanceState.getInt("possition");
    mpbg.seekTo(pos);
    super.onRestoreInstanceState(savedInstanceState);
}

для таких задач вы должны использовать сервис поскольку он не будет повторно инициализирован при изменении ориентации.


public void onSaveInstanceState(Bundle savedInstanceState) {

    super.onSaveInstanceState(savedInstanceState);

    savedInstanceState.putInt("Position", mediaPlayer.getCurrentPosition());
    savedInstanceState.putBoolean("isplaying", mediaPlayer.isPlaying());

     if (mediaPlayer.isPlaying())
          mediaPlayer.pause();

}


@Override

public void onRestoreInstanceState(Bundle savedInstanceState) {

    super.onRestoreInstanceState(savedInstanceState);

    position = savedInstanceState.getInt("Position");
    mediaPlayer.seekTo(position);
     if (savedInstanceState.getBoolean("isplaying"))
         mediaPlayer.start();



}

медиа-плеер должен играть музыку, если активность не на высоте. Поэтому вам лучше использовать сервис, который не зависит от ориентации экрана и прочим:

начать чтение http://developer.android.com/guide/components/services.html осторожно. Особенно START_STICKY важно для службы медиаплеера.


поэтому я боролся с этим довольно долго, но я, наконец, понял это. То, что вы хотите сделать, это сделать ваш Mediaplayer статической переменной-членом класса, аналогично верхнему ответу здесь. Однако ловушка, которую вы хотите избежать, использует метод" convenient " create (). Это фактически создает новый экземпляр mediaplayer каждый раз, когда он вызывается, даже если он статичен. Вместо этого вы хотите сделать что-то вроде этого:

static MediaPlayer m = new MediaPlayer();

теперь, где в вашем коде вы хотите чтобы создать плеер, сделайте что-то вроде этого:

m.reset();

try{
        m.setDataSource(getApplicationContext(),Uri.parse("android.resource://com.example.app/" + R.raw.soundId));
        m.prepare();

}catch(java.io.IOException e){ }

m.seekTo(pos);
m.start();

дело в том, что create (), хотя и удобно, действительно приятно, когда вы никогда не меняете ориентацию, потому что он будет продолжать создавать новые экземпляры и быстро использовать память. Создание одного статического элемента и повторное его использование при каждом вызове onCreate () намного чище и проще. Reset() переводит плеер в правильное состояние для повторного использования.


при изменении ориентации активность уничтожается и воссоздается.

вы можете сохранить фактический прогресс видео в onSaveInstanceState () и получить сохраненные данные в onRestoreInstanceState () из пакета, после чего вы можете начать воспроизведение либо с данными прогресса, либо с самого начала, если не было сохраненных данных.


Помимо использования "службы", еще одним решением было бы реализовать метод "onOrientationChange" в вашей деятельности. То же самое должно применяться к файлу манифеста действия как 'android: configChanges= "orientation / keyboardHidden"; что вы уже сделали.

в методе "onOrientationChange". получите текущую позицию воспроизведения и дайте это объекту media player и играйте снова.

делая это, он не будет создавать новый объект media player и использует то же самое с текущей позиции.


поскольку я также много раз боролся с этой проблемой, я решил создать POC для использования в качестве ссылки. В этом примере используется configChanges флаг и обрабатывает изменение размеров вручную. Он работает довольно хорошо IMHO

https://github.com/caspercba/POCMediaPlayerRotation


вы уверены, что вы положили

< android:configChanges="orientation|screenSize|keyboard" >

в нужном месте? вы должны положить его в деятельности вашего игрока не любой другой деятельности или вне деятельности.. В качестве примера я использовал его так в своем манифесте:

<activity android:name=".PlayerActivity" android:label="@string/title_activity_player" android:noHistory="true" android:configChanges="orientation|screenSize"> </activity>

и это работает.. надеюсь, это поможет..