Вопрос по playback, android, service, andengine, background – Комплексный отказоустойчивый музыкальный сервис Android для нескольких видов деятельности

25

Я знаю, что этот вопрос задавался много раз и может показаться совокупностью нескольких вопросов, но я чувствую, что он актуален и важен для многих разработчиков; Мне нужно создать фоновую музыкуService которая может выполнять несколько действий для моей игры для Android, которая заканчивается, когда приложение завершается, и приостанавливается при всех следующих обстоятельствах:

A certain Activity that has its own music is started. (Resume when this Activity finishes. This happens to be an AndEngine activity.) The home screen is pressed and the app is backgrounded, or the application is terminated. Resumes when the app returns to the foreground. Requires use of onUserLeaveHint(). Another helpful link. The phone receives a call and interrupts the app. Resumes when the call has been dealt with. Requires use of TelephonyManager similar to this. The screen is locked. (Resumes after screen has been unlocked.) Requires use of ACTION_USER_PRESENT, which seems to be very problematic. Basically the music pauses whenever the app is not being shown or when the special activity from #1 is being shown to the user.

Выше все, что мне нужно, и информация, которую я собрал воедино.My current code basically resembles этот.

Мне кажется любопытным, чтоAndEngine не удается решить ни одну из этих проблем со своей музыкой, поэтому, возможно, поиск в исходном коде поможет кому-то найти ответ. Я используюпоследняя функциональная версия GLES1 от Google Code.

Я посмотрел также следующие ссылки на создание хорошей музыкиService:

Stopping Background Service Music http://www.codeproject.com/Articles/258176/Adding-Background-Music-to-Android-App Android background music service Playing BG Music Across Activities in Android http://www.rbgrn.net/content/307-light-racer-20-days-61-64-completion

Я хотел бы решениеService чтобы:

Minimize the use of BroadcastReceivers and Android Manifest additions/permissions if possible Self contained and error checking

Другие заметки

Currently all the activities that require the background music all extend a common special class. The music needs to loop but only runs a single track.

Спасибо всем заранее! Удачи!

Редактировать - вот фрагменты кода, которые можно улучшать или игнорировать:

Media Player Wrapper

import android.content.SharedPreferences;
import android.media.MediaPlayer;
import android.preference.PreferenceManager;
import android.util.Log;

public class CarefulMediaPlayer {
    final SharedPreferences sp;
    final MediaPlayer mp;
    private boolean isPlaying = false;

    public CarefulMediaPlayer(final MediaPlayer mp, final MusicService ms) {
        sp = PreferenceManager.getDefaultSharedPreferences(ms.getApplicationContext());
        this.mp = mp;
    }

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

Music Service

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;

public class MusicService extends Service {
    static CarefulMediaPlayer mPlayer = null;

    @Override
    public IBinder onBind(final Intent arg0) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        final MediaPlayer mp = MediaPlayer.create(this, R.raw.title_music);
        mp.setLooping(true);
        mPlayer = new CarefulMediaPlayer(mp,this);
    }

    @Override
    public int onStartCommand(final Intent intent, final int flags, final int startId) {
        mPlayer.start();
        return 1;
    }

    @Override
    public void onStart(final Intent intent, final int startId) {

    }

    public IBinder onUnBind(final Intent arg0) {
        return null;
    }

    public static void onStop() {
        mPlayer.stop();
    }

    public static void onPause() {
        if (mPlayer!=null) {
            mPlayer.pause();
        }
    }

    public static void onResume() {
        if (mPlayer!=null) {
            mPlayer.start();
        }
    }

    @Override
    public void onDestroy() {
        mPlayer.stop();
        mPlayer = null;
    }

    @Override
    public void onLowMemory() {

    }
}

Improved Base Activity Class

import android.app.Activity;
import android.content.Intent;
import android.os.PowerManager;
import android.telephony.TelephonyManager;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.ImageView;

public abstract class BetterActivity extends Activity {

    private boolean isHome = true;

    @Override
    protected void onResume() {
        System.gc();
        super.onResume();
        MusicService.onResume();
        isHome = true;
    }

    @Override
    protected void onPause() {
        if (((TelephonyManager)getSystemService(TELEPHONY_SERVICE)).getCallState()==TelephonyManager.CALL_STATE_RINGING
                || !((PowerManager)getSystemService(POWER_SERVICE)).isScreenOn()) {
            MusicService.onPause();
        }
        super.onPause();
        System.gc();
    }

    @Override
    public boolean onKeyDown (final int keyCode, final KeyEvent ke) {
        switch (keyCode) {
        case KeyEvent.KEYCODE_BACK:
            isHome = false;
        default:
            return super.onKeyDown(keyCode, ke);
        }
    }

    @Override
    public void startActivity(final Intent i) {
        isHome = false;
        super.startActivity(i);
    }

    @Override
    protected void onUserLeaveHint() {
        if (isHome) {
            MusicService.onPause();
        }
        super.onUserLeaveHint();
    }

}
Это здорово, я буду ждать! pqn
@ ajacian81 давно не было на сайте, мы решили отложить музыку и выпустить ее ранее как бета-версию. pqn
Я сам пытаюсь достичь всех ваших целей и вижу ваш вопрос. Какой-либо прогресс? Я постараюсь сообщить вам, как это будет, когда я закончу. ajacian81
хорошо, я дам вам знать, как продвигается моя попытка, у меня должны быть ответы примерно через месяц. ajacian81

Ваш Ответ

3   ответа
5

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 () вы можете найти способ взаимодействия с вашим медиаплеером. Вы можете привязать любое действие к своему сервису.

Другое решение:

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

Внедрите паузу и возобновите MediaPlayer в каждом Activty, и все готово. Всякий раз, когда это прерывается, музыка приостанавливается. Вы также можете создать «абстрактный» класс -Activity-Class, который реализует эту функцию, и все ваши действия будут расширять эту функцию. (это более элегантная версия)
Я получаю исключение нулевого указателя на: StartupActivity.getService (). MusicStart (); Есть идеи, почему это может быть нулевым?
Относится ли это к моим пунктам 2, 3 и 4? pqn
Я также получаю нулевое значение на StartupActivity.getService (). MusicStart (); У кого-нибудь есть решение относительно того, почему это происходит?
2

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создайте базовое действие и расширьте все свои действия, если вы хотите воспроизвести на нем фоновую музыку:

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
    prot,ected 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 wha,t = 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" />
Это сработало для меня с несколькими модификациями в соответствии с моим кодом, спасибо.
0

вильно, так как служба будет продолжать работать после завершения активности, как мы не называлиstopService() в любом месте. Итак, часть & apos; startService (сервис) & apos; должен быть удален, так как служба привязки уже & quot;Auto-Creating& Quot; сервис тоже.

Пожалуйста, поправьте меня, если кто-то получил противоположные результаты

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

Похожие вопросы