如何避免屏幕旋转时重新创建活动?
我使用导航组件在我的应用程序中使用单一活动模式。我使用 YouTube Android 库来播放视频。当我单击视频播放器上的全屏图标时,顶部和底部工具栏必须消失,并且必须在横向模式下更改屏幕。但屏幕旋转后,活动被重新创建,视频停止并重新开始。问题是屏幕旋转后如何继续播放视频? 我找到了一种将 configChanges 添加到清单文件的解决方案,
<activity
android:name=".ui.MainActivity"
android:configChanges="orientation|screenSize|keyboardHidden|smallestScreenSize|screenLayout" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
这解决了我的问题,当屏幕旋转时,活动停止重新创建。但我不希望在所有片段中出现这种行为,我只需要在视频播放器所在的片段中出现这种行为。
这是我在片段中的代码:
private fun fullScreenListener() {
val decorView = activity?.window?.decorView?.let {
val screenListener = object : YouTubePlayerFullScreenListener {
override fun onYouTubePlayerEnterFullScreen() {
binding.youtubePlayer.enterFullScreen()
hideSystemUi(it)
}
override fun onYouTubePlayerExitFullScreen() {
showSystemUi(it)
}
}
binding.youtubePlayer.addFullScreenListener(screenListener)
}
}
private fun hideSystemUi(view: View) {
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
MainActivity.hideBottomNavBar()
WindowCompat.setDecorFitsSystemWindows(requireActivity().window, false)
WindowInsetsControllerCompat(requireActivity().window,view).let { controller ->
controller.hide(WindowInsetsCompat.Type.systemBars())
controller.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
}
}
private fun showSystemUi(view: View) {
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
MainActivity.showBottomNavBar()
WindowCompat.setDecorFitsSystemWindows(requireActivity().window, true)
WindowInsetsControllerCompat(requireActivity().window, view).show(WindowInsetsCompat.Type.systemBars())
}
I use single Activity pattern in my app using Navigation component. I use YouTube Android library for playing the video. When I click full screen icon on video player the top and bottom tool bars have to be gone and the screen has to be changed on landscape mode. But after the screen has rotated the activity was recreated and video stops and starts over. The question is how to keep playing the video after the screen has rotated?
I found one solution to add configChanges
to the manifest file
<activity
android:name=".ui.MainActivity"
android:configChanges="orientation|screenSize|keyboardHidden|smallestScreenSize|screenLayout" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
This solved my problem, the activity stopped being recreated when the screen was rotated. But I do not want this behavior in all fragments, I need it only in the fragment where the video player is located.
This is my code in Fragment:
private fun fullScreenListener() {
val decorView = activity?.window?.decorView?.let {
val screenListener = object : YouTubePlayerFullScreenListener {
override fun onYouTubePlayerEnterFullScreen() {
binding.youtubePlayer.enterFullScreen()
hideSystemUi(it)
}
override fun onYouTubePlayerExitFullScreen() {
showSystemUi(it)
}
}
binding.youtubePlayer.addFullScreenListener(screenListener)
}
}
private fun hideSystemUi(view: View) {
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
MainActivity.hideBottomNavBar()
WindowCompat.setDecorFitsSystemWindows(requireActivity().window, false)
WindowInsetsControllerCompat(requireActivity().window,view).let { controller ->
controller.hide(WindowInsetsCompat.Type.systemBars())
controller.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
}
}
private fun showSystemUi(view: View) {
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
MainActivity.showBottomNavBar()
WindowCompat.setDecorFitsSystemWindows(requireActivity().window, true)
WindowInsetsControllerCompat(requireActivity().window, view).show(WindowInsetsCompat.Type.systemBars())
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
抱歉,我不是 kotlin 开发人员,但这个解决方案修复了我的问题。但在我发布代码之前,让我向您解释一下,虽然它不是最可靠但更好的选择。
举例来说,您将此行添加到清单文件中。
现在,我将向您证明添加上述行根本不是一个选项:
首先,假设此行仍在您的清单文件中,那么如果您的应用程序面向 Api 级别 29 及以上,请切换 Android 系统 ui深色模式位于设置>;显示&亮度>深色主题然后返回到您的应用,您会注意到您的活动已重新创建并且视频重新启动。
现在,为了避免这种情况,您需要将 Uimode 添加到上面的代码行。
(注意它和第一个代码之间的区别)
现在您已经将 uimode 添加到了 configChanges,当 Android 系统 ui 暗模式开关切换时,特定的 Activity 将无法检测到更改。但它仍然不是最好的,因为它会导致以下问题:
无论如何,有太多的配置更改会导致活动重新启动,而不是添加此行并每次更改 configChanges 属性,只需使用:
现在,如果你想使用方法1,你需要了解首先使用 Android 生命周期架构组件,然后使用 onSavedInsatnceState 保存并使用onRestoreInsatnceState 恢复用户界面状态。但根据 https://developer.android.com/reference/android/app/Activity
将此声明为全局变量
覆盖 onSavedInsatnceState 方法并添加以下代码。
然后重写 onRestoreInstanceState 并添加以下行。
最后,如果 onRestoreInstanceState 未被调用,则重写 onResume 方法并添加以下代码行。
}
现在,在 onCreate 方法中,添加以下行
注意:
现在,如果你想使用第二种方法,即viewModel方法:
现在您可以从这里了解更多信息 https://www.geeksforgeeks.org/ viewmodel-with-savedstate-in-android/
请记住,我不是 kotlin 开发人员
Sorry i am not a kotlin developer, but this solution fixed mine. But before i post the codes, let me explain it to you, although it's not the most reliable but a better option.
Take for instance you added this line to your manifest file.
Now, i'll prove to you that adding above line is not an option at all:
Firstly, assuming this line is still in your manifest file, then if your app targets Api level 29 and above, toggle the android system ui dark mode which is located in Settings > Display & Brightness > Dark theme then return back to your app and you'll notice that your activity has been recreated and the video restarts.
Now, to avoid that, then you'll need to add Uimode to the above line of code.
(Notice the difference between it and the first code)
Now that you've added uimode to configChanges, the particular activity won't be able to detect changes when the android system ui dark mode switch is toggled. But it's still not the best because it will cause the following:
Anyways, there are so many configuration changes that will cause activity to restart and instead of adding this line and changing the configChanges attribute everytime just make use of the:
Now, if you want use method 1, you need to understand Android lifecycle architecture component first then use the onSavedInsatnceState to save and use the onRestoreInsatnceState to restore the ui states. But according to https://developer.android.com/reference/android/app/Activity
Declare this as global variable
Override onSavedInsatnceState method and add below codes.
Then override onRestoreInstanceState and add below lines.
Finally, incase onRestoreInstanceState is not called then override onResume method and add below lines of codes.
}
Now, in the onCreate method, add below lines
Note:
Now, if you want to use the second method which is viewModel method:
Now you can learn more from here https://www.geeksforgeeks.org/viewmodel-with-savedstate-in-android/
Remember, i'm not a kotlin developer
你真的不想这样做。问题不仅仅是轮流重新启动,而是至少有十几种情况可能导致活动重新启动,并且您无法阻止其中一些情况。在 Android 上,这实际上只是您需要忍受的事情,并学习如何编码以使其干净地重新启动。
不,您不能在运行时或仅对某些片段执行 configChanges。它适用于活动级别。
相反,您应该问一个不同的问题 - 告诉用户轮换时哪些部分不起作用,并询问如何通过重新启动来解决该问题。
You really do not want to do this. The problem isn't just the restart on rotation, it's that there's at LEAST a dozen situations that can cause an Activity restart, and you can't block some of them. On Android this is really just something you need to live with, and learn how to code to make it cleanly restart.
And no, you can't do configChanges at runtime or only for some fragments. It works on an Activity level.
Instead, you should ask a different question- tell use what isn't working when you rotate, and ask how to fix that with restart.
根据您的新答案-我很惊讶您的视频视图在没有工作的情况下不支持这一点。但是,如果您实现 onSaveInstanceState 来保存视频的查找时间,并实现 onRestoreInstanceState 来查找该时间,则在读取视频时最多应该出现短暂的停顿。
Based on your new answer- I'm surprised your video view doesn't support this without work. However, if you implement onSaveInstanceState to save the seek time of the video and onRestoreInstanceState to seek to that time, it should work with at most a brief hiccup as it reads in the video.