Reputation: 701
i am using VideoView and seek bar but when i seekTo(..) on desired position through seekBar it play video from starting.
i trying this code:
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) { mVideoView.seekTo(progress); }
Upvotes: 15
Views: 13695
Reputation: 17495
You're missing the listeners to start once seek is completed. The correct sequence to restart a video from a previously stored position using a VideoView
would look like this in Kotlin.
Storing the position, could be done in onPause
of Activity or any other lifecycle aware view:
val videoPosition = videoView.currentPosition
videoView.pause() // you can also use .stopPlayBack() since you'll restart anyway
And onResume
you can resume playback from that stored position, note how listeners are used to detect video prepare and video seek being complete:
videoView.setOnPreparedListener { mediaPlayer ->
mediaPlayer.seekTo(videoPosition)
mediaPlayer.setOnSeekCompleteListener { seekMediaPlayer ->
seekMediaPlayer.start()
}
For all of this to work the actual VideoView
has to be visible in the layout. If hidden (either using visibility INVISIBLE
or GONE
) the video will never prepare so nothing will happen.
If you encounter black screens or other artifacts caused by the view being visible before the content is fully loaded you can use alpha
instead to hide it.
videoView.alpha = 0f
videoView.setOnInfoListener { _, what, _ ->
if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START)
videoView.alpha = 1f
false
}
If you're working with an Activity or Fragment you can just hook onto the existing onPause
and onResume
methods.
override fun onPause() {
// handlePauseVideo()
super.onPause()
}
override fun onResume() {
super.onResume()
// handleResumeVideo()
}
When working with a custom view you'll need to make it lifecycle aware like so:
init {
inflate(context, R.layout.your_custom_view, this)
(context as? LifecycleOwner)?.lifecycle?.addObserver(this)
}
override fun onPause(owner: LifecycleOwner) {
// handlePauseVideo()
super.onPause(owner)
}
override fun onResume(owner: LifecycleOwner) {
super.onResume(owner)
// handleResumeVideo()
}
override fun onDestroy(owner: LifecycleOwner) {
// handleEndVideo()
super.onDestroy(owner)
}
Upvotes: 0
Reputation: 761
use my method works like charm
Take mediaPlayer
MediaPlayer mediaPlayer;
init mediaPlayer
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
mediaPlayer = mp;
}
});
use seekTo method like this
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mediaPlayer.seekTo((int) mStartPosition, MediaPlayer.SEEK_CLOSEST);
} else {
mediaPlayer.seekTo((int) mStartPosition);
}
Upvotes: 0
Reputation: 634
As Reno mentioned, you have to wait for the seeking to complete.
VideoView
does not have a OnSeekCompleteListener()
but you can access the MediaPlayer
from the onPrepared
method of the VideoView
and then set the OnSeekCompleteListener
, like this :
mVideoView.setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
mp.setOnSeekCompleteListener(new OnSeekCompleteListener() {
@Override
public void onSeekComplete(MediaPlayer mp) {
//TODO: Your code here
}
});
}
});
Upvotes: 28
Reputation: 1669
The call to VideoView.seekTo()
is a wrapper around MediaPlayer.seekTo()
. This function returns almost immediately even though the actual seeking is still being performed. Therefore you want to wait for seeking to complete via MediaPlayer.OnSeekCompleteListener
.
However, as Reno mentioned, the standard VideoView
does not support OnSeekCompleteListener
.
But you can copy and locally customize the VideoView
class to add this support yourself.
First, start with a copy of VideoView.java. Or you can clone the entire frameworks/base repo but warning it is over 1 gig of data to download.
Copy VideoView.java into your Eclipse Android project and it will start building but fail. Here's what I did to get it to compile:
MetaData
. The fix for this is on my todo list. These need to be replaced with calls to MediaMetadataRetriever
.mContext
with calls to getBaseContext()
Now you are ready to add the code for OnSeekCompleteListener
. The implementation is similar to the other listeners, i.e OnCompletionListener
.
public class VideoView extends SurfaceView
implements MediaPlayerControl {
// The client's listener which is the notification callback.
private OnSeekCompleteListener mOnSeekCompleteListener;
// Set up MediaPlayer to forward notifications to client.
private MediaPlayer.OnSeekCompleteListener mSeekCompleteListener =
new MediaPlayer.OnSeekCompleteListener() {
public void onSeekComplete(MediaPlayer mp) {
if (mOnCompletionListener != null) {
mOnCompletionListener.onCompletion(mMediaPlayer);
}
}
};
// API for client to set their listener.
public void setOnSeekCompleteListener(OnSeekCompleteListener l)
{
mOnSeekCompleteListener = l;
}
}
Finally, update your own code:
android.widget.VideoView
to use your customized VideoView
.setOnSeekCompleteListener()
.Your code now receives notifications when the seek has really completed and it can then perform subsequent seeks.
Upvotes: 6
Reputation: 33792
You have to wait for the seeking to complete, unfortunately VideoView
does not have a OnSeekCompleteListener()
(why Google? -_-)
Upvotes: 4