Android comprehensive failproof music service across multiple activities

前端 未结 3 1497
野的像风
野的像风 2020-12-24 02:17

I know this question has been asked many times before and might seem to be a conglomeration of several questions, but I feel that it is relevant and important to many develo

相关标签:
3条回答
  • 2020-12-24 02:47

    First here is some code. Below I'll give you an explanation.

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

    Activity:

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

    First of all you got a Service which runs in background. This service creates the mediaPlayer object as you did. With the localBinder you can bind the Service in your Activity(ies) and access it like a normal Java-Object. The Activity I've posted bindes the Service. In it's onCreate() method you can find a way how to interact with your mediaPlayer. You can bind any Activity to your Service.

    Another Solution:

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

    Then you can pause, play and stop the music by calling CarefulMediaPlayer.getInstance().play();

    0 讨论(0)
  • 2020-12-24 02:57

    In the startup activity we are binding and Starting Service seperately. This is wrong since service will keep running after activity exits as we haven't called stopService() anywhere. So The part ' startService(service) ' should be removed as bind service is already "Auto-Creating" the service too.

    Please correct me if anyone got opposite results

    startService(service);// remove this part
    bindService(new Intent(this, MusicService.class), mServiceConnection, Context.BIND_AUTO_CREATE);
    
    0 讨论(0)
  • 2020-12-24 03:04

    I did it this way and I'm pleased with the result:

    1st create the service:

    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, create a base activity and extend all your activities in witch you wish to play the background music from it:

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

    And that's it, now you have background sound in all the activities that are extended from ActivityBase.

    You can even control the pause / resume functionality by calling basePause() / baseResume().

    Don't forget to declare the service in manifest:

    <service android:name="com.gga.screaming.speech.LocalService" />
    
    0 讨论(0)
提交回复
热议问题