公司需要,定制化开发一机双屏且两块屏幕显示不同信息、可进行不同操作的app。说直白一点,就是一个运行Android系统的主机连接了两块屏幕,运行一个app但是两块屏幕各自操作各自的互不干扰;

通常情况下,两块屏幕有主副的区别,主屏幕的实现和以往是一样的,副屏会有区别;

Presentation

android 中常用来实现副屏的API,主板可以有多个硬件显卡输出的接口,presentation 可以指定在哪个输出接口显示哪个页面,或者理解为,把哪个页面送到哪个输出接口去显示,这样就可以在两块或多个屏幕上显示不同的内容。这种情况下,副屏的实现类似一个特殊弹窗,这个弹窗覆盖在activity上,但是只在指定屏幕显示,这样主屏显示activity副屏显示弹窗就实现了双屏异显。

问题

主副屏:一主机带两块屏幕的情况,一般会默认区分主副屏,不需要presentation再去设定了;

显示:主屏无特殊情况,但是副屏会比较特殊,由于副屏是一个特殊的弹窗,那在弹窗上展示弹窗就会出现问题,副屏无法展示弹窗例如dialog和toast,目前没有找到办法实现,都是自己模拟的弹窗;

键盘:副屏无法调用键盘获得输入,网上信息据说有支持副屏录入的键盘,但是我没有找到,目前只能 模拟数字、字母和特殊符号的键盘,汉字很麻烦没有实现,但是车牌号这种限定范围的汉字键盘是有的;

闪屏:副屏不同界面在切换的时候可能会出现闪屏,副屏的界面切换是关掉副屏A打开副屏B,猜测测试,副屏的生命周期比较简单,特殊弹窗也是弹窗,弹窗关闭后会先去显示activity然后再打开另外一个弹窗,建议自己维护一个副屏的实例list,始终保持有一个副屏不被关闭,这样在切换过成中就不会闪屏了,当然记得关闭副屏的时候清空list;

持久:副屏是一个特殊弹窗,弹窗就要有所依凭,如果依赖activity,那关闭这个activity就会关闭副屏,建议使用aplicationcontext,这样切换activity就不会影响到副屏了;

尺寸:副屏的尺寸和主屏不太一样,同一个控件设定一样的宽高尺寸显示效果是不同的,在开发过程中需要单独调试;

示例:

private lateinit var presentationList: ArrayList<Presentation>//防止闪屏所以要保留至少一个副屏
private lateinit var displayM: Display
private lateinit var displayListener: DisplayManager.DisplayListener

/**
 * 获取屏幕管理控制器
 */
private fun handlePresentation() {
    presentationList = ArrayList()
    val mediaRouter = getSystemService(MEDIA_ROUTER_SERVICE) as MediaRouter
    val router = mediaRouter.getSelectedRoute(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG)
    val displays = router.presentationDisplay
    if (displays != null) {
        createDisplay(displays.displayId)
    }
}

/**
 * 获取屏幕控件
 * @param displayId Int
 */
private fun createDisplay(displayId: Int) {
    val displayManage = getSystemService(DISPLAY_SERVICE) as DisplayManager
    displayM = displayManage.getDisplay(displayId)

}

/**
 * 屏幕管理器监听
 * 当外接屏幕增加减少时
 */
private fun initDisplayListener() {
    displayListener = object : DisplayManager.DisplayListener {
        override fun onDisplayAdded(displayId: Int) {
            createDisplay(displayId)
        }

        override fun onDisplayRemoved(displayId: Int) {

        }

        override fun onDisplayChanged(displayId: Int) {
        }

    }
}

/**
*内存中只留取一个控制闪屏
*
**/
private fun presentationListCacheRemove() {
    if (presentationList.size > 1) {
        val tempPre = presentationList[0]
        tempPre.dismiss()
        presentationList.remove(tempPre)
    }
}

/**
*添加进入缓存
*
**/
private fun presentationListCacheAdd(tempP: Presentation) {
    presentationList.add(tempP)
}

/**
*实现副屏页面切换
*
**/
private fun showPresentation(presentation: BasePresentation) {
    presentationListCacheRemove()
    presentation.window?.setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
    presentation.show()
    presentationListCacheAdd(presentation)
}

fun aP() {
    val ap = Ap(this, displayM)
    showPresentation(ap)
}

fun bP() {
    val bP= Bp(this, displayM)
    showPresentation(bP)

}
/**
*清空所有缓存避免溢出
*
**/
fun pQuit() {
    if (presentationList.size > 0) {
        val tempPre = presentationList[0]
        tempPre.dismiss()
        presentationList.remove(tempPre)
    }
}