You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter(仅Android)自定义应用无法显示问题求助

排查device_apps库无法展示指定包名应用的问题

问题

使用device_apps库展示指定包名的自定义应用,点击Custom Apps按钮后无任何内容显示。

代码错误分析

  1. myApps初始化错误
    原代码中late Future<List<Application>>? myApps = [] as Future<List<Application>>?;是错误的强制类型转换,把空列表直接转为Future对象,导致后续无法正确向列表添加应用。

  2. loadMyApps方法逻辑错误
    通过then和whenComplete嵌套操作myApps的Future结果,这种方式不仅逻辑混乱,还无法正确收集应用数据。应该创建普通列表,逐个获取应用并添加。

  3. FutureBuilder重复调用loadMyApps
    每次build都会调用loadMyApps(),导致重复发起请求,同时没有正确利用Future的生命周期。

  4. FutureBuilder状态判断不准确
    原代码只判断data.data == null,忽略了Future的连接状态,会导致初始状态一直显示加载指示器,而数据返回后也无法正确渲染。

修复后的代码

import 'package:device_apps/device_apps.dart';
import 'package:flutter/material.dart';

class CustomApps extends StatefulWidget {
  const CustomApps({super.key});

  @override
  State<CustomApps> createState() => _CustomAppsState();
}

class _CustomAppsState extends State<CustomApps> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Custom Apps"),
      ),
      body: const _CustomAppsList(),
    );
  }
}

class _CustomAppsList extends StatefulWidget {
  const _CustomAppsList({Key? key}) : super(key: key);

  @override
  State<_CustomAppsList> createState() => _CustomAppsListState();
}

class _CustomAppsListState extends State<_CustomAppsList> {
  late Future<List<Application>> _myAppsFuture;

  Future<List<Application>> loadMyApps() async {
    final List<Application> apps = [];
    // 逐个获取应用并添加到列表
    final oneConnect = await DeviceApps.getApp('com.samsung.android.oneconnect');
    if (oneConnect != null) apps.add(oneConnect);

    final easyMover = await DeviceApps.getApp('com.sec.android.easyMover');
    if (easyMover != null) apps.add(easyMover);

    final timeZoneUpdate = await DeviceApps.getApp('com.samsung.android.timezone.autoupdate_O');
    if (timeZoneUpdate != null) apps.add(timeZoneUpdate);

    return apps;
  }

  @override
  void initState() {
    super.initState();
    // 在initState中初始化Future,避免重复调用
    _myAppsFuture = loadMyApps();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<List<Application>>(
        future: _myAppsFuture,
        builder: (BuildContext context, AsyncSnapshot<List<Application>> snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return const Center(child: CircularProgressIndicator());
          } else if (snapshot.hasError) {
            return Center(child: Text('加载出错: ${snapshot.error}'));
          } else if (!snapshot.hasData || snapshot.data!.isEmpty) {
            return const Center(child: Text('没有找到指定应用'));
          } else {
            List<Application> apps = snapshot.data!;

            return Scrollbar(
              child: ListView.builder(
                  itemBuilder: (BuildContext context, int position) {
                    Application app = apps[position];
                    return Column(
                      children: <Widget>[
                        ListTile(
                          leading: app is ApplicationWithIcon
                              ? CircleAvatar(
                                  backgroundImage: MemoryImage(app.icon),
                                  backgroundColor: Colors.white,
                                )
                              : null,
                          onTap: () => onAppClicked(context, app),
                          title: Text('${app.appName} (${app.packageName})'),
                          subtitle: Text('Version: ${app.versionName}\n'
                              'System app: ${app.systemApp}\n'
                              'APK file path: ${app.apkFilePath}\n'
                              'Data dir: ${app.dataDir}\n'
                              'Installed: ${DateTime.fromMillisecondsSinceEpoch(app.installTimeMillis).toString()}\n'
                              'Updated: ${DateTime.fromMillisecondsSinceEpoch(app.updateTimeMillis).toString()}'),
                        ),
                        const Divider(
                          height: 1.0,
                        )
                      ],
                    );
                  },
                  itemCount: apps.length),
            );
          }
        });
  }
}

void onAppClicked(BuildContext context, Application app) {
  showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text(app.appName),
          actions: <Widget>[
            _AppButtonAction(
              label: '打开应用',
              onPressed: () => app.openApp(),
            ),
            _AppButtonAction(
              label: '打开应用设置',
              onPressed: () => app.openSettingsScreen(),
            ),
            _AppButtonAction(
              label: '卸载应用',
              onPressed: () async => app.uninstallApp(),
            ),
          ],
        );
      });
}

class _AppButtonAction extends StatelessWidget {
  final String label;
  final VoidCallback? onPressed;

  const _AppButtonAction({required this.label, this.onPressed});

  @override
  Widget build(BuildContext context) {
    return TextButton(
      onPressed: () {
        onPressed?.call();
        Navigator.of(context).maybePop();
      },
      child: Text(label),
    );
  }
}

修复说明

  • 把myApps改为_myAppsFuture,在initState中初始化,避免每次build重复加载数据。
  • 重构loadMyApps方法,使用普通列表逐个获取应用并添加,逻辑清晰且易维护。
  • 完善FutureBuilder的状态判断,增加加载中、错误、无数据的处理场景,提升用户体验。

内容的提问来源于stack exchange,提问作者Florentin Lupascu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 14:37:35