我知道这个问题之前已被问过很多次,似乎是几个问题的集合,但我觉得这对很多开发人员来说都很重要;我需要创建一个背景音乐Service
,它可以在Android游戏的多个活动中运行,在应用程序终止时结束,并在以下所有情况下暂停:
Activity
。 (当Activity
完成时恢复。这恰好是AndEngine
活动。)onUserLeaveHint()
。 Another helpful link. TelephonyManager
。ACTION_USER_PRESENT
,be very problematic。以上是我需要的所有内容以及我拼凑在一起的信息。 我当前的代码基本上类似于this。
我很遗憾AndEngine
设法在音乐中没有这些问题,因此查看源代码可能有助于寻找答案的人。我正在使用the last functional GLES1 version from Google Code。
我已经看过以下链接以及创建好音乐Service
:
我希望解决方案Service
能够:
BroadcastReceivers
和Android Manifest添加/权限其他笔记
提前感谢大家!祝你好运!
编辑 - 以下是代码段,随意改进或忽略:
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) {}
}
}
音乐服务
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();
}
}
答案 0 :(得分: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,您可以在Activity中绑定Service,并像普通的Java-Object一样访问它。 我发布的活动bindes the Service。在它的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();
答案 1 :(得分: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;
}
}
}
第二次,创建一个基本活动并扩展您希望播放背景音乐的所有活动:
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" />
答案 2 :(得分:0)
在启动活动中,我们分别绑定和启动服务。这是错误的,因为服务将在活动退出后继续运行,因为我们在任何地方都没有调用 stopService()。因此,应该删除部分'startService(service)',因为绑定服务已经“自动创建”服务。
如果有人得到相反的结果,请纠正我
startService(service);// remove this part
bindService(new Intent(this, MusicService.class), mServiceConnection, Context.BIND_AUTO_CREATE);