lling0028 2026-03-16 13:56 采纳率: 50%
浏览 15
已采纳

手机重启壁纸就会丢失问题

参照网上的壁纸 WallpaperService 教程,在相册里选择若干图片
地址 uri 使用 SharedPreference 永久保存防止丢失
正常使用时没有任何问题,每次锁屏切换下一张壁纸
但是手机重启就会丢失壁纸
我做了多次尝试,比如只选择一张壁纸不会丢失
只要是两张以上手机重启,壁纸就会丢失
不知道是哪里出了问题?
我以前使用的一款壁纸 SB_Wallpaper 软件就没有此种问题
不知道你这里是否有办法解决?

  • 写回答

2条回答 默认 最新

  • 极客车云 2026-03-17 00:11
    关注

    针对手机重启后壁纸丢失的问题,我会从WallpaperService的工作机制SharedPreferences的可靠性系统重启后的恢复逻辑三个核心维度,为你提供完整的解决方案:

    一、问题根本原因分析

    1. 系统层面: Android重启后会重新调用WallpaperServiceonCreate()方法,若没有自动恢复壁纸的逻辑,系统会默认使用静态壁纸或纯色背景
    2. 存储层面: 你用SharedPreferences保存的Uri可能是临时Uri(如相册选择的content://开头的Uri),重启后权限失效
    3. 服务层面: 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()
            }
        }
    }
    

    三、关键注意事项

    1. 权限问题:
      • Android 13+ 需要申请READ_MEDIA_IMAGES权限
      • 必须使用takePersistableUriPermission获取永久Uri权限,避免重启后访问被拒绝
    2. SharedPreferences可靠性:
      • 建议使用apply()而非commit(),前者是异步操作更高效
      • 不要存储过大的数据,壁纸列表建议限制在50张以内
    3. 性能优化:
      • drawWallpaper()中对Bitmap进行缩放,避免OOM
      • onVisibilityChanged()中暂停/恢复壁纸切换,节省电量
    4. 兼容性:
      • 部分定制ROM可能会限制开机自启,需要引导用户手动开启应用的自启权限
      • Android 8.0+ 对后台启动有严格限制,开机广播可能需要配合前台服务

    四、额外增强方案

    1. 添加默认壁纸:restoreWallpaperConfig()中如果没有保存的Uri,添加内置的默认壁纸
    2. 错误处理: 检测到无效Uri时自动从列表中移除
    3. 预览功能: 在设置Activity中添加壁纸预览
    4. 定时切换: 允许用户自定义切换间隔时间

    通过以上方案,你的动态壁纸在手机重启后就能自动恢复之前的配置,不会再出现丢失的问题。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

问题事件

  • 已采纳回答 3月18日
  • 创建了问题 3月16日