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

У меня есть медиаплеер вMusic класс, который вызывается из другого вторичногоActivity, Работает нормально.

Но когда экран выключается (либо по таймауту, либо по кнопке), музыка перестает воспроизводиться, а когда он возвращается и пытается закрыть действие, программа переходит в «Приложение не отвечает», потому чтоIllegalStateException на запрос какmediaplayer.isPlaying().

Как я могу предотвратить остановку медиаплеера при выключении экрана?

Это должно быть через службу?

Предполагая, что ответ да, я попытался преобразоватьMusic Класс в услугу (см. ниже). Я также добавил<service android:enabled="true" android:name=".Music" /> вManifest.xmlи я звонюMusic класс как это:

startService(new Intent(getBaseContext(), Music.class));
Music track = Music(fileDescriptor);

Только две новые строки в основной деятельностиstartService(new Intent(getBaseContext(), Music.class)); а такжеstopService(new Intent(getBaseContext(), Music.class));вместе с соответствующим импортом.

Но теперь я получаюInstantiationException ошибка, потому чтоcan't instantiate class при попытке запустить сервис. Чего мне не хватает?

Это исключение:

E/AndroidRuntime(16642): FATAL EXCEPTION: main
E/AndroidRuntime(16642): java.lang.RuntimeException: Unable to instantiate service com.floritfoto.apps.ave.Music:                                                                             java.lang.InstantiationException: can't instantiate class com.floritfoto.apps.ave.Music; no empty constructor                                                                   
E/AndroidRuntime(16642):    at android.app.ActivityThread.handleCreateService(ActivityThread,.java:2249)
E/AndroidRuntime(16642):    at android.app.ActivityThread.access$1600(ActivityThread.java:127)
E/AndroidRuntime(16642):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1213)
E/AndroidRuntime(16642):    at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime(16642):    at android.os.Looper.loop(Looper.java:137)
E/AndroidRuntime(16642):    at android.app.ActivityThread.main(ActivityThread.java:4507)
E/AndroidRuntime(16642):    at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(16642):    at java.lang.reflect.Method.invoke(Method.java:511)
E/AndroidRuntime(16642):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:980)
E/AndroidRuntime(16642):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:747)
E/AndroidRuntime(16642):    at dalvik.system.NativeStart.main(Native Method)
E/AndroidRuntime(16642): Caused by: java.lang.InstantiationException: can't instantiate class com.floritfoto.apps.ave.Music; no empty constructor
E/AndroidRuntime(16642):    at java.lang.Class.newInstanceImpl(Native Method)
E/AndroidRuntime(16642):    at java.lang.Class.newInstance(Class.java:1319)
E/AndroidRuntime(16642):    at android.app.ActivityThread.handleCreateService(ActivityThread.java:2246)
E/AndroidRuntime(16642):    ... 10 more

и это Music.class:

package com.floritfoto.apps.ave;

import java.io.FileDescriptor;
import java.io.IOException;

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

public class Music extends Service implements OnCompletionListener{
    MediaPlayer mediaPlayer;
    boolean isPrepared = false;

    //// TEstes de servico
    @Override
    public void onCreate() {
        super.onCreate();
        info("Servico criado!");
    }
    @Override
    public void onDestroy() {
        info("Servico fudeu!");
    }
    @Override
    public void onStart(Intent intent, int startid) {
        info("Servico started!");
    }   
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    public void info(String txt) {
        Toast toast = Toast.makeText(getApplicationContext(), txt, Toast.LENGTH_LONG);
        toast.show();
    }
    //// Fim testes de servico

    public Music(FileDescriptor fileDescriptor){
        mediaPlayer = new MediaPlayer();
        try{
            mediaPlayer.setDataSource(fileDescriptor);
            mediaPlayer.prepare();
            isPrepared = true;
            mediaPlayer.setOnCompletionListener(this);
        } catch(Exception ex){
            throw new RuntimeException("Couldn't load music, uh oh!");
        }
    }

    public void onCompletion(MediaPlayer mediaPlayer) {
        synchronized(this){
            isPrepared = false;
        }
    }

    public void play() {
        if(mediaPlayer.isPlaying()) return;
        try{
            synchronized(this){
                if(!isPrepared){
                    mediaPlayer.prepare();
                }
                mediaPlayer.seekTo(0);
                mediaPlayer.start();
            }
        } catch(IllegalStateException ex){
            ex.printStackTrace();
        } catch(IOException ex){
            ex.printStackTrace();
        }
    }

    public void stop() {
        mediaPlayer.stop();
        synchronized(this){
            isPrepared = false;
        }
    }

    public void switchTracks(){
        mediaPlayer.seekTo(0);
        mediaPlayer.pause();
    }

    public void pause() {
        mediaPlayer.pause();
    }

    public boolean isPlaying() {
        return mediaPlayer.isPlaying();
    }

    public boolean isLooping() {
        return mediaPlayer.isLooping();
    }

    public void setLooping(boolean isLooping) {
        mediaPlayer.setLooping(isLooping);
    }

    public void setVolume(float volumeLeft, float volumeRight) {
        mediaPlayer.setVolume(volumeLeft, volumeRight);
    }

    public String getDuration() {
        return String.valueOf((int)(mediaPlayer.getDuration()/1000));
    }
    public void dispose() {
        if(mediaPlayer.isPlaying()){
            stop();
        }
        mediaPlayer.release();
    }
}
 deefactorial27 окт. 2012 г., 04:37
