WebView中通过JavaScript设置FLAG_KEEP_SCREEN_ON报错的解决方法
问题
我希望在WebView内通过JavaScript启用或禁用screen_on(屏幕常亮)功能,尝试了以下代码:
@JavascriptInterface fun setScreenOn(screenOn: Boolean) { val window = m_Activity.window if (screenOn) { Log.d("screen", "addFlag") window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) } else { Log.d("screen", "clearFlag") window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) } }
但运行时抛出异常:
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. Expected: main Calling: JavaBridge at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:11023) at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:2473) at android.view.View.requestLayout(View.java:28020) at android.view.View.setLayoutParams(View.java:20530) at android.view.WindowManagerGlobal.updateViewLayout(WindowManagerGlobal.java:464) at android.view.WindowManagerImpl.updateViewLayout(WindowManagerImpl.java:165) at android.app.Activity.onWindowAttributesChanged(Activity.java:4364) at android.view.Window.dispatchWindowAttributesChanged(Window.java:1323) at com.android.internal.policy.PhoneWindow.dispatchWindowAttributesChanged(PhoneWindow.java:3193) at android.view.Window.setFlags(Window.java:1309) at android.view.Window.clearFlags(Window.java:1283)
异常提示“Only the original thread that created a view hierarchy can touch its views.”,请问是否无法通过JavaScript修改FLAG_KEEP_SCREEN_ON?或有什么可行的解决办法?
解答
不是不能通过JavaScript修改FLAG_KEEP_SCREEN_ON,问题核心是线程调用错误:
WebView的@JavascriptInterface方法默认在JavaBridge线程执行,而Android规定所有操作View层级的代码必须在**主线程(UI线程)**运行,这就是触发CalledFromWrongThreadException的原因。
解决办法1:切换到主线程执行窗口标志位修改
利用Activity的runOnUiThread方法,把修改Window标志位的逻辑包裹在主线程任务中:
@JavascriptInterface fun setScreenOn(screenOn: Boolean) { m_Activity.runOnUiThread { val window = m_Activity.window if (screenOn) { Log.d("screen", "addFlag") window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) } else { Log.d("screen", "clearFlag") window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) } } }
解决办法2:通过View的keepScreenOn属性控制
在布局中添加一个不可见的View,通过动态修改它的keepScreenOn属性实现屏幕常亮控制,效果和修改Window标志位一致,代码更简洁:
<!-- 在Activity布局中添加一个隐藏的View --> <View android:id="@+id/keep_screen_trigger" android:layout_width="0dp" android:layout_height="0dp" />
private val keepScreenTrigger: View = m_Activity.findViewById(R.id.keep_screen_trigger) @JavascriptInterface fun setScreenOn(screenOn: Boolean) { m_Activity.runOnUiThread { keepScreenTrigger.keepScreenOn = screenOn Log.d("screen", if (screenOn) "开启屏幕常亮" else "关闭屏幕常亮") } }
内容的提问来源于stack exchange,提问作者Lorenz Meyer
相关产品推荐
相关产品推荐

