使用ObjectOutputStream保存MediaPlayer对象时遇java.io.NotSerializableException错误的解决办法
嘿,这个坑我踩过好几次了,咱们来一步步搞定它~
首先明确问题根源:ObjectOutputStream要求被序列化的对象必须实现Serializable标记接口,而你用的MediaPlayer类(不管是自定义的还是第三方库比如Android的MediaPlayer)显然没实现这个接口,所以抛出了java.io.NotSerializableException。
下面分三种场景给你解决方案:
场景1:你能修改MediaPlayer的源码
如果这个MediaPlayer是你自己写的类,那最简单的办法就是让它实现Serializable接口:
public class MediaPlayer implements Serializable { // 你原来的类代码,不需要额外实现任何方法 }
⚠️ 注意:如果类里有一些不能被序列化的资源(比如文件句柄、网络连接、硬件相关的对象),记得用transient关键字修饰这些字段,序列化时会自动跳过它们:
public class MediaPlayer implements Serializable { private transient FileInputStream audioStream; // 不会被序列化 private String audioFilePath; // 会被正常序列化 // 其他代码 }
场景2:MediaPlayer是第三方类(无法修改源码)
如果MediaPlayer是像Android SDK里的那种第三方类,你没法改它的源码,那就得用自定义序列化逻辑。核心思路是:在你用来封装MediaPlayer的类里,手动控制哪些状态需要保存,以及如何恢复。
举个例子,假设你有个PlayerWrapper类用来持有MediaPlayer:
public class PlayerWrapper implements Serializable { // 用transient标记MediaPlayer,让它不被自动序列化 private transient MediaPlayer mediaPlayer; // 保存MediaPlayer的关键状态(这些是可序列化的) private String audioSourcePath; private int currentPlayPosition; private boolean wasPlaying; // 构造方法等原有代码 // 自定义序列化方法,会被ObjectOutputStream自动调用 private void writeObject(ObjectOutputStream out) throws IOException { // 先序列化所有非transient的字段 out.defaultWriteObject(); // 手动保存MediaPlayer的当前状态 currentPlayPosition = mediaPlayer.getCurrentPosition(); wasPlaying = mediaPlayer.isPlaying(); // 这里可以根据需求保存更多状态,比如音量、循环模式等 } // 自定义反序列化方法,会被ObjectInputStream自动调用 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { // 先恢复非transient的字段 in.defaultReadObject(); // 重新创建MediaPlayer实例 mediaPlayer = new MediaPlayer(); mediaPlayer.setDataSource(audioSourcePath); mediaPlayer.prepare(); // 恢复之前的播放状态 mediaPlayer.seekTo(currentPlayPosition); if (wasPlaying) { mediaPlayer.start(); } } }
这种方式的核心是:不直接序列化MediaPlayer实例,而是序列化它的可持久化状态,反序列化时重新创建MediaPlayer并把状态还原回去。
场景3:不需要保存MediaPlayer实例,只需要保存配置
如果你的需求只是保存MediaPlayer的配置信息(比如要播放的音频路径、默认音量),而不是实例本身,那可以单独抽一个配置类来序列化:
public class MediaPlayerConfig implements Serializable { private String audioPath; private float defaultVolume; private boolean loopEnabled; // 构造方法、getter、setter }
保存的时候只序列化这个MediaPlayerConfig对象,下次需要使用MediaPlayer时,用配置类里的参数初始化新的MediaPlayer实例即可。
额外注意事项
Serializable是一个标记接口,不需要实现任何方法,只是告诉JVM这个类的对象可以被序列化。- 如果你的类有父类,要么父类也实现
Serializable,要么父类必须有一个无参构造函数(反序列化时会调用父类的无参构造来初始化父类部分)。 - 对于一些复杂的第三方对象,也可以考虑用JSON序列化(比如Gson、Jackson)来替代ObjectOutputStream,很多第三方库的对象虽然不支持Serializable,但支持JSON序列化。
内容的提问来源于stack exchange,提问作者Jovan Dukic

