如何在Android中更改方向时连续播放音频?

问题描述 投票:15回答:11

我是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();


        }
    } 

}

而且我在Manifest.xml文件中做了一些更改。

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

并创建layout-land文件夹。

为什么音乐播放两次?

android audio android-mediaplayer
11个回答
5
投票

当我们将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();


        }
    } 

}

0
投票

确定要放吗

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

在正确的位置?您必须将其放入播放器的活动中,而不是其他任何活动中或活动之外。作为示例,我在清单中使用了这样的代码:

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

并且它可以工作..希望能对您有所帮助..


0
投票

您需要使用此代码,不要忘了android:configChanges="orientation|screenSize"在清单活动中添加此代码

@Override
public void onConfigurationChanged(Configuration newConfig) {
   super.onConfigurationChanged(
   if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
     //if you are using mediaplayer than u need to mp.getCurrentPosition();
       int currentPosition = vv.getCurrentPosition();
       vv.seekTo(currentPosition);
   }
    else if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        int currentPosition = vv.getCurrentPosition();
        vv.seekTo(currentPosition);  
    }
}

9
投票

此问题的最简单答案。

@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);
}

3
投票

对于这样的任务,您应该使用Service,因为方向改变时不会重新初始化它。


2
投票
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();



}

1
投票

如果活动不在最前面,则媒体播放器也应该播放音乐。因此,最好使用一项服务,该服务与屏幕方向和其他因素无关:

开始仔细阅读http://developer.android.com/guide/components/services.html。特别是START_STICKY对于媒体播放器服务很重要。


1
投票

所以我为此花了很长时间,但是我终于想通了。您要做的是使Mediaplayer成为类的静态成员变量,类似于此处的最佳答案。但是,您要避免的陷阱是使用“便捷” 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()使播放器处于正确的状态,以便可以重新使用。


0
投票

更改方向时,活动被销毁并重新创建。

您可以将视频的实际进度保存在onSaveInstanceState()中,并从捆绑包中获取保存的数据到onRestoreInstanceState()中,之后您可以使用进度数据开始播放,如果没有数据,也可以从头开始播放保存。


0
投票

除了使用“服务”之外,另一种解决方案是在活动中实现“ onOrientationChange”方法。必须将相同的内容应用于活动的清单文件'android:configChanges =“ orientation | keyboardHidden”';您已经完成了。

在'onOrientationChange'方法中。获取当前播放位置并将其分配给媒体播放器对象,然后再次播放。

这样做,将不会创建媒体播放器的新对象,并且将其与当前位置一起使用。


0
投票

因为我也为此问题苦苦挣扎很多次,所以我决定创建一个POC用作参考。本示例使用configChanges标志并手动处理调整大小。效果很好IMHO

https://github.com/caspercba/POCMediaPlayerRotation

© www.soinside.com 2019 - 2024. All rights reserved.