android - sistema - se cayo twitter hoy 2018
Servicio integral de mĂșsica a prueba de fallas de Android en mĂșltiples actividades (3)
Sé que esta pregunta se ha formulado muchas veces antes y puede parecer un conglomerado de varias preguntas, pero creo que es relevante e importante para muchos desarrolladores; Necesito crear un Service
música de fondo que pueda ejecutarse en múltiples actividades para mi juego de Android que finalice cuando la aplicación finalice y se detenga en todas las circunstancias siguientes:
- Se inicia una determinada
Activity
que tiene su propia música. (Reanude cuando estaActivity
termine. Esto pasa a ser una actividad deAndEngine
). - Se presiona la pantalla de inicio y la aplicación queda en segundo plano, o se termina la aplicación. Se reanuda cuando la aplicación vuelve al primer plano. Requiere el uso de
onUserLeaveHint()
. Otro enlace útil. - El teléfono recibe una llamada e interrumpe la aplicación. Se reanuda cuando la llamada ha sido tratada. Requiere el uso de
TelephonyManager
similar a this . - La pantalla está bloqueada. (Se reanuda después de que se haya desbloqueado la pantalla). Requiere el uso de
ACTION_USER_PRESENT
, que parece be very problematic . - Básicamente, la música se detiene cada vez que la aplicación no se muestra o cuando se muestra al usuario la actividad especial de # 1.
Arriba está todo lo que necesito y la información que he reunido. Mi código actual básicamente se parece a this .
Me parece curioso que AndEngine
logre no tener ninguno de estos problemas con su música, por lo que quizás buscar el código fuente ayudaría a alguien que busca una respuesta. Estoy usando la última versión funcional de GLES1 de Google Code .
También he echado un vistazo a los siguientes enlaces para crear un buen Service
música:
- Detener la música del servicio de fondo
- http://www.codeproject.com/Articles/258176/Adding-Background-Music-to-Android-App
- Servicio de música de fondo para Android
- Reproducción de música BG a través de actividades en Android
- http://www.rbgrn.net/content/307-light-racer-20-days-61-64-completion
Me gustaría que el Service
soluciones:
- Minimice el uso de los permisos / adiciones
BroadcastReceivers
y Android Manifest si es posible - Autocontenido y comprobación de errores.
Otras notas
- Actualmente, todas las actividades que requieren la música de fondo extienden una clase especial común.
- La música necesita un bucle pero solo corre una sola pista.
Gracias a todos por adelantado! ¡La mejor de las suertes!
Editar - Aquí hay fragmentos de código, siéntase libre de mejorar o ignorar:
Reproductor de medios 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) {}
}
}
Servicio de musica
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() {
}
}
Clase de actividad base mejorada
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();
}
}
En la actividad de inicio estamos vinculando e iniciando el servicio por separado. Esto es incorrecto ya que el servicio continuará ejecutándose después de que la actividad termine, ya que no hemos llamado a stopService () en ninguna parte. Por lo tanto, la parte ''startService (servicio)'' debe eliminarse, ya que el servicio de enlace ya está " creando automáticamente " el servicio también.
Por favor corrígeme si alguien tiene resultados opuestos
startService(service);// remove this part
bindService(new Intent(this, MusicService.class), mServiceConnection, Context.BIND_AUTO_CREATE);
Lo hice de esta manera y estoy satisfecho con el resultado:
Primero crea el servicio:
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;
}
}
}
En segundo lugar , cree una actividad base y extienda todas sus actividades de la forma en que desea reproducir la música de fondo:
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();
}
}
Y eso es todo, ahora tiene un sonido de fondo en todas las actividades que se extienden desde ActivityBase.
Incluso puede controlar la funcionalidad de pausa / reanudación llamando a basePause () / baseResume ().
No olvides declarar el servicio en manifiesto:
<service android:name="com.gga.screaming.speech.LocalService" />
Primero aquí hay un código. A continuación te doy una explicación.
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;
}
}
Actividad:
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;
}
}
En primer lugar tienes un servicio que se ejecuta en segundo plano. Este servicio crea el objeto mediaPlayer como lo hiciste. Con el localBinder puede vincular el Servicio en su (s) Actividad (es) y acceder a él como un objeto Java normal. La Actividad que he publicado enlaza el Servicio. En su método onCreate () puedes encontrar una forma de interactuar con tu mediaPlayer. Puedes vincular cualquier actividad a tu servicio.
Otra solución:
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) {}
}
}
Luego puede pausar, reproducir y detener la música llamando a CarefulMediaPlayer.getInstance (). Play ();