播放video时禁用Android的VideoView requestAudioFocus?

我正在构build一个logging和回放video的应用程序。 我想这样做,而不影响背景音乐播放,即如果我开始播放video,我不想暂停其他应用程序的audio。 但是,在棒棒糖上,当调用私有方法VideoView.openVideo()时,Android的VideoView类会自动请求audio焦点:

 AudioManager am = (AudioManager) super.getSystemService(name); am.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); 

有关如何解决这个问题的任何build议?

Solutions Collecting From Web of "播放video时禁用Android的VideoView requestAudioFocus?"

我解决了这个愚蠢的解决scheme,通过复制android.widget.VideoView的棒棒糖的整个源代码,并删除你提到的行。

制作您自己的VideoView类。 不要使用extends VideoView因为你不能覆盖openVideo()方法。

我不build议这样做,因为我认为这是一个临时解决scheme。 VideoView在4.1-5.0之间改变了很多,所以这可能会导致除了棒棒糖以外的Android版本的RuntimeException

编辑

我做了一个方法MediaPlayer + SurfaceView pinxue告诉我们; 它尊重viewWidthviewHeight

  final String finalFilePath = filePath; final SurfaceHolder surfaceHolder = sv.getHolder(); final MediaPlayer mediaPlayer = new MediaPlayer(); final LinearLayout.LayoutParams svLayoutParams = new LinearLayout.LayoutParams(viewWidth,viewHeight); surfaceHolder.addCallback(new SurfaceHolder.Callback(){ @Override public void surfaceCreated(SurfaceHolder holder) { try { if(isDebug) { System.out.println("setting VideoPath to VideoView: "+finalFilePath); } mediaPlayer.setDataSource(finalFilePath); }catch (IOException ioe){ if(isDebug){ ioe.printStackTrace(); } //mediaPlayer = null; } mediaPlayer.setDisplay(surfaceHolder); mediaPlayer.prepareAsync(); mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { if(isDebug){ System.out.println("Video is starting..."); } // for compatibility, we adjust size based on aspect ratio if ( mp.getVideoWidth() * svLayoutParams.height < svLayoutParams.width * mp.getVideoHeight() ) { //Log.i("@@@", "image too wide, correcting"); svLayoutParams.width = svLayoutParams.height * mp.getVideoWidth() / mp.getVideoHeight(); } else if ( mp.getVideoWidth() * svLayoutParams.height > svLayoutParams.width * mp.getVideoHeight() ) { //Log.i("@@@", "image too tall, correcting"); svLayoutParams.height = svLayoutParams.width * mp.getVideoHeight() / mp.getVideoWidth(); } sv.post(new Runnable(){ @Override public void run() { sv.setLayoutParams(svLayoutParams); } }); mp.start(); } }); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { if(isDebug){ System.out.println("surfaceChanged(holder, "+format+", "+width+", "+height+")"); } } @Override public void surfaceDestroyed(SurfaceHolder holder) { try { mediaPlayer.setDataSource(""); }catch (IOException ioe){ if(isDebug){ ioe.printStackTrace(); } } } }); if(sv.post(new Runnable() { @Override public void run() { sv.setLayoutParams(svLayoutParams);/// sv.setVisibility(View.VISIBLE); }})){ if(isDebug) { System.out.println("post Succeded"); } }else{ if(isDebug) { System.out.println("post Failed"); } } 

您可以改用MediaPlayer + SurfaceView。

接受的解决scheme并不能保证所有Android版本的兼容性,而不是一个真正的解决scheme。 我尝试了各种forms的黑客来获得这个工作,但没有任何工作让我满意。

我想出了一个更好的解决scheme – 从VideoView切换到TextureView并加载MediaPlayer 。 从用户的angular度来看,没有什么区别,只是没有更多的audio停顿。

这是我玩MP4循环的用例:

 private TextureView _introVideoTextureView; private MediaPlayer _introMediaPlayer; ... @Override public void onCreate(...) { _introVideoTextureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() { @Override public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) { try { destoryIntroVideo(); _introMediaPlayer = MediaPlayer.create(SignInActivity.this, R.raw.intro_video); _introMediaPlayer.setSurface(new Surface(surfaceTexture)); _introMediaPlayer.setLooping(true); _introMediaPlayer.setVideoScalingMode(MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING); _introMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mediaPlayer) { mediaPlayer.start(); } }); } catch (Exception e) { System.err.println("Error playing intro video: " + e.getMessage()); } } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) {} @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) { return false; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {} }); } @Override public void onDestroy() { super.onDestroy(); destoryIntroVideo(); } private void destoryIntroVideo() { if (_introMediaPlayer != null) { _introMediaPlayer.stop(); _introMediaPlayer.release(); _introMediaPlayer = null; } } 

使用audioManager.abandonAudioFocus(null)

如果您查看VideoView代码,您会注意到它调用OnAudioFocusChangeListener的方法audioManager.requestAudioFocus为null。 当你使用AudioManager注册一个监听器的时候,它使用这个方法为监听器创build一个ID

 private String getIdForAudioFocusListener(OnAudioFocusChangeListener l) { if (l == null) { return new String(this.toString()); } else { return new String(this.toString() + l.toString()); } } 

每次使用null都会生成相同的ID。 因此,如果您调用abandonAudioFocus与null它将删除任何添加了作为OnAudioFocusChangeListener的参数为null的侦听器