如何将Java中TextureView+MediaPlayer代码转为Jetpack Compose实现
将Java中TextureView+MediaPlayer的视频逻辑迁移到Jetpack Compose
问题描述
我原本在Java的VideoCropActivity中通过实现TextureView.SurfaceTextureListener接口,结合TextureView和MediaPlayer处理视频相关操作。现在想把这段逻辑迁移到Jetpack Compose中,尝试用AndroidView加载布局的方式但没能正常运行,求正确的转换方案。
原Java代码
class VideoCropActivity extends Activity implements TextureView.SurfaceTextureListener { private MediaPlayer mPlayer; private Surface mSurface; private TextureView textureview; public void initSurface() { textureview = (TextureView) findViewById(R.id.aliyun_video_textureview); textureview.setSurfaceTextureListener(this); } @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { if (mPlayer == null) { try { mSurface = new Surface(surface); mPlayer = new MediaPlayer(); mPlayer.setSurface(mSurface); } catch (Exception e) { e.printStackTrace(); } } } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {} @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { return false; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {} }
当前尝试的Compose代码(无法正常工作)
AndroidView(factory = { val view = LayoutInflater.from(it).inflate(R.layout.aliyun_video_player, null) val textureView = view.findViewById<TextureView>(R.id.videoTextureView) textureView.apply { // 仅创建了监听器对象,但未设置给TextureView object : TextureView.SurfaceTextureListener { override fun onSurfaceTextureAvailable(p0: SurfaceTexture, p1: Int, p2: Int) { println("=================") } override fun onSurfaceTextureSizeChanged(p0: SurfaceTexture, p1: Int, p2: Int) { TODO("Not yet implemented") } override fun onSurfaceTextureDestroyed(p0: SurfaceTexture): Boolean { TODO("Not yet implemented") } override fun onSurfaceTextureUpdated(p0: SurfaceTexture) { TODO("Not yet implemented") } } } }, update = { // 每次重组都会创建新的MediaPlayer,逻辑混乱 val s = it.surfaceTexture if (s != null) { val surface = android.view.Surface(it.surfaceTexture) val mediaPlayer = MediaPlayer() mediaPlayer.setSurface(surface) println(it) } })
正确实现方案
你的代码核心问题是未给TextureView绑定SurfaceTextureListener,且update块中重复创建MediaPlayer导致生命周期混乱。以下是修复后的完整实现:
方案1:直接创建TextureView(无需布局文件)
@Composable fun VideoPlayer(videoUri: Uri) { // 用remember持有对象,避免Compose重组时重复创建 val mediaPlayer = remember { MediaPlayer() } var playerSurface by remember { mutableStateOf<Surface?>(null) } AndroidView( factory = { context -> TextureView(context).apply { // 关键:给TextureView设置SurfaceTextureListener surfaceTextureListener = object : TextureView.SurfaceTextureListener { override fun onSurfaceTextureAvailable( surfaceTexture: SurfaceTexture, width: Int, height: Int ) { val newSurface = Surface(surfaceTexture) playerSurface = newSurface // 初始化MediaPlayer并绑定Surface try { mediaPlayer.reset() mediaPlayer.setDataSource(context, videoUri) mediaPlayer.setSurface(newSurface) mediaPlayer.prepareAsync() mediaPlayer.setOnPreparedListener { it.start() } } catch (e: IOException) { e.printStackTrace() } } override fun onSurfaceTextureSizeChanged( surfaceTexture: SurfaceTexture, width: Int, height: Int ) { // 可选:处理视频尺寸变化逻辑 } override fun onSurfaceTextureDestroyed(surfaceTexture: SurfaceTexture): Boolean { // 释放资源 mediaPlayer.stop() mediaPlayer.release() playerSurface?.release() return true } override fun onSurfaceTextureUpdated(surfaceTexture: SurfaceTexture) { // 可选:每一帧更新时的操作 } } } }, update = { textureView -> // 可选:当videoUri变化时,重新加载视频 if (mediaPlayer.dataSource != videoUri.toString()) { playerSurface?.let { surface -> try { mediaPlayer.reset() mediaPlayer.setDataSource(textureView.context, videoUri) mediaPlayer.setSurface(surface) mediaPlayer.prepareAsync() mediaPlayer.setOnPreparedListener { it.start() } } catch (e: IOException) { e.printStackTrace() } } } } ) // 确保Compose组件销毁时释放资源 DisposableEffect(Unit) { onDispose { mediaPlayer.stop() mediaPlayer.release() playerSurface?.release() } } }
方案2:加载现有布局文件
如果你想继续使用R.layout.aliyun_video_player,只需修改factory块的逻辑:
factory = { context -> val view = LayoutInflater.from(context).inflate(R.layout.aliyun_video_player, null) val textureView = view.findViewById<TextureView>(R.id.videoTextureView) // 给TextureView设置监听器(核心修复点) textureView.surfaceTextureListener = object : TextureView.SurfaceTextureListener { // 同上的监听器实现逻辑 } view }
关键修复点
- 绑定SurfaceTextureListener:必须调用
textureView.setSurfaceTextureListener(),否则不会触发回调 - 生命周期管理:用
remember保存MediaPlayer和Surface,避免重组时重复创建;用DisposableEffect确保组件销毁时释放资源 - 避免重复初始化:不在
update块中创建新的MediaPlayer,而是复用已有的对象
内容的提问来源于stack exchange,提问作者gaohomway
相关产品推荐
相关产品推荐

