如何打造个性化安卓直播系统控制界面

为什么要写这篇文章呢?

  • Firsr​:直接集成ijkplayer的控制界面太丑了
  • Second​:无法满足我们的需求

我们来看下直接集成的ijkplayer控制界面:

如何打造个性化安卓直播系统控制界面_ide

是不是没法用,那么我们现在来自定义。

##自定义MediaController

首先我们先去看看ijplayer怎么做的,然后我们照葫芦画瓢,去修修改改。

直播系统###一、ijplayer的demo如何实现?

package tv.danmaku.ijk.media.example.widget.media;

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.ActionBar;
import android.util.AttributeSet;
import android.view.View;
import android.widget.MediaController;

import java.util.ArrayList;

public class AndroidMediaController extends MediaController implements IMediaController {
private ActionBar mActionBar;

public AndroidMediaController(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}

public AndroidMediaController(Context context, boolean useFastForward) {
super(context, useFastForward);
initView(context);
}

public AndroidMediaController(Context context) {
super(context);
initView(context);
}

private void initView(Context context) {
}

public void setSupportActionBar(@Nullable ActionBar actionBar) {
mActionBar = actionBar;
if (isShowing()) {
actionBar.show();
} else {
actionBar.hide();
}
}

@Override
public void show() {
super.show();
if (mActionBar != null)
mActionBar.show();
}

@Override
public void hide() {
super.hide();
if (mActionBar != null)
mActionBar.hide();
for (View view : mShowOnceArray)
view.setVisibility(View.GONE);
mShowOnceArray.clear();
}

//----------
// Extends
//----------
private ArrayList<View> mShowOnceArray = new ArrayList<View>();

public void showOnce(@NonNull View view) {
mShowOnceArray.add(view);
view.setVisibility(View.VISIBLE);
show();
}
}

例子中​​AndroidMediaController​​的功能主要是支持将顶部的toolbar和MediaController绑定在一起,一起show/hide.

从上面代码可以看出来​​AndroidMediaController​​​集成自​​MediaController​​​也就是说,主要功能是在​​android.widget.MediaController​​实现的。

那么我们想要打造个性控制界面,就需要移植​​MediaController​​然后做定制。

###二、MediaController的解读

先来看一下API:

如何打造个性化安卓直播系统控制界面_android_02

一个包含媒体播放器(MediaPlayer)控件的视图。包含了一些典型的按钮,像"播放(Play)/暂停(Pause)", “倒带(Rewind)”, "快进(Fast Forward)"与进度滑动器(progress slider)。它管理媒体播放器(MediaController)的状态以保持控件的同步。

直播系统

通过编程来实例化使用这个类。这个媒体控制器将创建一个具有默认设置的控件,并把它们放到一个窗口里漂浮在你的应用程序上。具体来说,这些控件会漂浮在通过setAnchorView()指定的视图上。如果这个窗口空闲3秒那么它将消失,直到用户触摸这个视图的时候重现。

当媒体控制器是在一个XML布局资源文件中创建的时候,像show()和 hide()这些函数是无效的。媒体播放器将根据这些规则去显示和隐藏:

  • 在调用setPrevNextListeners()函数之前,"previous"和 "next"按钮都是隐藏的。

  • 如果setPrevNextListeners()函数被调用但传入的监听器参数是null,那么"previous"和 "next"按钮是可见的但是处于禁用状态。

  • “rewind” 和 "fastforward"按钮是显示的,如果不需要可以使用构造函数MediaController(Context, boolean)将boolean设置为false。

如何打造个性化安卓直播系统控制界面_ide_03

几个重要方法解析:


public void hide ()从屏幕中移除控制器。



public boolean isShowing ()判断媒体控制器是否处于可见状态



public void onFinishInflate ()XML文件加载视图完成时调用。这个函数在加载的最后阶段被调用,所有的子视图已经被添加。即使子类重写了onFinishInflate方法,也应该始终确保调用父类方法,以便我们调用



public void setAnchorView (View view)设置这个控制器绑定(anchor/锚)到一个视图上。例如可以是一个VideoView对象,或者是你的activity的主视图。



