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

Flutter应用APK真机灰屏,模拟器正常问题排查

Flutter真机灰屏问题排查与修复

问题现象

应用在模拟器运行正常,但安装APK到真机后显示灰屏;接入自定义JsonString文件前功能正常,当前抛出错误:

════════ Exception caught by widgets library Incorrect use of ParentDataWidget. The itss ══════════════════════════════

怀疑问题出在ListView组件。


MainScreen代码

import 'package:dromis/feature/common/dr_app_bar_bottom.dart';
import 'package:dromis/feature/common/dr_bgr_for_main.dart';
import 'package:dromis/feature/common/dr_colors.dart';
import 'package:dromis/feature/common/dr_app_bar.dart';

import 'package:dromis/feature/dashboard/dashboard_screen.dart';
import 'package:dromis/feature/main/widgets/main_active_list.dart';
import 'package:dromis/feature/main/widgets/main_available_list.dart';
import 'package:dromis/feature/main/widgets/main_completed_list.dart';
import 'package:dromis/feature/utils/navigable.dart';
import 'package:dromis/feature/info/info_screen.dart';
import 'package:flutter/material.dart';


import '../../core/injection/configurator.dart';

import '../pulse/pulse_screen.dart';
import '../ranking/ranking_screen.dart';
import '../utils/routes.dart';
import 'bloc/active_list_bloc/active_list_bloc.dart';
import 'bloc/available_list_bloc/available_list_bloc.dart';
import 'bloc/completed_list_bloc/completed_list_bloc.dart';

class MainScreen extends StatefulWidget implements Navigable{

  @override
  String getName() => Routes.mainScreen;

  @override
  State<MainScreen> createState() => _MainScreenState();
}

class _MainScreenState extends State<MainScreen> {

  bool activeBool = true;
  bool availableBool = true;
  bool completedBool = true;

  final activeListBloc = getIt<ActiveListBloc>();
  final availableListBloc = getIt<AvailableListBloc>();
  final completedListBloc = getIt<CompletedListBloc>();

