Flutter加载屏优先显示,延后执行Java原生数据请求方案咨询
解决Flutter加载屏被Java原生网络请求阻塞的问题
看起来你遇到的核心问题是Java端的同步阻塞操作卡住了Flutter的UI初始化流程,导致加载屏没法及时渲染,直接出现白屏直到请求完成。咱们一步步来修复这个问题:
第一步:修复Java端的阻塞逻辑
你原来的getReal2()方法里用了while (!completableFuture.isDone()) {}轮询+completableFuture.get()同步等待,这会直接阻塞configureFlutterEngine所在的线程——而这个线程正是Flutter用来初始化UI的关键线程,自然会导致加载屏迟迟显示不出来。
咱们把Java代码改成异步回调的方式,让网络请求在后台线程执行,完成后再把结果返回给Flutter,完全不阻塞主线程:
public class MainActivity extends FlutterActivity { private static final String CHANNEL = "samples.flutter.dev/battery"; @Override public void configureFlutterEngine(FlutterEngine flutterEngine) { super.configureFlutterEngine(flutterEngine); new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL) .setMethodCallHandler( (call, result) -> { if (call.method.equals("getDate")) { // 异步执行网络请求,不阻塞当前线程 CompletableFuture.supplyAsync(() -> { try { return getCoffee(); } catch (IOException e) { e.printStackTrace(); return null; } }).whenComplete((coffeeList, throwable) -> { if (throwable != null) { // 请求出错时返回错误信息给Flutter result.error("NETWORK_ERROR", "Failed to fetch coffee data", throwable.getMessage()); } else if (coffeeList == null) { result.error("NO_DATA", "No coffee data retrieved", null); } else { // 请求成功,返回结果 result.success(coffeeList); } }); } else { result.notImplemented(); } } ); } public static List<String> getCoffee() throws IOException { ArrayList<String> coffee = new ArrayList<>(); Document doc = Jsoup.connect("https://www.bankofabyssinia.com").timeout(6000).get(); for(int i=0;i<=8;i++) { for (int j=2;j<=3;j++){ coffee.add(doc.select("#myTable > tbody > tr:nth-child("+i+") > td:nth-child("+j+")").text()); } } return coffee; } }
第二步:调整Flutter端的请求时机
原来你在initState里直接调用getWholeJava(),这时候Widget还没完成第一帧渲染,可能导致加载屏还没来得及显示就进入请求等待。咱们改成等加载屏渲染完成后再发起请求:
import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'Home.dart'; class Load extends StatefulWidget { @override _LoadState createState() => _LoadState(); } class _LoadState extends State<Load> { static const platform = const MethodChannel('samples.flutter.dev/battery'); void getWholeJava() async { try { final List result = await platform.invokeMethod('getDate'); Navigator.of(context).pushReplacement(MaterialPageRoute( builder: (BuildContext context) => Home( whole: result, ))); } on PlatformException catch (e) { print("Error fetching data: ${e.message}"); // 这里可以添加错误提示,比如显示一个重试按钮 } } @override void initState() { super.initState(); // 等待当前帧渲染完成后再发起请求,确保加载屏先显示出来 WidgetsBinding.instance.addPostFrameCallback((_) { getWholeJava(); }); } @override Widget build(BuildContext context) { return Scaffold( body: Container( child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, // 居中显示加载文本 children: <Widget>[ Text( 'The app is loading', style: TextStyle( fontSize: 40.0, fontWeight: FontWeight.w900, color: Colors.green[900]), ), // 可以加个CircularProgressIndicator让加载状态更明显 SizedBox(height: 20), CircularProgressIndicator(color: Colors.green[900]), ] ) ), ) ); } }
为什么原来的代码不生效?
- Java端阻塞线程:你原来的
while循环+get()会卡住FlutterEngine的初始化线程,导致Flutter根本没时间渲染加载屏,直接进入白屏等待。 - Flutter请求时机过早:
initState在Widget初始化时就执行,这时候UI还没完成绘制,即使Java端不阻塞,加载屏也可能来不及显示。
额外优化建议
- 添加错误处理UI:如果网络请求失败,不要只打印日志,给用户显示一个重试按钮或者错误提示。
- 优化加载屏体验:比如添加动画、品牌logo,让用户感知到App正在正常工作。
- 考虑用Flutter原生的网络请求库(比如
http、dio)替代Java原生请求,这样可以减少跨平台通信的复杂度,也更容易在Flutter端控制请求时机和状态。
内容的提问来源于stack exchange,提问作者Marven
相关产品推荐
相关产品推荐

