Flutter使用youtube_player_flutter遇LateInitializationError问题求助
问题根源分析
- 全局声明的
late YoutubePlayerController _youtubePlayerController在build方法执行时,YoutubePlayerBuilder的player参数会直接访问这个未初始化的变量,触发LateInitializationError。 - 错误地将同一个全局控制器赋值给所有列表项的
YoutubePlayer,导致视频逻辑混乱,且控制器初始化时机滞后于组件渲染。 - 生命周期方法拼写错误:
deactive应为deactivate,dipose应为dispose,导致控制器无法被正确暂停/释放。
解决方案
1. 移除全局控制器,为每个列表项单独创建控制器
每个视频项需要独立的控制器,避免全局变量的初始化冲突。
2. 修复生命周期方法拼写
确保Flutter能正确调用组件的生命周期钩子,管理控制器资源。
3. 调整YoutubePlayerBuilder的使用
无需全局包裹YoutubePlayerBuilder,每个列表项内部的YoutubePlayer可独立运行(如需全局播放器覆盖层,可将Builder移到Scaffold层级)。
修改后的完整代码
import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:mahuva_azadari/Models/LinkModel.dart'; import 'package:youtube_player_flutter/youtube_player_flutter.dart'; import 'package:http/http.dart' as http; import '../Models/Hexa color.dart'; class LiveProgram extends StatefulWidget { const LiveProgram({Key? key}) : super(key: key); @override State<LiveProgram> createState() => _LiveProgramState(); } class _LiveProgramState extends State<LiveProgram> { // 移除全局控制器变量 Future<LinkModel> getAllLinks() async { var url = "https://aeliya.000webhostapp.com/MajlisLinks.php"; var response = await http.get(Uri.parse(url)); var jsondata = jsonDecode(response.body.toString()); if (response.statusCode == 200) { return LinkModel.fromJson(jsondata); } else { return LinkModel.fromJson(jsondata); } } @override void deactivate() { // 全局无控制器,此处可移除,或改为遍历列表项控制器进行暂停(需额外存储控制器列表) super.deactivate(); print("deactivate"); } @override void dispose() { // 全局无控制器,此处可移除,或改为遍历列表项控制器进行释放(需额外存储控制器列表) super.dispose(); print("dispose"); } @override Widget build(BuildContext context) { return SafeArea( child: Scaffold( appBar: AppBar( title: const Text( "Live Program", style: TextStyle( fontWeight: FontWeight.bold, fontSize: 25, ), ), centerTitle: true, backgroundColor: Color(hexColors('006064')), ), body: FutureBuilder<LinkModel>( future: getAllLinks(), builder: (context, snapshot) { if (snapshot.hasData) { return ListView.builder( itemCount: snapshot.data!.data!.length, itemBuilder: (context, index) { var allItem = snapshot.data!.data![index]; // 为每个列表项单独创建控制器 final videoId = YoutubePlayer.convertUrlToId(allItem.link!); if (videoId == null) { return const Padding( padding: EdgeInsets.all(8.0), child: Text("无效的YouTube链接"), ); } final controller = YoutubePlayerController( initialVideoId: videoId, flags: const YoutubePlayerFlags( autoPlay: false, ), )..addListener(() { if (mounted) setState(() {}); }); return Container( margin: const EdgeInsets.all(8), child: Card( color: Color(hexColors("00BCD4")), elevation: 6, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10.0), ), child: Column( children: [ YoutubePlayer( controller: controller, showVideoProgressIndicator: true, ), const SizedBox(height: 10), Text( controller.metadata.title.isEmpty ? 'Loading Title.....' : "Title: ${controller.metadata.title}", textAlign: TextAlign.left, style: const TextStyle( color: Colors.white, fontSize: 15, fontWeight: FontWeight.w700, fontStyle: FontStyle.italic, ), ), Text("City : ${allItem.city!}"), Text("Post Date : ${allItem.postDateTime!}") ], ), ), ); }, ); } else { return const Center(child: CircularProgressIndicator()); } }, ), ), ); } }
额外优化建议
如果需要统一管理所有列表项的控制器(比如页面销毁时统一释放),可以在状态类中添加一个List<YoutubePlayerController>变量,在创建控制器时加入列表,然后在dispose方法中遍历释放:
List<YoutubePlayerController> _controllers = []; // 创建控制器时 final controller = YoutubePlayerController(...); _controllers.add(controller); // dispose方法中 @override void dispose() { for(var ctrl in _controllers){ ctrl.dispose(); } super.dispose(); }
内容的提问来源于stack exchange,提问作者Taki Rajani
相关产品推荐
相关产品推荐

