-
Notifications
You must be signed in to change notification settings - Fork 343
Description
Technology | Version |
---|---|
Workmanager version | 0.8.0 |
Describe the error
When the workmanager calls the callbackDispatcher, the app UI freezes for a moment and any heavy work will continue to freeze it. It can be mitigated by using compute for the heavy computations, but the initial callbackDispatcher call will always freeze the UI. Seems like the initial call is still tied to the main isolate unlike the call with compute.
I've tried searching an answer to this everywhere but no luck. I've tested this in the example project by adding a CircularProgressIndicator()
to the top of the of the column as well as created my own small one below. I believe this is leading to some weird interactions with the audio_session in my own app (though that's just speculation on my part).
I'm perfectly willing to accept I'm setting this all up wrong. If so, I'd love to what I'm doing wrong.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:xml/xml.dart';
import 'package:http/http.dart' as http;
import 'package:workmanager/workmanager.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
Workmanager().initialize(
callbackDispatcher,
isInDebugMode: false,
);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
void initState() {
// TODO: implement initState
super.initState();
}
int _counter = 0;
void registerTask(bool useCompute) {
Workmanager().cancelAll();
Workmanager().registerOneOffTask(
'backgroundTask',
'backgroundTask',
initialDelay: const Duration(seconds: 2),
existingWorkPolicy: ExistingWorkPolicy.replace,
inputData: { 'useCompute': useCompute }
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: () => registerTask(false),
child: Text('Task without compute'),
),
ElevatedButton(
onPressed: () => registerTask(true),
child: Text('Task with compute'),
),
CircularProgressIndicator(),
],
),
),
);
}
}
@pragma('vm:entry-point')
void callbackDispatcher() async {
Workmanager().executeTask((task, inputData) async {
final useCompute = inputData?['useCompute'] ?? false;
if(useCompute) {
compute<Map<String, dynamic>, void>(updateTask, inputData ?? {});
return true;
}
else {
await updateTask(inputData ?? {});
return true;//Future.value(true);
}
});
}
updateTask(Map<String, dynamic> value) async {
try{
print('Start debug task');
final url = r'https://feeds.libsyn.com/583795/rss?limit=10';
final uri = Uri.parse(url);
print('Create Response');
final request = http.Request('GET', uri)..maxRedirects = 20;
request.followRedirects = false;
final response = await http.Client().send(request);
final location = response.headers['location'];
// snapShot = log('Check feed URL', stopwatch, snapShot);
print('Http get');
//final feedContent = await http.get(uri);
final feedContent = await http.get(uri);
// snapShot = log('Feed url get', stopwatch, snapShot);
final decodedContent = Utf8Decoder().convert(feedContent.bodyBytes);
//print('No XML');
print('XML Parse');
final feedDoc = XmlDocument.parse(decodedContent);
// snapShot = log('Xml parse', stopwatch, snapShot);
final parentNode = feedDoc.findElements('rss')
.single.findElements('channel').single;
print('Get title');
final title = _getNodeValue(parentNode, 'title', 'Title Not Found');
print(title);
} catch (e) {
print(e);
}
print('End debug task');
}
String _getNodeValue(XmlElement parentNode, String nodeName, String backup) {
try {
var node = parentNode.findElements(nodeName);
if (node.isNotEmpty) {
var nodeText = node.first.innerText;
return nodeText;
} else
return backup;
} catch (_) {
return backup;
}
}
name: test_project
description: "A new Flutter project."
publish_to: 'none'
version: 1.0.0+1
environment:
sdk: ^3.8.1
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.8
xml: ^6.5.0
http: ^1.4.0
workmanager: ^0.8.0
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^5.0.0
flutter:
uses-material-design: true
[√] Flutter (Channel stable, 3.32.7, on Microsoft Windows [Version 10.0.26100.4652], locale en-US)
[√] Windows Version (11 Home 64-bit, 24H2, 2009)
[√] Android toolchain - develop for Android devices (Android SDK version 35.0.0)
[√] Chrome - develop for the web
[X] Visual Studio - develop Windows apps
X Visual Studio not installed; this is necessary to develop Windows apps.
Download at https://visualstudio.microsoft.com/downloads/.
Please install the "Desktop development with C++" workload, including all of its default components
[√] Android Studio (version 2024.2)
[√] VS Code (version 1.102.1)
[√] Connected device (5 available)
[√] Network resources