public void setMediaPlayer (MediaController.MediaPlayerControl player)把这个媒体控制器设置到VideoView对象上。



public void setPrevNextListeners (View.OnClickListener next, View.OnClickListener prev)设置"previous"和 "next"按钮的监听器函数。



public void show (int timeout)在屏幕上显示这个控制器。它将在闲置’超时 (timeout)’毫秒到达后自动消失。参数:timeout 这个参数以毫秒为单位。如果设置为0将一直显示到调用hide()函数为止。


​android.widget.MediaController​​​就了解到这里,我们接下来要做的就是,copy一份​​android.widget.MediaController​​然后进行个性化定制。

直播系统

###三、移植mediaController

第一步:

首先创建一个自定义的​​mediaController​​,我们这里叫 ​​MyMediaController​​,代码原封不动的把​​android.widget.MediaController​​拷进来。

如何打造个性化安卓直播系统控制界面_android_04

上图左侧是安卓的MediaController,右侧是我们自定义的​​mediaController​

第二步:

接下来我们去改造里面:这里我们需要注意一下接下来要创建的​​PhoneWindow​​对象。

如图右侧是我们的改造方案:

如何打造个性化安卓直播系统控制界面_ide_05

那么为什么要这样改造呢?

因为​​PhoneWindow​​是隐藏API,我们没法直接使用(文章结尾会补充该知识点)。所以我们需要通过反射去获取。

代码如下:

try {
Class clazz = Class.forName("com.android.internal.policy.impl.PhoneWindow");
Constructor constructor = clazz.getDeclaredConstructor(Context.class);
mWindow = (Window) constructor.newInstance(mContext);
} catch (Exception e) {
e.printStackTrace();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

第三步:

更换布局文件:

如何打造个性化安卓直播系统控制界面_ide_06

只需​​mRoot = inflate.inflate(R.layout.media_my_controller, null);​​更换布局文件,布局文件根据ui设计的就可以。

直播系统

这里我们可以自己设计我们的控制界面喽!! 让我们看一下效果:

如何打造个性化安卓直播系统控制界面_jar_07

到这里我们ijkplayer打造个性化控制界面就完成了,不过这里给大家补充一个知识点,就是上面说到的隐藏API。

##补充知识点

//======知识点>

上面我们说到​​PhoneWindow​​不能直接使用,而是要通过反着,那么我们先来看下​​PhoneWindow​​类。

我们看到注释上面会有​​@hide​​,也就是说​​@hide​​标记的类和函数称为隐藏API,不能被开发者直接调用,除此之外还有位于包com.android.internal的内部API,也不可以被使用者直接调用,那么这两类API有什么不同呢?

如何打造个性化安卓直播系统控制界面_ide_08

###内部API和隐藏API的不同

隐藏API隐藏是为了防止开发人员使用SDK中未完成或者未稳定(接口和架构方面看)的部分。比如,Bluetooth API在API Level 5(android 2.0)之前就存在,但在API Level 3和4(android 1.5和1.6)中使用@hide隐藏起来了。当该API稳定下来,google的开发人员移除@hide属性,在API Level 5中就有Bluetooth API了。还有很多东西在Level 4和5之间发生了变化。如果程序依赖于某些隐藏API,可能会在新版本的Android OS上运行出现问题。

而内部API则不计划对外开放。这是android的内部餐厅,开发人员可以视为黑盒子。这里面的东西同样可能发生改变。同样的,如果您的程序依赖于内部API,在新的Android发布后,可能遇到麻烦。

直播系统


隐藏API = 正在开发中

内部API = 黑盒

###内部和隐藏API的编译时和运行时对比

当您使用Android SDK进行开发时,会引用一个非常重要的jar文件android.jar。它位于Android SDK的平台目录SDK_DIR/platforms/platform-X/android.jar(其中X为API Level,可以是5或者10或其它的数字)。在android.jar中,com.android.internal中所有的类移除了,同样的,所有标记为@hide的类、枚举、字段、方法也移除了。

但是当您在设备中运行应用程序时,加载的是framework.jar(大约等价于android.jar),它没有被裁减,包含所有的内部类和隐藏API。所以您可以使用反射机制来访问隐藏API和内部API