Android跨多个活动提供全面的防故障音乐服务

Android跨多个活动提供全面的防故障音乐服务,android,service,background,andengine,playback,Android,Service,Background,Andengine,Playback,我知道这个问题以前被问过很多次,可能看起来是几个问题的组合,但我觉得它对许多开发者来说是相关和重要的;我需要创建一个背景音乐服务,它可以在我的Android游戏的多个活动中运行,当应用程序终止并在以下所有情况下暂停时结束: 启动具有自己音乐的特定活动。(此活动完成后继续。这恰好是一个和引擎活动。) 按下主屏幕,应用程序处于后台状态,或应用程序终止。当应用程序返回前台时恢复。需要使用 手机会接到来电并中断应用程序。处理完呼叫后恢复。需要使用与类似的TelephonyManager 屏幕已锁定。(屏

我知道这个问题以前被问过很多次,可能看起来是几个问题的组合,但我觉得它对许多开发者来说是相关和重要的;我需要创建一个背景音乐
服务
,它可以在我的Android游戏的多个活动中运行,当应用程序终止并在以下所有情况下暂停时结束:

  • 启动具有自己音乐的特定
    活动
    。(此
    活动
    完成后继续。这恰好是一个
    和引擎
    活动。)
  • 按下主屏幕,应用程序处于后台状态,或应用程序终止。当应用程序返回前台时恢复。需要使用
  • 手机会接到来电并中断应用程序。处理完呼叫后恢复。需要使用与类似的
    TelephonyManager
  • 屏幕已锁定。(屏幕解锁后恢复。)需要使用,这似乎是
  • 基本上,当应用程序未显示或向用户显示来自#1的特殊活动时,音乐会暂停
  • 以上是我所需要的一切和我拼凑的信息我当前的代码基本类似。

    我觉得奇怪的是,
    AndEngine
    在他们的音乐中没有这些问题,所以也许查找源代码可以帮助人们寻找答案。我正在使用

    关于创建好的音乐
    服务
    ,我也查看了以下链接:

    我希望解决方案
    服务
    能够:

    • 尽可能减少使用
      BroadcastReceivers
      和Android清单添加/权限
    • 自包含和错误检查
    其他注释

    • 目前所有需要背景音乐的活动都扩展了一个普通的特殊类
    • 音乐需要循环,但只运行一个曲目
    提前感谢大家!祝你好运

    编辑-以下是代码片段,请随意改进或忽略:

    媒体播放器包装

    音乐服务

    改进的基本活动类


    首先,这里有一些代码。下面我会给你一个解释

    public class MusicService extends Service {
    
        // service binder
        private final IBinder mBinder = new LocalBinder();
    
        // music player controling game music
        private static CarefulMediaPlayer mPlayer = null;
    
        @Override
        public void onCreate() {
            // load music file and create player
            MediaPlayer mediaPlayer = MediaPlayer.create(this, R.raw.title_music);
            mediaPlayer.setLooping(true);
            mPlayer = new CarefulMediaPlayer(mediaPlayer, this);
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
        }
    
        // =========================
        // Player methods
        // =========================
        public void musicStart() {
            mPlayer.start();
        }
    
        public void musicStop() {
            mPlayer.stop();
        }
    
        public void musicPause() {
            mPlayer.pause();
        }
    
        /**
         * Class for clients to access. Because we know this service always runs in
         * the same process as its clients, we don't need to deal with IPC.
         */
        public class LocalBinder extends Binder {
            MusicService getService() {
                return MusicService.this;
            }
        }
    
        @Override
        public IBinder onBind(Intent arg0) {
            return mBinder;
        }
    
    }
    
    活动:

    public class StartupActivity extends Activity {
    
    // bounded service
    private static MusicService mBoundService;
    
    // whetere service is bounded or not
    private boolean mIsBound;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_startup);
        doBindService();
    
        // HOW TO WORK WITH THE SERVICE:
        // call the following methods whenever
        // you want to interact with you 
        // music player
        // ===================================
    
        // call this e.g. in onPause() of your Activities
        StartupActivity.getService().musicPause();
    
        // call this e.g. in onStop() of your Activities
        StartupActivity.getService().musicStop();
    
        // call this e.g. in onResume() of your Activities
        StartupActivity.getService().musicStart();
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();
        doUnbindService();
    }
    
    private final ServiceConnection mServiceConnection = new ServiceConnection() {
    
        @Override
        public void onServiceConnected(ComponentName className, IBinder service) {
            setService(((MusicService.LocalBinder) service).getService());
        }
    
        @Override
        public void onServiceDisconnected(ComponentName className) {
            setService(null);
        }
    };
    
    private void doBindService() {
        Intent service = new Intent(getBaseContext(), MusicService.class);
        // start service and bound it
        startService(service);
        bindService(new Intent(this, MusicService.class), mServiceConnection, Context.BIND_AUTO_CREATE);
        mIsBound = true;
    }
    
    private void doUnbindService() {
        if (mIsBound) {
            // Detach existing connection.
            unbindService(mServiceConnection);
            mIsBound = false;
        }
    }
    
    public static MusicService getService() {
        return mBoundService;
    }
    
    private static void setService(MusicService mBoundService) {
        StartupActivity.mBoundService = mBoundService;
    }
    }
    
    首先,你有一个在后台运行的服务。此服务会像您一样创建mediaPlayer对象。使用localBinder,您可以在活动中绑定服务,并像普通Java对象一样访问它。 我发布的活动绑定了该服务。在它的onCreate()方法中,您可以找到如何与mediaPlayer交互的方法。 您可以将任何活动绑定到您的服务

    另一个解决方案:

    public class CarefulMediaPlayer {
    final SharedPreferences sp;
    final MediaPlayer mp;
    private boolean isPlaying = false;
    private static CarefulMediaPlayer instance;
    
    public CarefulMediaPlayer(final MediaPlayer mp, final MusicService ms) {
        sp = PreferenceManager.getDefaultSharedPreferences(ms.getApplicationContext());
        this.mp = mp;
        instance = this;
    }
    
    public static CarefulMediaPlayer getInstance() {
        return instance;
    }
    
    public void start() {
        if (sp.getBoolean("com.embed.candy.music", true) && !isPlaying) {
            mp.start();
            isPlaying = true;
        }
    }
    
    public void pause() {
        if (isPlaying) {
            mp.pause();
            isPlaying = false;
        }
    }
    
    public void stop() {
        isPlaying = false;
        try {
            mp.stop();
            mp.release();
        } catch (final Exception e) {}
    }
    }
    

    然后,您可以通过调用CarefulMediaPlayer.getInstance().play()暂停、播放和停止音乐

    在启动活动中,我们分别绑定和启动服务。这是错误的,因为在活动退出后服务将继续运行,因为我们没有在任何地方调用stopService()。因此,应删除“startService(service)”部分,因为绑定服务也已“自动创建”该服务

    如果有人得到相反的结果,请纠正我

    startService(service);// remove this part
    bindService(new Intent(this, MusicService.class), mServiceConnection, Context.BIND_AUTO_CREATE);
    

    我是这样做的,我对结果感到满意:

    第一次创建服务:

    public class LocalService extends Service
    {
        // This is the object that receives interactions from clients. See RemoteService for a more complete example.
        private final IBinder mBinder = new LocalBinder();
        private MediaPlayer player;
    
        /**
         * Class for clients to access. Because we know this service always runs in
         * the same process as its clients, we don't need to deal with IPC.
         */
        public class LocalBinder extends Binder
        {
            LocalService getService()
            {
                return LocalService.this;
            }
        }
    
        @Override
        public void onCreate()
        {
    
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId)
        {
            // We want this service to continue running until it is explicitly stopped, so return sticky.
            return START_STICKY;
        }
    
        @Override
        public void onDestroy()
        {
            destroy();
        }
    
        @Override
        public IBinder onBind(Intent intent)
        {
            return mBinder;
        }
    
    
        public void play(int res)
        {
            try
            {
                player = MediaPlayer.create(this, res);
                player.setLooping(true);
                player.setVolume(0.1f, 0.1f);
                player.start();
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }
        }
    
    
        public void pause()
        {
            if(null != player && player.isPlaying())
            {
                player.pause();
                player.seekTo(0);
            }
        }
    
    
        public void resume()
        {
            try
            {
                if(null != player && !player.isPlaying())
                {
                    player.start();
                }
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }
        }
    
    
        public void destroy()
        {
            if(null != player)
            {
                if(player.isPlaying())
                {
                    player.stop();
                }
    
                player.release();
                player = null;
            }
        }
    
    }
    
    2nd,创建一个基本活动,并扩展您希望播放背景音乐的所有活动:

    public class ActivityBase extends Activity
    {
        private Context context = ActivityBase.this;
        private final int [] background_sound = { R.raw.azilum_2, R.raw.bg_sound_5 };
        private LocalService mBoundService;
        private boolean mIsBound = false;
    
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            doBindService();
        }
    
        @Override
        protected void onStart()
        {
            super.onStart();
    
            try
            {
                if(null != mBoundService)
                {
                    Random rand = new Random();
                    int what = background_sound[rand.nextInt(background_sound.length)];
                    mBoundService.play(what);
                }
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }
        }
    
        @Override
        protected void onStop()
        {
            super.onStop();
            basePause();
        }
    
    
    
        protected void baseResume()
        {
            try
            {
                if(null != mBoundService)
                {
                    mBoundService.resume();
                }
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }
        }
    
    
        protected void basePause()
        {
            try
            {
                if(null != mBoundService)
                {
                    mBoundService.pause();
                }
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }
        }
    
    
    
        private ServiceConnection mConnection = new ServiceConnection()
        {
            public void onServiceConnected(ComponentName className, IBinder service)
            {
                // This is called when the connection with the service has been
                // established, giving us the service object we can use to
                // interact with the service. Because we have bound to a explicit
                // service that we know is running in our own process, we can
                // cast its IBinder to a concrete class and directly access it.
                mBoundService = ((LocalService.LocalBinder) service).getService();
    
                if(null != mBoundService)
                {
                    Random rand = new Random();
                    int what = background_sound[rand.nextInt(background_sound.length)];
                    mBoundService.play(what);
                }
            }
    
            public void onServiceDisconnected(ComponentName className)
            {
                // This is called when the connection with the service has been
                // unexpectedly disconnected -- that is, its process crashed.
                // Because it is running in our same process, we should never
                // see this happen.
                mBoundService = null;
    
                if(null != mBoundService)
                {
                    mBoundService.destroy();
                }
            }
        };
    
        private void doBindService()
        {
            // Establish a connection with the service. We use an explicit
            // class name because we want a specific service implementation that
            // we know will be running in our own process (and thus won't be
            // supporting component replacement by other applications).
    
            Intent i = new Intent(getApplicationContext(), LocalService.class);
            bindService(i, mConnection, Context.BIND_AUTO_CREATE);
            mIsBound = true;
        }
    
        private void doUnbindService()
        {
            if (mIsBound)
            {
                // Detach our existing connection.
                unbindService(mConnection);
                mIsBound = false;
            }
        }
    
    
        @Override
        protected void onDestroy()
        {
            super.onDestroy();
            doUnbindService();
        }
    }
    
    就这样,现在所有从ActivityBase扩展的活动都有了背景声音

    您甚至可以通过调用basePause()/baseResume()来控制暂停/恢复功能

    不要忘记在清单中声明服务:

    <service android:name="com.gga.screaming.speech.LocalService" />
    
    
    
    在每次活动中暂停和恢复MediaPlayer,您就完成了。每当它被打断,音乐就会暂停。您还可以创建一个实现此功能的“抽象”活动类,您的所有活动都将扩展此类。(这是更为elgant的版本)我在以下位置收到一个空指针异常:StartupActivity.getService().musicStart();知道为什么会为空吗?我在StartupActivity.getService().musicStart()上也得到了空值;有人知道为什么会发生这种情况吗?我正在努力实现你的所有目标,我自己也看到了你的问题。有进展吗?当我完成后,我会试着让你知道这是怎么回事。@ajacian81已经有一段时间没有出现在这个网站上了,我们决定推迟播放音乐,并提前发布测试版。好的,我会让你知道我的尝试是怎么回事,我应该在一个月左右得到一些答案。太好了,我会等待的!这对我来说很有用,只是做了一些修改以适应我的代码,谢谢。
    public class LocalService extends Service
    {
        // This is the object that receives interactions from clients. See RemoteService for a more complete example.
        private final IBinder mBinder = new LocalBinder();
        private MediaPlayer player;
    
        /**
         * Class for clients to access. Because we know this service always runs in
         * the same process as its clients, we don't need to deal with IPC.
         */
        public class LocalBinder extends Binder
        {
            LocalService getService()
            {
                return LocalService.this;
            }
        }
    
        @Override
        public void onCreate()
        {
    
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId)
        {
            // We want this service to continue running until it is explicitly stopped, so return sticky.
            return START_STICKY;
        }
    
        @Override
        public void onDestroy()
        {
            destroy();
        }
    
        @Override
        public IBinder onBind(Intent intent)
        {
            return mBinder;
        }
    
    
        public void play(int res)
        {
            try
            {
                player = MediaPlayer.create(this, res);
                player.setLooping(true);
                player.setVolume(0.1f, 0.1f);
                player.start();
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }
        }
    
    
        public void pause()
        {
            if(null != player && player.isPlaying())
            {
                player.pause();
                player.seekTo(0);
            }
        }
    
    
        public void resume()
        {
            try
            {
                if(null != player && !player.isPlaying())
                {
                    player.start();
                }
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }
        }
    
    
        public void destroy()
        {
            if(null != player)
            {
                if(player.isPlaying())
                {
                    player.stop();
                }
    
                player.release();
                player = null;
            }
        }
    
    }
    
    public class ActivityBase extends Activity
    {
        private Context context = ActivityBase.this;
        private final int [] background_sound = { R.raw.azilum_2, R.raw.bg_sound_5 };
        private LocalService mBoundService;
        private boolean mIsBound = false;
    
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            doBindService();
        }
    
        @Override
        protected void onStart()
        {
            super.onStart();
    
            try
            {
                if(null != mBoundService)
                {
                    Random rand = new Random();
                    int what = background_sound[rand.nextInt(background_sound.length)];
                    mBoundService.play(what);
                }
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }
        }
    
        @Override
        protected void onStop()
        {
            super.onStop();
            basePause();
        }
    
    
    
        protected void baseResume()
        {
            try
            {
                if(null != mBoundService)
                {
                    mBoundService.resume();
                }
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }
        }
    
    
        protected void basePause()
        {
            try
            {
                if(null != mBoundService)
                {
                    mBoundService.pause();
                }
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }
        }
    
    
    
        private ServiceConnection mConnection = new ServiceConnection()
        {
            public void onServiceConnected(ComponentName className, IBinder service)
            {
                // This is called when the connection with the service has been
                // established, giving us the service object we can use to
                // interact with the service. Because we have bound to a explicit
                // service that we know is running in our own process, we can
                // cast its IBinder to a concrete class and directly access it.
                mBoundService = ((LocalService.LocalBinder) service).getService();
    
                if(null != mBoundService)
                {
                    Random rand = new Random();
                    int what = background_sound[rand.nextInt(background_sound.length)];
                    mBoundService.play(what);
                }
            }
    
            public void onServiceDisconnected(ComponentName className)
            {
                // This is called when the connection with the service has been
                // unexpectedly disconnected -- that is, its process crashed.
                // Because it is running in our same process, we should never
                // see this happen.
                mBoundService = null;
    
                if(null != mBoundService)
                {
                    mBoundService.destroy();
                }
            }
        };
    
        private void doBindService()
        {
            // Establish a connection with the service. We use an explicit
            // class name because we want a specific service implementation that
            // we know will be running in our own process (and thus won't be
            // supporting component replacement by other applications).
    
            Intent i = new Intent(getApplicationContext(), LocalService.class);
            bindService(i, mConnection, Context.BIND_AUTO_CREATE);
            mIsBound = true;
        }
    
        private void doUnbindService()
        {
            if (mIsBound)
            {
                // Detach our existing connection.
                unbindService(mConnection);
                mIsBound = false;
            }
        }
    
    
        @Override
        protected void onDestroy()
        {
            super.onDestroy();
            doUnbindService();
        }
    }
    
    <service android:name="com.gga.screaming.speech.LocalService" />