  @override
  Widget build(BuildContext context) {
    return DRBgrForMain(
      child: SafeArea(
        child: Scaffold(
            backgroundColor: Colors.transparent,
            appBar: PreferredSize(
              preferredSize: const Size.fromHeight(90.0),
              child: AppBar(
                backgroundColor: Colors.transparent,
                toolbarHeight: 90, 
                foregroundColor: Colors.transparent,
                shadowColor: Colors.transparent,
                leadingWidth: 0,
                centerTitle: false,
                elevation: 0.2,
                title: DRAppbar(moneyCount: '4,50', onTapFaq: (){
                 Navigator.push(
                 context,
                 FadeInRoute(
                  routeName: Routes.infoScreen,
                  page: InfoScreen(),
                  ),
                  );
                }, onTapMoneyCount: (){}, onTapProfile: (){}),
              ),
            ),
            bottomNavigationBar: BottomAppBar(child: DRAppBarBottom(onTapPlay: (){}, onTapDashBoard: (){
              Navigator.push(
                 context,
                 FadeInRoute(
                  routeName: Routes.dashboardScreen,
                  page: DashboardScreen(),
                  ),
                  );
            }, onTapRanking: (){
               Navigator.push(
                 context,
                 FadeInRoute(
                  routeName: Routes.rankingScreen,
                  page: RankingScreen(),
                  ),
                  );
            }, onTapPulse: (){
              Navigator.push(
                 context,
                 FadeInRoute(
                  routeName: Routes.pulseScreen,
                  page: PulseScreen(),
                  ),
                  );
            }, selectedPageNum: 1)),
            body: SingleChildScrollView(
                    child: Column(
                      children: [
                         Row(
                    children: [
                      const Spacer(flex: 1,),
                      Container(
                        height: 10,
                        width: 10,
                        decoration: BoxDecoration(
                          borderRadius: BorderRadius.circular(66),
                          color: DRColors.greenColor,
                        ),
                      ),
                      const SizedBox( width: 9, ),
                      InkWell(
                        splashColor: Colors.transparent,
                        highlightColor: Colors.transparent,
                        hoverColor: Colors.transparent,
                        onTap: () {
                          setState(() {
                            activeBool? activeBool = false: activeBool = true;
                          });
                        },
                        child: Row(
                          children: [
                            Text('ACTIVE',
                                style: TextStyle(
                                  color: Colors.white,
                                  fontFamily: 'Montserrat',
                                  fontWeight: FontWeight.w300,
                                  fontSize: 20,
                                ),
                            ),
                            const SizedBox( width: 7, ),
                            const SizedBox( width: 7, ),
                            Icon(activeBool? Icons.keyboard_arrow_down: Icons.keyboard_arrow_up,
                            color: DRColors.whiteTextColor,
                      ),
                          ],
                        ),
                      ),
                      
                      
                      const Spacer(flex: 9,),
        
                    ],
                  ),
                  const SizedBox(height: 5,),
                  ActiveListWidget(activeListBloc: activeListBloc, showAll: activeBool,),
                  const SizedBox(height: 10,),
                  Row(
                    children: [
                      const Spacer(flex: 1,),
                      Container(
                        height: 10,
                        width: 10,
                        decoration: BoxDecoration(
                          borderRadius: BorderRadius.circular(66),
                          color: Colors.yellow,
                        ),
                      ),
                      const SizedBox( width: 9, ),
                      InkWell(
                        splashColor: Colors.transparent,
                        highlightColor: Colors.transparent,
                        hoverColor: Colors.transparent,
                        onTap: () {
                          setState(() {
                            availableBool? availableBool = false: availableBool = true;
                          });
                        },
                        child: Row(
                          children: [
                            Text('AVAILABLE',
                                style: TextStyle(
                                  color: Color.fromARGB(255, 255, 255, 255),
                                  fontFamily: 'Montserrat',
                                  fontWeight: FontWeight.w300,
                                  letterSpacing: 1,
                                  fontSize: 19,
                                ),
                            ),
                             const SizedBox( width: 7, ),
                             Icon(availableBool? Icons.keyboard_arrow_down: Icons.keyboard_arrow_up,
                             color: DRColors.whiteTextColor,
                      ),
                      
                          ],
                        ),
                      ),
                      
                      const Spacer(flex: 8,),
        
                    ],
                  ),
                  const SizedBox(height: 5,),
                  AvailableListWidget(availableListBloc: availableListBloc, showAll: availableBool),
                  const SizedBox(height: 10,),
                   Row(
                    children: [
                      const Spacer(flex: 1,),
                      Container(
                        height: 10,
                        width: 10,
                        decoration: BoxDecoration(
                          borderRadius: BorderRadius.circular(66),
                          color: DRColors.inputTextColor,
                        ),
                      ),
                      const SizedBox( width: 9, ),
                      InkWell(
                        splashColor: Colors.transparent,
                        highlightColor: Colors.transparent,
                        hoverColor: Colors.transparent,
                        onTap: () {
                          setState(() {
                            completedBool? completedBool = false: completedBool = true;
                          });
                        },
                        child: Row(
                          children: [
                            Text('COMPLETED',
                                style: TextStyle(
                                  color: Colors.white,
                                  fontFamily: 'Montserrat',
                                  fontWeight: FontWeight.w300,
                                  letterSpacing: 1,
                                  fontSize: 19,
                                ),
                            ),
                            const SizedBox( width: 7, ),
                      Icon(completedBool? Icons.keyboard_arrow_down: Icons.keyboard_arrow_up,
                      color: DRColors.whiteTextColor,
                      ),
                          ],
                        ),
                      ),
                      
                      
                      const Spacer(flex: 7,),
        
                    ],
                  ),
                  const SizedBox(height: 5,),
                  CompletedListWidget(completedListBloc: completedListBloc, showAll: completedBool)
                      ],
                    ),
                  ),
                ),
        ),
              
              
            
          
      
    );
  }
}

列表组件代码

import 'package:dromis/feature/common/info_buttons_card/dr_info_cards_active.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

import '../bloc/active_list_bloc/active_list_bloc.dart';
import '../bloc/active_list_bloc/active_list_event.dart';
import '../bloc/active_list_bloc/active_list_state.dart';

class ActiveListWidget extends StatelessWidget {
  final ActiveListBloc activeListBloc;
  bool showAll;
  ActiveListWidget({
    super.key,
    required this.activeListBloc,
    required this.showAll,
  });