Вы прочитали документацию о том, как пользоваться услугой?developer.android.com/reference/android/app/Service.html
 Luis A. Florit27 окт. 2012 г., 06:18
@deefactorial Конечно нет! Я просто хочу реализовать самый простой медиаплеер из когда-либо сделанных !! Я не хочу (и ожидать не нужно), чтобы узнать все его тонкости. Я просто пытаюсь следовать примеру (известного?) Маракана здесьmarakana.com/forums/android/examples/60.html, Что я делаю не так ...

Ответы на вопрос(2)

чтобы MediaPlayer воспроизводил медиа:

 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
Решение Вопроса

Caused by: java.lang.InstantiationException: can't instantiate class com.floritfoto.apps.ave.Music; no empty constructor

Вашему сервису нужен другой конструктор, который не принимает аргументов:

public Music() {
    super("Music");
}

РЕДАКТИРОВАТЬ:

Использование службы является правильным подходом, если вы хотите, чтобы музыка воспроизводилась при выключенном экране. Тем не менее, телефон будет пытаться спать, когда экран выключен, и это может прервать вашMediaPlayer.

Наиболее надежным решением является использованиечастичный WakeLock чтобы устройство не спало во время воспроизведения музыки. Обязательно выпуститеWakeLock правильно, когда ты не играешь активно музыку; в противном случае аккумулятор разрядится.

Вы также можете использоватьstartForeground(), что снизит риск того, что ваш сервис будет убит при нехватке памяти. Это также создаст приятный пользовательский опыт, показывая постоянное уведомление, когда ваша служба работает.

ИнстанцированиеMusic класс сMusic track = Music(fileDescriptor); вероятно, приносит вред. Лучший подход - передать дескриптор файла какExtra вIntent что вы передаетеstartService():

Intent serviceIntent = new Intent(this, Music.class);
serviceIntent.putExtra("ServiceFileDescriptor", fileDescriptor);
startService(serviceIntent);

Затем получите дескриптор файла из того жеIntent когда он передается к вашим услугамonStartCommand() метод:

public int onStartCommand(Intent intent, int flags, int startId) {
    super.onStart();

    Bundle bundle = intent.getExtras();
    // NOTE: The next line will vary depending on the data type for the file
    // descriptor. I'm assuming that it's an int.
    int fileDescriptor = bundle.getIntExtra("ServiceFileDescriptor");
    mediaPlayer = new MediaPlayer();
    try {
        mediaPlayer.setDataSource(fileDescriptor);
        ...
    ...
    return START_STICKY;
}

Несколько вещей, чтобы отметить здесь. Я переместил код из вашего исходного конструктора (который должен быть удален) вonStartCommand(), Вы можете удалитьonStart() метод, так как он будет вызываться только на устройствах до версии 2.0. Если вы хотите поддерживать современные версии Android, вам нужно использоватьonStartCommand() вместо. Наконец,START_STICKY возвращаемое значение будет гарантировать, что служба продолжает работать, пока вы не позвонитеstopService() от вашей деятельности.

РЕДАКТИРОВАТЬ 2:

Использование службы позволяет пользователям перемещаться между действиями, не прерываяMediaPlayer, Вы не имеете большого контроля над тем, как долгоActivity останется в памяти, но активнымService (особенно если вы звонитеstartForeground()) не будет убит, если не будет сильного давления памяти.

Взаимодействовать сMediaPlayer После запуска службы у вас есть несколько вариантов. Вы можете передать дополнительные команды службе, создавIntents и используя строку действия (и / или некоторые дополнительные функции), чтобы сообщить службе, что вы хотели бы от нее сделать. Просто позвониstartActivity() снова с новымIntent, а такжеonStartCommand() будет вызван в службе, после чего вы можете манипулироватьMediaPlayer, Второй вариант заключается в использованиисвязанная служба (примерВот) и привязывать / отменять привязку каждый раз, когда вы входите / выходите из действия, которое необходимо для связи со службой. Использование привязанного сервиса «чувствует», как будто вы напрямую манипулируете сервисом, но это также более сложно, так как вам нужно управлять связыванием и отменой привязки.

 Luis A. Florit27 окт. 2012 г., 17:25
Или, может быть, проблема в том, что mediaPlayer не создается при создании службы ...? : О (
 Luis A. Florit27 окт. 2012 г., 06:42
Может быть, Услуги не то, что мне нужно, чтобы решить эту проблему, и есть какое-то другое, гораздо более простое решение ?? Пожалуйста помоги...
 Luis A. Florit27 окт. 2012 г., 05:58
Теперь я понял, что вы имели в виду (но мне пришлось удалить"Music" внутри скобки). Но тогда у меня все та же проблема: я вижу в logcat, что медиаплеер отключается, когда экран выключен, и я получаюIllegalStateException когда запросmediaPlayer.isPlayingкак если бы не выполнялась никакая служба. :(
 acj28 дек. 2012 г., 17:45
После того, как вы запустили сервис с намерением, вы можете связать его и вызвать любые открытые методы, которые вы определили в своемService, Например, вы можете определить методы, которые получают статус воспроизведения или длительность текущей песни. Пожалуйста, посмотрите на пример ссылки в нижней части моего ответа.
 Luis A. Florit27 окт. 2012 г., 05:27
Вы имеете в виду следовать линииpublic Music(FileDescriptor fileDescriptor){? Я сделал это и получил «Конструктор службы (строка) не определена», и попросил меня удалить «Музыка». Я сделал это, и получил то же самоеInstantiationException, :(

Ваш ответ на вопрос