Lui*_*rit 6 android screen media-player instantiationexception
我在一个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);
Run Code Online (Sandbox Code Playgroud)
主Activity中只有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
Run Code Online (Sandbox Code Playgroud)
这是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();
}
}
Run Code Online (Sandbox Code Playgroud)
Logcat中的这一行是重要的一行:
Caused by: java.lang.InstantiationException: can't instantiate class com.floritfoto.apps.ave.Music; no empty constructor
Run Code Online (Sandbox Code Playgroud)
您的服务需要另一个不带参数的构造函数:
public Music() {
super("Music");
}
Run Code Online (Sandbox Code Playgroud)
编辑:
如果您想在屏幕关闭时保持音乐播放,则使用服务是正确的方法.但是,当屏幕关闭时,手机会尝试睡眠,这可能会打断你的电话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);
Run Code Online (Sandbox Code Playgroud)
然后,在将文件描述符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;
}
Run Code Online (Sandbox Code Playgroud)
这里要注意的一些事情.我已将代码从原始构造函数(应删除)移动到onStartCommand().您也可以删除该onStart()方法,因为它只会在2.0之前的设备上调用.如果您想支持现代Android版本,则需要使用onStartCommand().最后,START_STICKY返回值将确保服务保持运行,直到您stopService()从活动中调用.
编辑2:
使用服务使您的用户可以在不中断活动的情况下在活动之间移动MediaPlayer.你没有多少控制Activity将留在记忆中的时间,但是除非存在非常强的记忆压力,否则不会被杀死Service(特别是如果你打电话startForeground()).
要MediaPlayer在服务启动后与之交互,您有几个选择.您可以通过创建Intents并使用操作字符串(和/或一些额外内容)将其他命令传递给服务,以告知服务您希望它执行的操作.只需startActivity()再次使用new 调用Intent,onStartCommand()将在服务中调用,此时您可以操作MediaPlayer.第二个选项是使用绑定服务(此处为示例),并在每次进入/离开需要与服务通信的活动时绑定/取消绑定.使用绑定服务"感觉"就像您直接操作服务一样,但由于您需要管理绑定和解除绑定,因此它也更复杂.
| 归档时间: |
|
| 查看次数: |
10403 次 |
| 最近记录: |