Kotlin添加窗口报错
Process: 包名, PID: 27541
android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?
at android.view.ViewRootImpl.setView(ViewRootImpl.java:980)
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:398)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:96)
报错描述: 通过在当前Service服务中动态wm.addView(view, lp)
添加一个window窗口。执行时报错,错误信息如上面代码片。该服务Service启动于MainAcitivity并作为前台服务一直处于保活状态。
创建窗口代码
import android.content.Context
import android.graphics.PixelFormat
import android.os.Build
import android.util.Log
import android.view.Gravity
import android.view.View
import android.view.WindowManager
/**
* WindowCreated.kt 添加窗口类
*/
object WindowCreated {
private lateinit var context: Context
private lateinit var wm: WindowManager
private lateinit var lp: WindowManager.LayoutParams
fun initWindow(context: Context) {
this.context = context
this.wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
lp = createLayoutParams()
}
// 创建布局属性
fun createLayoutParams(): WindowManager.LayoutParams {
val lp = WindowManager.LayoutParams()
lp.apply {
this.width = WindowManager.LayoutParams.MATCH_PARENT
this.height = WindowManager.LayoutParams.MATCH_PARENT
gravity = Gravity.CENTER
format = PixelFormat.TRANSLUCENT
flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON or
WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
// >= 8.0
type = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY
else
WindowManager.LayoutParams.TYPE_PHONE
}
return lp
}
// 获取视图控件
fun getView(layoutId: Int): View {
return View.inflate(context, layoutId, null)
}
// 显示窗口
fun showWindowView(view: View) {
Log.e("=====com.wensi显示窗口=====", view.toString())
if (view.parent == null) {
wm.addView(view, lp)
}
}
fun showWindowView(view: View, lp: WindowManager.LayoutParams) {
if (view.parent == null) {
wm.addView(view, lp)
}
}
// 隐藏窗口
fun hideWindowView(view: View) {
if (view.parent == null) {
// 不等于空,说明正在显示
wm.removeView(view)
}
}
// 更新视图
fun updateWindowView(view: View, lp: WindowManager.LayoutParams) {
wm.updateViewLayout(view, lp)
}
}
之后在Service服务方法override fun onCreate()
中初始化窗口及布局
WindowCreated.initWindowHelper(this) // 初始化窗口
fullWindowView = WindowCreated.getView(R.layout.layout_window_item)
然后通过用户触发事件激活并添加窗口
WindowCreated.showWindowView(fullWindowView)
但执行后报错。后来经过逐步排查,窗口权限已添加且申请
// 申请权限
protected fun requestWindowPermission(packageName: String) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // >= 23 6.0
startActivityForResult(
Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:$packageName")),
codeWindowPermission) // codeWindowPermission = 1000
}
}
排查方向不对: 业务逻辑代码也无问题,即不存在popWindow
初始化显示窗口过早问题。
排查方向不对: 为避免出现类似new AlertDialog.Builder(context)
一样的问题,尝试将context指向Activity。
后经过查看源码即第37行布局属性发现了问题:(不小心赋值变量错误导致)
应用必须使用名为TYPE_APPLICATION_OVERLAY
的新窗口, 而不是TYPE_ACCESSIBILITY_OVERLAY
。