MVVM架构下ExoPlayer初始化问题求助:ViewModel无法持有Context
解决ViewModel中初始化ExoPlayer的Context问题
嘿,这个问题我之前在项目里也踩过坑——ViewModel确实不能持有和UI组件绑定的Context,但ExoPlayer初始化又离不开它,给你两个符合MVVM规范且安全的解决方案,完全不会造成内存泄漏:
方案一:使用AndroidViewModel(最简单直接)
AndroidViewModel是ViewModel的子类,专门为Android场景设计,它本身就持有Application实例,不需要额外传参,非常省心。
代码示例(Java)
import android.app.Application; import androidx.annotation.NonNull; import androidx.lifecycle.AndroidViewModel; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; public class PlayerViewModel extends AndroidViewModel { private final ExoPlayer exoPlayer; public PlayerViewModel(@NonNull Application application) { super(application); // 初始化轨道选择器 DefaultTrackSelector trackSelector = new DefaultTrackSelector(application); // 替代废弃的ExoPlayerFactory,用官方推荐的Builder创建实例 exoPlayer = new ExoPlayer.Builder(application) .setTrackSelector(trackSelector) .build(); } // 播放操作方法 public void play() { exoPlayer.play(); } public void pause() { exoPlayer.pause(); } public void switchTrack(MediaItem mediaItem) { exoPlayer.setMediaItem(mediaItem); exoPlayer.prepare(); exoPlayer.play(); } @Override protected void onCleared() { super.onCleared(); // 务必在ViewModel销毁时释放播放器资源,避免内存泄漏 exoPlayer.release(); } }
在Activity/Fragment中获取ViewModel
PlayerViewModel viewModel = new ViewModelProvider(this).get(PlayerViewModel.class);
方案二:自定义ViewModelFactory传入Application Context
如果不想用AndroidViewModel,也可以自定义ViewModelFactory,把Application Context传入普通的ViewModel中,这种方式灵活性更高。
自定义ViewModelFactory(Java)
import android.app.Application; import androidx.annotation.NonNull; import androidx.lifecycle.ViewModel; import androidx.lifecycle.ViewModelProvider; public class PlayerViewModelFactory implements ViewModelProvider.Factory { private final Application application; public PlayerViewModelFactory(Application application) { this.application = application; } @NonNull @Override public <T extends ViewModel> T create(@NonNull Class<T> modelClass) { if (modelClass.isAssignableFrom(PlayerViewModel.class)) { return (T) new PlayerViewModel(application); } throw new IllegalArgumentException("Unknown ViewModel class"); } }
普通ViewModel实现(Java)
import android.app.Application; import androidx.lifecycle.ViewModel; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; public class PlayerViewModel extends ViewModel { private final ExoPlayer exoPlayer; public PlayerViewModel(Application application) { DefaultTrackSelector trackSelector = new DefaultTrackSelector(application); exoPlayer = new ExoPlayer.Builder(application) .setTrackSelector(trackSelector) .build(); } // 播放操作方法和方案一一致 public void play() { exoPlayer.play(); } public void pause() { exoPlayer.pause(); } public void switchTrack(MediaItem mediaItem) { exoPlayer.setMediaItem(mediaItem); exoPlayer.prepare(); exoPlayer.play(); } @Override protected void onCleared() { super.onCleared(); exoPlayer.release(); } }
在Activity/Fragment中获取ViewModel
PlayerViewModel viewModel = new ViewModelProvider(this, new PlayerViewModelFactory(getApplication())) .get(PlayerViewModel.class);
关键注意事项
- 必须用Application Context:绝对不能传入Activity/Fragment的Context,因为ViewModel的生命周期比UI组件长,持有组件Context会导致严重的内存泄漏。
- 及时释放资源:一定要在
onCleared()方法中调用exoPlayer.release(),这是ViewModel被销毁时的回调,用来清理播放器占用的系统资源。 - 废弃API替换:你代码里用的
ExoPlayerFactory已经被官方废弃,现在推荐使用ExoPlayer.Builder来创建实例,兼容最新版本的ExoPlayer,功能更完善。
内容的提问来源于stack exchange,提问作者Muhamed Raafat
相关产品推荐
相关产品推荐

