如何防止媒体播放器停止时,屏幕熄灭?(How to prevent mediaplayer to s

2019-08-02 01:01发布

我有一个媒体播放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);

在主活动的唯一2新线是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();
    }
}

Answer 1:

这从logcat的线是重要的:

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

你的服务需要另一个构造函数不带参数:

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

编辑

使用服务是正确的做法,如果你想保持音乐播放时,屏幕是关闭的。 然而,手机会尝试当屏幕关闭时睡觉,这会打断你MediaPlayer

最可靠的解决方案是使用部分激活锁定 ,以防止设备在您播放音乐睡觉。 一定要释放WakeLock正确的,当你不积极地播放音乐; 否则电池将排出。

您可能还需要使用startForeground()这会降低你的服务的时候有内存压力被杀害的危险。 它也将创建出当你的服务正在运行一个永久通知一个很好的用户体验。

实例化Music与类Music track = Music(fileDescriptor); 可能做一些危害。 更好的方法是通过文件描述符作为ExtraIntent ,你传递给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服务启动后,你有两个选择。 您可以通过创建额外的传递命令到服务Intent S和使用操作字符串(和/或一些额外的)告诉你想它做什么业务。 只需调用startActivity()与新再次Intent ,并onStartCommand()将在服务调用,此时您可以操纵MediaPlayer 。 第二个选择是使用绑定的服务 (例如这里 )和绑定/每次进入时解除绑定/离开需要与服务进行通信的活跃性。 使用绑定的服务“感觉”就好像你直接操纵的服务,但它也更复杂,因为你需要管理的结合,并解除绑定。



Answer 2:

作为一个选项,你可以保持激活保持的MediaPlayer再现媒体画面:

 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);


文章来源: How to prevent mediaplayer to stop when screen goes off?