25

この質問は以前に何度も出されており、いくつかの質問が寄せ集められているように思えるかもしれませんが、多くの開発者にとって関連性があり、重要であると感じています。Serviceアプリケーションが終了すると終了し、次のすべての状況で一時停止する Android ゲームの複数のアクティビティで実行できるバックグラウンド ミュージックを作成する必要があります。

  1. Activity独自の音楽を持っているとあるが開始されます。(これが終わったら再開Activity。たまたまAndEngineアクティビティです。)
  2. ホーム画面が押されてアプリがバックグラウンドになっている、またはアプリが終了している。アプリがフォアグラウンドに戻ると再開します。の使用が必要ですonUserLeaveHint()別の役立つリンク。
  3. 電話が着信し、アプリが中断されます。コールが処理されると再開します。これTelephonyManagerに似たものを使用する必要があります。
  4. 画面がロックされています。(画面のロックが解除された後に再開します。) を使用するACTION_USER_PRESENT必要 あり ます
  5. 基本的に、アプリが表示されていないとき、または #1 の特別なアクティビティがユーザーに表示されているときはいつでも音楽が一時停止します。

以上が、私が必要とするすべてのものと、私がまとめた情報です。私の現在のコードは基本的にこれに似ています。

彼らの音楽にこれらの問題がまったくないことに興味があるAndEngineので、ソースコードを調べると、答えを探している人に役立つかもしれません. Google Code の最後の機能 GLES1 バージョンを使用しています。

良い音楽を作成する方法については、次のリンクも参照してくださいService

次の解決策を希望Serviceします。

  • BroadcastReceivers可能であれば、Android マニフェストの追加/権限の使用を最小限に抑える
  • 自己完結型およびエラー チェック

その他の注意事項

  • 現在、バックグラウンド ミュージックを必要とするすべてのアクティビティは、すべて共通の特別なクラスを拡張しています。
  • 音楽はループする必要がありますが、1 つのトラックしか実行しません。

みなさん、お早めにどうぞ!頑張ってください!

編集 - コード スニペットは次のとおりです。自由に改善または無視してください。

メディア プレーヤー ラッパー

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

音楽サービス

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

    }
}

改善されたベース アクティビティ クラス

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

}
4

3 に答える 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;
}
}

まず、バックグラウンドで実行される Service を取得します。このサービスは、行ったように 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(); を呼び出して、音楽を一時停止、再生、停止できます。

于 2012-07-25T08:40:30.547 に答える
2

私はこの方法でそれを行い、結果に満足しています:

最初にサービスを作成します。

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

}

2番目に、ベースアクティビティを作成し、そこからバックグラウンドミュージックを再生したい魔女のすべてのアクティビティを拡張します:

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" />
于 2014-04-23T19:55:41.827 に答える
0

スタートアップ アクティビティでは、サービスを個別にバインドして開始します。stopService()をどこにも呼び出していないため、アクティビティが終了した後もサービスが実行され続けるため、これは間違っています。そのため、「 startService(service) 」の部分は削除する必要があります。バインド サービスも既に「自動作成」されているためです。

誰かが反対の結果を得た場合は、私を修正してください

startService(service);// remove this part
bindService(new Intent(this, MusicService.class), mServiceConnection, Context.BIND_AUTO_CREATE);
于 2013-11-22T18:18:55.203 に答える