参照网上的壁纸 WallpaperService 教程,在相册里选择若干图片
地址 uri 使用 SharedPreference 永久保存防止丢失
正常使用时没有任何问题,每次锁屏切换下一张壁纸
但是手机重启就会丢失壁纸
我做了多次尝试,比如只选择一张壁纸不会丢失
只要是两张以上手机重启,壁纸就会丢失
不知道是哪里出了问题?
我以前使用的一款壁纸 SB_Wallpaper 软件就没有此种问题
不知道你这里是否有办法解决?
手机重启壁纸就会丢失问题
- 写回答
- 好问题 0 提建议
- 关注问题
- 邀请回答
-
2条回答 默认 最新
极客车云 2026-03-17 00:11关注针对手机重启后壁纸丢失的问题,我会从WallpaperService的工作机制、SharedPreferences的可靠性和系统重启后的恢复逻辑三个核心维度,为你提供完整的解决方案:
一、问题根本原因分析
- 系统层面: Android重启后会重新调用
WallpaperService的onCreate()方法,若没有自动恢复壁纸的逻辑,系统会默认使用静态壁纸或纯色背景 - 存储层面: 你用
SharedPreferences保存的Uri可能是临时Uri(如相册选择的content://开头的Uri),重启后权限失效 - 服务层面:
WallpaperService没有在重启后自动加载之前保存的壁纸配置
二、完整解决方案代码实现
1. 核心修改:在WallpaperService中添加重启恢复逻辑
class MyLiveWallpaperService : WallpaperService() { private lateinit var prefs: SharedPreferences private var wallpaperUris: MutableList<String> = mutableListOf() private var currentIndex = 0 override fun onCreate() { super.onCreate() prefs = getSharedPreferences("WallpaperPrefs", MODE_PRIVATE) // 重启后恢复之前的壁纸配置 restoreWallpaperConfig() } // 恢复保存的壁纸列表和当前索引 private fun restoreWallpaperConfig() { val urisString = prefs.getString("wallpaper_uris", "") if (!urisString.isNullOrEmpty()) { wallpaperUris = urisString.split(",").toMutableList() } currentIndex = prefs.getInt("current_index", 0) } // 保存壁纸配置到SharedPreferences private fun saveWallpaperConfig() { prefs.edit() .putString("wallpaper_uris", wallpaperUris.joinToString(",")) .putInt("current_index", currentIndex) .apply() } override fun onCreateEngine(): Engine { return MyWallpaperEngine() } inner class MyWallpaperEngine : Engine() { private var handler = Handler(Looper.getMainLooper()) private val updateRunnable = Runnable { if (wallpaperUris.isNotEmpty()) { drawWallpaper() currentIndex = (currentIndex + 1) % wallpaperUris.size saveWallpaperConfig() // 每次切换都保存当前状态 handler.postDelayed(updateRunnable, 10000) // 10秒切换一次 } } override fun onVisibilityChanged(visible: Boolean) { super.onVisibilityChanged(visible) if (visible) { handler.post(updateRunnable) } else { handler.removeCallbacks(updateRunnable) } } private fun drawWallpaper() { val surfaceHolder = surfaceHolder ?: return val canvas = surfaceHolder.lockCanvas() ?: return try { val uri = Uri.parse(wallpaperUris[currentIndex]) // 使用ContentResolver获取Bitmap,避免权限问题 val bitmap = contentResolver.openInputStream(uri)?.use { BitmapFactory.decodeStream(it) } bitmap?.let { // 缩放图片适配屏幕 val scaleX = canvas.width.toFloat() / it.width val scaleY = canvas.height.toFloat() / it.height val scale = max(scaleX, scaleY) val scaledBitmap = Bitmap.createScaledBitmap(it, (it.width * scale).toInt(), (it.height * scale).toInt(), true) val x = (canvas.width - scaledBitmap.width) / 2f val y = (canvas.height - scaledBitmap.height) / 2f canvas.drawBitmap(scaledBitmap, x, y, null) } } catch (e: Exception) { e.printStackTrace() // 处理Uri失效的情况,移除无效的Uri wallpaperUris.removeAt(currentIndex) currentIndex = currentIndex % wallpaperUris.size saveWallpaperConfig() } finally { surfaceHolder.unlockCanvasAndPost(canvas) } } } }2. 添加开机自启广播接收器(关键!)
创建
BootCompleteReceiver.kt,监听系统开机完成广播,主动设置壁纸:class BootCompleteReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (Intent.ACTION_BOOT_COMPLETED == intent.action) { // 开机后重新设置动态壁纸 val wallpaperIntent = Intent(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER) wallpaperIntent.putExtra( WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT, ComponentName(context, MyLiveWallpaperService::class.java) ) wallpaperIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) context.startActivity(wallpaperIntent) } } }3. 在AndroidManifest.xml中配置权限和组件
<manifest ...> <!-- 开机自启权限 --> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <!-- 读取外部存储权限(针对旧系统) --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <!-- Android 13+ 读取媒体图片权限 --> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <application ...> <!-- 注册动态壁纸服务 --> <service android:name=".MyLiveWallpaperService" android:label="我的动态壁纸" android:permission="android.permission.BIND_WALLPAPER"> <intent-filter> <action android:name="android.service.wallpaper.WallpaperService" /> </intent-filter> <meta-data android:name="android.service.wallpaper" android:resource="@xml/wallpaper" /> </service> <!-- 注册开机广播接收器 --> <receiver android:name=".BootCompleteReceiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver> </application> </manifest>4. 优化Uri存储:使用持久化Uri(避免重启后权限失效)
在选择图片的Activity中,使用
takePersistableUriPermission获取永久访问权限:// 选择图片后的处理 override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == REQUEST_SELECT_WALLPAPER && resultCode == RESULT_OK) { data?.data?.let { uri -> // 获取永久访问权限 contentResolver.takePersistableUriPermission( uri, Intent.FLAG_GRANT_READ_URI_PERMISSION ) // 保存Uri到SharedPreferences val prefs = getSharedPreferences("WallpaperPrefs", MODE_PRIVATE) val uris = prefs.getString("wallpaper_uris", "")?.split(",")?.toMutableList() ?: mutableListOf() uris.add(uri.toString()) prefs.edit() .putString("wallpaper_uris", uris.joinToString(",")) .apply() } } }
三、关键注意事项
- 权限问题:
- Android 13+ 需要申请
READ_MEDIA_IMAGES权限 - 必须使用
takePersistableUriPermission获取永久Uri权限,避免重启后访问被拒绝
- Android 13+ 需要申请
- SharedPreferences可靠性:
- 建议使用
apply()而非commit(),前者是异步操作更高效 - 不要存储过大的数据,壁纸列表建议限制在50张以内
- 建议使用
- 性能优化:
- 在
drawWallpaper()中对Bitmap进行缩放,避免OOM - 在
onVisibilityChanged()中暂停/恢复壁纸切换,节省电量
- 在
- 兼容性:
- 部分定制ROM可能会限制开机自启,需要引导用户手动开启应用的自启权限
- Android 8.0+ 对后台启动有严格限制,开机广播可能需要配合前台服务
四、额外增强方案
- 添加默认壁纸: 在
restoreWallpaperConfig()中如果没有保存的Uri,添加内置的默认壁纸 - 错误处理: 检测到无效Uri时自动从列表中移除
- 预览功能: 在设置Activity中添加壁纸预览
- 定时切换: 允许用户自定义切换间隔时间
通过以上方案,你的动态壁纸在手机重启后就能自动恢复之前的配置,不会再出现丢失的问题。
本回答被题主选为最佳回答 , 对您是否有帮助呢?评论 打赏 举报解决 1无用- 系统层面: Android重启后会重新调用