我希望保留在VideoView
中播放的视频的缓冲部分。我发现VideoView
SurfaceDestroyed
release(true);
有mMediaPlayer
次调用,导致根据此问题释放SurfaceHolder.Callback
个实例
VideoView onResume loses buffered portion of the video
我不想破解内部API,因此我决定重写mSHCallback
并将其替换为release(true);
字段,以避免使用反射调用VideoView.start()
。
但是当我在SurfaceCreated
覆盖中调用package com.tirkx.aos;
import android.util.Log;
import android.widget.MediaController;
import android.media.MediaPlayer;
import android.view.SurfaceHolder;
import android.widget.VideoView;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
public class CustomVidViewCallbackLoader implements SurfaceHolder.Callback
{
private final String TAG = "CustomCallbackLoader";
private Map<String, Field> PrivateFields;
private Map<String, Method> PrivateMethods;
private VideoView VideoView;
boolean VideoOpened;
public CustomVidViewCallbackLoader(VideoView videoView)
{
VideoView = videoView;
PrivateFields = new HashMap<String, Field>();
PrivateMethods = new HashMap<String, Method>();
Class VideoViewClass = videoView.getClass();
//Reflection things
try
{
PrivateFields.put("mSHCallback", VideoViewClass.getDeclaredField("mSHCallback"));
PrivateFields.put("mSurfaceHolder", VideoViewClass.getDeclaredField("mSurfaceHolder"));
PrivateFields.put("mMediaController", VideoViewClass.getDeclaredField("mMediaController"));
PrivateFields.put("mMediaPlayer", VideoViewClass.getDeclaredField("mMediaPlayer"));
PrivateFields.put("mSurfaceWidth", VideoViewClass.getDeclaredField("mSurfaceWidth"));
PrivateFields.put("mSurfaceHeight", VideoViewClass.getDeclaredField("mSurfaceHeight"));
PrivateFields.put("mTargetState", VideoViewClass.getDeclaredField("mTargetState"));
PrivateFields.put("mVideoWidth", VideoViewClass.getDeclaredField("mVideoWidth"));
PrivateFields.put("mVideoHeight", VideoViewClass.getDeclaredField("mVideoHeight"));
PrivateFields.put("mSeekWhenPrepared", VideoViewClass.getDeclaredField("mSeekWhenPrepared"));
PrivateMethods.put("openVideo", VideoViewClass.getDeclaredMethod("openVideo"));
for(Map.Entry<String, Method> m : PrivateMethods.entrySet())
m.getValue().setAccessible(true);
for(Map.Entry<String, Field> f : PrivateFields.entrySet())
f.getValue().setAccessible(true);
}
catch(Exception ex)
{
ex.printStackTrace();
}
try
{
SurfaceHolder.Callback SHCallback = (SurfaceHolder.Callback) PrivateFields
.get("mSHCallback").get(videoView);
if (SHCallback != null)
{
videoView.getHolder().removeCallback(SHCallback);
PrivateFields.get("mSHCallback").set(videoView, this);
videoView.getHolder().addCallback((SurfaceHolder.Callback) PrivateFields
.get("mSHCallback").get(videoView));
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
@Override
public void surfaceCreated(SurfaceHolder holder)
{
try
{
PrivateFields.get("mSurfaceHolder").set(VideoView, holder);
if(!VideoOpened)
{
PrivateMethods.get("openVideo").invoke(VideoView);
VideoOpened = true;
}
else
{
VideoView.start();
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
{
try
{
//PrivateFields.get("mSurfaceHolder").set(VideoView, holder);
int mVideoWidth = (int) PrivateFields.get("mVideoWidth").get(VideoView);
int mVideoHeight = (int) PrivateFields.get("mVideoHeight").get(VideoView);
int mTargetState = (int) PrivateFields.get("mTargetState").get(VideoView);
int mSeekWhenPrepared = (int) PrivateFields.get("mSeekWhenPrepared").get(VideoView);
MediaPlayer mMediaPlayer = (MediaPlayer) PrivateFields.get("mMediaPlayer").get(VideoView);
PrivateFields.get("mSurfaceWidth").set(VideoView, width);
PrivateFields.get("mSurfaceHeight").set(VideoView, height);
boolean isValidState = (mTargetState == 3);
boolean hasValidSize = (mVideoWidth == width && mVideoHeight == height);
if(mMediaPlayer != null && isValidState && hasValidSize)
{
if(mSeekWhenPrepared != 0)
VideoView.seekTo(mSeekWhenPrepared);
VideoView.start();
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder)
{
try
{
PrivateFields.get("mSurfaceHolder").set(VideoView, null);
MediaController mediaController = (MediaController) PrivateFields.get("mMediaController")
.get(VideoView);
if(mediaController != null)
mediaController.hide();
VideoView.pause();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
public void setMediaPlayerOnBufferedChanged(MediaPlayer mediaPlayer)
{
if (mediaPlayer != null)
{
mediaPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener()
{
@Override
public void onBufferingUpdate(MediaPlayer mp, int percent)
{
Log.i(TAG, "-->" + percent);
}
});
}
}
}
时似乎很奇怪,我有多次“无法播放此视频”消息,但音频会一直播放到最后切换到其他活动。
这是我的自定义回调
Int32