如何在Android中实现音频连续播放,即使屏幕方向改变?

16

我是 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 文件夹。

为什么音乐会播放两次?

11个回答

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

4

当我们将mediaplayer声明为静态变量时,只会存在一个mp实例。假设我们的Activity方向发生了改变,现在所有内容都将被重新创建,但由于静态属性,Mp变量不会被重新创建。通过这种方式,我们只需设置一个条件。

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

在我们的onCreate()方法中,这将检查音乐是否已经在播放,如果正在播放,则if条件将不允许应用程序再次启动音乐播放器。如果音乐没有播放,那么if条件将允许应用程序重新启动音乐。
以下是更新后的代码:
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();


        }
    } 

}

1
它是类未找到异常,请检查在src文件夹中Audio_Activity是否正确拼写,并检查它的manifest.xml。 - Ahmad Raza
1
请确认包名与manifest.xml中定义的名称相似,并检查包名是否正确。 - Ahmad Raza
1
请在此处发布您的manifest.xml文件。谢谢。 - Ahmad Raza
1
是的,没错,现在请检查您的包名。您的包名应该是“com.tutorialmediaplayer”,在这个包中放置这个活动“Audio_Activity”。 - Ahmad Raza
1
你应该创建一个新项目。在创建新项目时,将活动名称设置为“Audio_Activity”,将布局放置在布局文件中,并将我的代码简单地放置在“Audio_Activity.java”中。 - Ahmad Raza
显示剩余10条评论

3

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


3

所以我花了很长时间来解决这个问题,但最终我弄清楚了。你想要做的是将你的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()将玩家置于正确的状态,以便重新使用。


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
你确定你输入了

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

放置位置正确吗? 您必须将它放在您的播放器活动中,而不是任何其他活动或活动外部。 例如,我在清单中使用它:

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

它会起作用的..希望这有所帮助..


1

您需要使用此代码,并不要忘记在清单活动中添加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);  
    }
}

android:configChanges="orientation|screenSize" =我已将此代码添加到清单文件中的相关活动中。当屏幕在播放声音时改变方向时,声音仍然会继续流动。 - serif

0

因为我也曾经遇到过这个问题,所以我决定创建一个 POC 作为参考。这个例子使用了 configChanges 标志并手动处理了调整大小。在我看来它运行得相当不错。

https://github.com/caspercba/POCMediaPlayerRotation


0

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

您可以在onSaveInstanceState()中保存视频的实际进度,并从Bundle中在onRestoreInstanceState()中获取保存的数据,之后您可以使用进度数据开始播放,或者如果没有保存数据,则从开头开始播放。


我怎样才能知道在竖屏模式下是否需要播放视频...因为如果用户在横屏模式下暂停了视频,则应该保持暂停状态,而如果视频正在播放,则应该继续播放... - Erum

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接