  @override
  Widget build(BuildContext context) {
    return BlocProvider<ActiveListBloc>.value(
      value: activeListBloc..add(GetActiveListEvent()),
      child: BlocBuilder<ActiveListBloc, ActiveListState>(
        builder: (context, state) {
          if (state is ActiveListLoadedState) {
            return state.list.data?.isEmpty ?? true
                ? const SizedBox()
                : 
                      ListView.separated(
                        physics: const NeverScrollableScrollPhysics(),
                        padding: const EdgeInsets.symmetric(horizontal: 10),
                        itemCount: showAll? 2:state.list.data!.length,
                        shrinkWrap: true,
                        separatorBuilder: (context, index) {
                          return const SizedBox(
                            height: 10,
                          );
                        },
                        itemBuilder: (context, index) {
                          return DRInfoCardActive(
                              listdata: state.list.data?[index],
                            
                          );
                        },
                      
                    
                  );
          } else {
            return const SizedBox(
              height: 100,
            );
          }
        },
      ),
    );
  }
}

修复方案

1. 解决ParentDataWidget错误

该错误核心是Widget的父容器与自身所需的父组件不兼容,比如Expanded/Flexible被放在非Row/Column的父容器中。

  • 检查DRInfoCardActive内部代码,确保所有Expanded/Flexible的父组件是Row或Column;
  • 若卡片内使用了Stack,避免直接在Stack子组件中使用需要ParentData的Widget。

2. 优化滚动组件嵌套结构

SingleChildScrollView嵌套ListView(即使设置了shrinkWrap: true)容易引发真机布局计算异常,可替换为两种方案:

方案A:用Column替代ListView

直接遍历列表项,减少滚动组件嵌套:

// 替换ListView.separated为以下代码
Column(
  children: [
    for (int index = 0; index < (showAll ? 2 : state.list.data!.length); index++)
      ...[
        DRInfoCardActive(listdata: state.list.data?[index]),
        // 最后一项不显示分隔符
        if (index != (showAll ? 1 : state.list.data!.length - 1))
          const SizedBox(height: 10),
      ],
  ],
)

方案B:改用CustomScrollView

将整个页面改为CustomScrollView,用SliverToBoxAdapter包裹静态内容,SliverList加载列表:

// MainScreen的body替换为
CustomScrollView(
  slivers: [
    SliverToBoxAdapter(child: /* 原Row标题部分 */),
    SliverToBoxAdapter(child: const SizedBox(height:5)),
    ActiveListWidget(/* 参数 */),
    // 其余列表同理替换为Sliver结构
  ],
)

3. 排查JSON解析问题

接入自定义JsonString后出现问题,需验证真机上的解析逻辑:

  • 在Bloc的事件处理中添加异常捕获,打印详细错误:
    // 在GetActiveListEvent的处理逻辑中
    try {
      // JSON解析代码
      emit(ActiveListLoadedState(list: parsedData));
    } catch (e, stackTrace) {
      print('JSON解析失败: $e');
      print(stackTrace);
      emit(ActiveListErrorState(error: e.toString()));
    }
    
  • 在UI中添加错误状态展示,避免空布局导致灰屏:
    // BlocBuilder中补充错误状态处理
    } else if (state is ActiveListErrorState) {
      return Padding(
        padding: const EdgeInsets.all(16),
        child: Text('加载失败: ${state.error}', color: Colors.white),
      );
    }
    

4. 修正Bloc事件触发逻辑

当前列表组件每次build都会触发GetActiveListEvent(),可能引发重复请求和状态混乱:

  • 将事件移到MainScreen的initState中触发:
    @override
    void initState() {
      super.initState();
      activeListBloc.add(GetActiveListEvent());
      availableListBloc.add(GetAvailableListEvent());
      completedListBloc.add(GetCompletedListEvent());
    }
    
  • 列表组件中移除BlocProvider.value,直接使用BlocBuilder:
    @override
    Widget build(BuildContext context) {
      return BlocBuilder<ActiveListBloc, ActiveListState>(
        builder: (context, state) {
          // 原状态处理逻辑
        },
      );
    }
    

内容的提问来源于stack exchange,提问作者Murray Karelin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 05:57:02