Как непрерывно воспроизводить музыку в фоновом режиме через приложение?

У меня есть 4 действия в моем приложении для Android. Когда создается первое действие, оно запускает музыку в фоновом режиме. Теперь, когда пользователь переходит от 1-го действия ко 2-му действию, я хочу, чтобы песня продолжалась без перерыва. Песня должна останавливаться только тогда, когда пользователь выходит из приложения.

Сейчас музыка останавливается, когда я заканчиваю одно занятие, и начинается с начала следующего занятия.


person hibafebin    schedule 17.04.2014    source источник
comment
Я бы использовал локальную связанную службу: developer.android.com/guide/components/services. html   -  person Ken Wolf    schedule 17.04.2014
comment
тогда вы должны реализовать Service и управлять экземпляром MediaPlayer оттуда   -  person M D    schedule 17.04.2014
comment
возможный дубликат службы фоновой музыки Android   -  person Snicolas    schedule 17.04.2014
comment
@KenWolf Я не думаю, что вам следует использовать bindService. Он будет уничтожен, когда вы отвяжетесь от него. Вы могли бы лучше использовать startService (а затем привязаться к нему).   -  person RvdK    schedule 17.04.2014
comment
@RvdK Технически это все равно будет связанная служба, потому что вы привязываетесь к ней и вызываете общедоступные методы. Вы просто не запустили его через бинд. Но я с тобой согласен :)   -  person Ken Wolf    schedule 17.04.2014
comment
Действительно, для реального музыкального приложения лучше всего не привязываться, так как это будет означать, что сервис будет в том же процессе, что и приложение, что будет тяжело. Было бы лучше иметь процесс только с сервисом, тогда взаимодействие с ним можно было бы осуществлять через намерения.   -  person Snicolas    schedule 17.04.2014


Ответы (3)


Держите проигрыватель в фоновом режиме в качестве статической ссылки. Затем дайте ему знать, если вы двигаетесь в приложении или вне его. Вот как бы я это сделал. Для этой цели я использую класс с именем DJ.

public class DJ { 
private static MediaPlayer player;
private static boolean keepMusicOn;

public static void iAmIn(Context context){
if (player == null){
player = MediaPlayer.create(context, R.raw.music1);
player.setLooping(true);

try{
player.prepare();
}
catch (IllegalStateException e){}
catch (IOException e){}
}

if(!player.isPlaying()){
player.start();
}

keepMusicOn= false;
}

public static void keepMusicOn(){
keepMusicOn= true;
}

public static void iAmLeaving(){

if(!keepMusicOn){
player.pause();
}
}
}

Теперь из своей активности позвоните диджею вот так. (Сообщите ему, хотите ли вы оставить музыку включенной)

public void onPause() {
super.onPause();
DJ.iAmLeaving();
}

public void onResume(){
super.onResume();
DJ.iAmIn(this); 
}

public void buttonOnClick(View view){
DJ.keepMusicOn();
Intent intent = new Intent(this, TheOtherActivity.class);
startActivity(intent);
}
person febinkk    schedule 17.04.2014

Я сделал так и результатом доволен:

Сначала создайте службу:

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

И все, теперь у вас есть фоновый звук во всех действиях, расширенных из ActivityBase.

Вы даже можете управлять функциями паузы/возобновления, вызывая basePause()/baseResume().

Не забудьте объявить сервис в манифесте:

<service android:name="com.gga.screaming.speech.LocalService" />
person Goran Horia Mihail    schedule 23.04.2014

Идея состоит в том, что вы не должны воспроизводить музыку из самого действия. В Android действия и другие контексты имеют жизненные циклы. Это значит, что они будут жить... и умрут. И когда они мертвы, они больше ничего не могут сделать.

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

Самое простое решение — сервис Android. Здесь вы можете найти хорошую тему: Служба фоновой музыки для Android

person Snicolas    schedule 17.04.2014