Open
Description
Hi, to put them in context
I am consuming an API, and I save the data to a local database (Hive), then I get this data using a Stream to the local database.
When I run Workmanager, when the app is minimized (in my case registerPeriodicTask), doing a get of the api and updating the data every 15', the data is updated in the DB but not in the UI (this happens when the app is in the background and you go back to the app -> foreground ).
I have already tried:
- Use Provider, and notify listeners
- Notify the stream again that there were changes
- Use set state when returning the app to foreground
- Use AutomaticKeepAliveClientMixin = true
- Send updated data to other box in hive, and update my main box in foreground with the new data
But nothing seems to work. Any idea how to correct it?
This is a basic example of my screen
class TestView extends StatelessWidget {
const TestView({super.key});
@override
Widget build(BuildContext context) {
final localDatabaseRepository = LocalDatabaseRepository();
return Scaffold(
appBar: AppBar(
title: const Text('Test'),
actions: [
IconButton(
onPressed: () {},
icon: const Icon(Icons.add),
),
],
),
body: StreamBuilder<List<DataEntity>>(
stream: localDatabaseRepository.loadCasesStream(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
final dataSnapshot = snapshot.data;
if (dataSnapshot != null && dataSnapshot.isNotEmpty) {
return ListView.builder(
itemCount: dataSnapshot.length,
itemBuilder: (context, index) {
final data =
dataSnapshot[dataSnapshot.length - index - 1].caseStatus!;
return Text('${data.text}');
},
);
} else {
return const Center(
child: Text(
'Empty',
textAlign: TextAlign.center,
),
);
}
}
},
),
);
}
}
This is a basic example of mi main
void main() async {
WidgetsFlutterBinding.ensureInitialized();
//await FirebaseConfig.init();
await dotenv.load();
await Hive.initFlutter();
Hive
..registerAdapter(CaseEntityAdapter())
..registerAdapter(CaseStatusAdapter())
..registerAdapter(HistCaseStatusAdapter());
await Workmanager().initialize(callbackDispatcher, isInDebugMode: true);
if (!await Permission.notification.isPermanentlyDenied) {
await Permission.notification.request();
await LocalNotificationManager().initNotification();
}
runApp(const MainApp());
}
class MainApp extends StatefulWidget {
const MainApp({super.key});
@override
State<MainApp> createState() => _MainAppState();
}
class _MainAppState extends State<MainApp> {
@override
Widget build(BuildContext context) {
return FGBGNotifier(
onEvent: (FGBGType event) async {
if (event == FGBGType.foreground) {
await Workmanager().cancelAll();
} else {
//FGBGType.background
await Workmanager().registerPeriodicTask(
task,
task,
backoffPolicy: BackoffPolicy.exponential,
frequency: const Duration(minutes: 15),
constraints: Constraints(
requiresBatteryNotLow: false, //Only android
requiresCharging: false, //Only android
requiresStorageNotLow: false, //Only android
networkType: NetworkType.connected,
),
);
}
},
child: GetMaterialApp(
debugShowCheckedModeBanner: false,
theme: AppTheme.getTheme(),
initialRoute: AppRouter.home,
getPages: AppRouter.routes,
navigatorObservers: [
RouterObserver(),
],
localizationsDelegates: const [
S.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: S.delegate.supportedLocales,
),
)
}
}
// CallbackDispatcher needs to be a top-level function
// If u want change taskName, also change taskName in ios/Runner/AppDelegate.m
const task = 'be.tramckrijte.workmanagerExample.iOSBackgroundAppRefresh';
@pragma('vm:entry-point')
void callbackDispatcher() {
Workmanager().executeTask((taskName, inputData) async {
try {
switch (taskName) {
case task:
WidgetsFlutterBinding.ensureInitialized();
await dotenv.load();
await LocalNotificationManager().initNotification();
await Hive.initFlutter();
Hive
..registerAdapter(TestEntityAdapter())
..registerAdapter(TestsStatusAdapter())
..registerAdapter(HistTestStatusAdapter());
await MyManager().fetchCases();
log('Excecute task ${DateTime.now()}');
default:
}
} catch (e) {
log('error workmanager $e');
}
return Future.value(true);
});
}
Thanks you.