本篇内容将介绍 IJKPlayer 播放器在 Android 中的使用
一、导入依赖库
// required, enough for most devices.
api 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'
api 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.8'
// Other ABIs: optional
api 'tv.danmaku.ijk.media:ijkplayer-armv5:0.8.8'
api 'tv.danmaku.ijk.media:ijkplayer-arm64:0.8.8'
api 'tv.danmaku.ijk.media:ijkplayer-x86:0.8.8'
api 'tv.danmaku.ijk.media:ijkplayer-x86_64:0.8.8'
// ExoPlayer as IMediaPlayer: optional, experimental
api 'tv.danmaku.ijk.media:ijkplayer-exo:0.8.8'
二、查看官方 Demo
三、重写 MediaController 实现自己需要的效果
1. IJKPlayer 的使用
IJKPlayer 播放使用到了上面 Demo 中的 IjkVideoView, 给 IjkVideoView 设置一个 Controller,调用 setVideoPath 设置播放链接,再执行 start 方法开始播放视频即可;不过使用其原来的 AndroidMediaController,效果很差,所以需要重写;
private var mController: AndroidMediaController? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_video)
mController = AndroidMediaController(this)
mController!!.setSupportActionBar(txtTitle)
player?.setMediaController(mController)
player?.setVideoPath("http://baobab.kaiyanapp.com/api/v1/playUrl?vid=66073&editionType=high&source=aliyun")
player?.setOnErrorListener(this)
player?.setOnCompletionListener(this)
player?.start()
}
2. 重写 AndroidMediaController
AndroidMediaController 继承自MediaController,所以我们可以按照 MediaController 的模式,写一个自己的 Controller 给 AndroidMediaController 继承;
首先是 initFloatingWindow 方法中,实例化 Window 的处理,Window 对应唯一一个 PhoneWindow,却是系统的隐藏Api,只能通过反射的方式获取实例;反射的时候需要注意一点:
Android 5.1 及之前是使用 PolicyManager.makeNewWindow(context) 创建的 PhoneWindow;
Android 5.1 之后是通过 new PhoneWindow(context) 创建的 PhoneWindow;
两种方式对应的 PhoneWindow 的路径并不相同,所以反射代码如下:
private void initFloatingWindow() {
mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
try {
Class<?> clazz;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
clazz = Class.forName("com.android.internal.policy.PhoneWindow");
} else {
clazz = Class.forName("com.android.internal.policy.impl.PhoneWindow");
}
Constructor constructor = clazz.getDeclaredConstructor(Context.class);
constructor.setAccessible(true);
mWindow = (Window) constructor.newInstance(mContext);
} catch (Exception e) {
e.printStackTrace();
if (mContext instanceof Activity) {
mWindow = ((Activity) mContext).getWindow();
}
}
mWindow.setWindowManager(mWindowManager, null, null);
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
mDecor = mWindow.getDecorView();
mDecor.setOnTouchListener(mTouchListener);
mWindow.setContentView(this);
mWindow.setBackgroundDrawableResource(android.R.color.transparent);
// While the media controller is up, the volume control keys should
// affect the media stream type
mWindow.setVolumeControlStream(AudioManager.STREAM_MUSIC);
setFocusable(true);
setFocusableInTouchMode(true);
setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
requestFocus();
}
再来是 makeControllerView 方法中,定义各自需要的 UI 效果,
private void initControllerView(View v) {
Resources res = mContext.getResources();
mPlayDescription = res.getText(R.string.lockscreen_transport_play_description);
mPauseDescription = res.getText(R.string.lockscreen_transport_pause_description);
mRelativeVideo = v.findViewById(R.id.relativeVideo);
if (mRelativeVideo != null) {
mRelativeVideo.setOnClickListener(mRelativeVideoClick);
}
mPauseButton = v.findViewById(R.id.imgPlay);
if (mPauseButton != null) {
mPauseButton.requestFocus();
mPauseButton.setOnClickListener(mPauseListener);
}
mProgress = v.findViewById(R.id.seekVideo);
if (mProgress != null) {
if (mProgress instanceof SeekBar) {
SeekBar seeker = (SeekBar) mProgress;
seeker.setOnSeekBarChangeListener(mSeekListener);
}
mProgress.setMax(1000);
}
mEndTime = v.findViewById(R.id.txtDuration);
mCurrentTime = v.findViewById(R.id.txtCurrentTime);
mFormatBuilder = new StringBuilder();
mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());
}
注意如果不重写 Error 监听器,IJKPlayer 在播放出错的时候将会弹出一个很丑的弹窗,并且点击弹窗的确认,调用了 onComplete() 方法
四、最后
Demo 的效果图如下,如果需要看源码的,可以转到 GitHub