Flutter安卓应用设置壁纸后崩溃(仅红米设备出现)
问题背景
应用设置壁纸后立即卡顿并崩溃,壁纸配置为每分钟自动更换。该问题仅在红米设备(MIUI系统)上出现,诺基亚设备无异常。
核心代码逻辑
通过AndroidAlarmManager.periodic周期性调用myfunction实现自动换壁纸:
static Future<void> myfunction()async{ final response = await http.get(Uri.parse("my url here")); var jsonData = json.decode(response.body); results = jsonData; var url = results["urls"]["full"]; String result; var progressString = Wallpaper.imageDownloadProgress(url); progressString.listen((data) { print("DataReceived: " + data); }, onDone: () async { if (Globals.selectedScreen.toString() == 'home') { try { await Wallpaper.homeScreen(); } catch (e) { debugPrint(e); } } else if (Globals.selectedScreen.toString() == 'lock') { try { await Wallpaper.lockScreen(); } catch (e) { debugPrint(e); } } else { try { await Wallpaper.bothScreen(); } catch (e) { debugPrint(e); } } }); }
崩溃日志(中文翻译)
DataReceived: 100%
W/MIUIScout App(13194): 进入APP_SCOUT_WARNING状态
W/MIUIScout App(13194): 事件:APP_SCOUT_WARNING 线程:main 调用栈:
W/MIUIScout App(13194): at android.graphics.Bitmap.nativeCompress(Native Method)
W/MIUIScout App(13194): at android.graphics.Bitmap.compress(Bitmap.java:1445)
W/MIUIScout App(13194): at android.app.WallpaperManager.setBitmap(WallpaperManager.java:1535)
W/MIUIScout App(13194): at android.app.WallpaperManager.setBitmap(WallpaperManager.java:1506)
W/MIUIScout App(13194): at com.prateektimer.wallpaper.WallpaperPlugin.setHomeLockScreen(WallpaperPlugin.java:182)
W/MIUIScout App(13194): at com.prateektimer.wallpaper.WallpaperPlugin.onMethodCall(WallpaperPlugin.java:91)
W/MIUIScout App(13194): at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:262)
W/MIUIScout App(13194): at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(DartMessenger.java:295)
W/MIUIScout App(13194): at io.flutter.embedding.engine.dart.DartMessenger.lambda$dispatchMessageToQueue$0$DartMessenger(DartMessenger.java:319)
W/MIUIScout App(13194): at io.flutter.embedding.engine.dart.-$$Lambda$DartMessenger$TsixYUB5E6FpKhMtCSQVHKE89gQ.run(Unknown Source:12)
W/MIUIScout App(13194): at android.os.Handler.handleCallback(Handler.java:938)
W/MIUIScout App(13194): at android.os.Handler.dispatchMessage(Handler.java:99)
W/MIUIScout App(13194): at android.os.Looper.loopOnce(Looper.java:210)
W/MIUIScout App(13194): at android.os.Looper.loop(Looper.java:299)
W/MIUIScout App(13194): at android.app.ActivityThread.main(ActivityThread.java:8168)
W/MIUIScout App(13194): at java.lang.reflect.Method.invoke(Native Method)
W/MIUIScout App(13194): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:556)
W/MIUIScout App(13194): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1037)
I/libc (13194): 请求为线程13194 (ample.app)生成崩溃转储
问题分析
从日志可以定位,崩溃发生在Bitmap.nativeCompress方法,即系统压缩Bitmap为壁纸格式的环节。MIUI的APP_SCOUT机制触发警告,说明主线程被耗时操作阻塞,超过了MIUI的监控阈值,核心原因包括:
- 下载的原图分辨率过高,压缩时占用大量主线程资源
- 壁纸设置操作直接在主线程执行,MIUI对主线程耗时管控比其他安卓系统更严格
- 使用的
Wallpaper插件未针对MIUI做后台线程优化,导致主线程阻塞
解决方案
1. 将壁纸设置移到后台线程
用Flutter的compute函数将耗时操作转移到后台线程,避免阻塞主线程:
// 封装壁纸设置逻辑 Future<void> _setWallpaper() async { switch(Globals.selectedScreen.toString()) { case 'home': try { await Wallpaper.homeScreen(); } catch(e) { debugPrint(e.toString()); } break; case 'lock': try { await Wallpaper.lockScreen(); } catch(e) { debugPrint(e.toString()); } break; default: try { await Wallpaper.bothScreen(); } catch(e) { debugPrint(e.toString()); } } } // 修改onDone回调 progressString.listen((data) { print("DataReceived: " + data); }, onDone: () async { await compute(_setWallpaper, null); });
2. 压缩图片后再设置
先将下载的图片压缩到适配设备屏幕的尺寸,减少Bitmap内存占用:
可使用flutter_image_compress插件实现:
import 'package:flutter_image_compress/flutter_image_compress.dart'; import 'package:path_provider/path_provider.dart'; import 'dart:io'; // 下载并压缩图片 Future<String> _downloadAndCompressImage(String url) async { final response = await http.get(Uri.parse(url)); final tempDir = await getTemporaryDirectory(); final tempFile = File('${tempDir.path}/temp_wp.jpg'); await tempFile.writeAsBytes(response.bodyBytes); // 压缩到设备屏幕尺寸(需替换为实际设备分辨率) final compressedFile = await FlutterImageCompress.compressAndGetFile( tempFile.path, '${tempDir.path}/compressed_wp.jpg', quality: 80, width: 1080, height: 2340, ); return compressedFile!.path; } // 修改myfunction逻辑 static Future<void> myfunction()async{ final response = await http.get(Uri.parse("my url here")); var jsonData = json.decode(response.body); var url = jsonData["urls"]["full"]; // 先压缩图片 final compressedPath = await _downloadAndCompressImage(url); // 若插件支持本地路径,直接传入设置;否则需将文件转为Bitmap后处理 }
3. 优化周期性任务
- 添加任务锁,避免前一次壁纸设置未完成时启动新任务,防止资源冲突
- 增加错误重试机制,避免单次失败直接崩溃
- 锁屏时暂停任务,减少不必要的资源消耗
4. MIUI适配调整
- 确认应用已申请必要权限(如安卓10以下的
WRITE_EXTERNAL_STORAGE) - 临时关闭开发者选项中的APP Scout监控(仅用于测试,不建议作为最终方案)
内容的提问来源于stack exchange,提问作者abhijith k sabu

