目前,我正在使用加载页面来避免在用户被重定向到主页而在同一线程(导致大量丢帧的 UI 线程)上创建通知时出现大延迟。我尝试使用计算 dart 函数,但问题是该函数需要使用静态方法,并且您不能传递对象。因此,我将不胜感激有关如何使用线程创建通知的一些提示。PS:在最坏的情况下,应用程序会创建 7*24 通知(一周中的每一天 24 个),即使在高端设备上也很慢。
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter/material.dart';
import '../pages/home_page/home_page.dart';
import 'package:timezone/data/latest.dart' as tz;
import 'package:timezone/timezone.dart' as tz;
import 'data.dart';
import 'package:flutter_native_timezone/flutter_native_timezone.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:auto_size_text/auto_size_text.dart';
class NotificationLoading extends StatefulWidget {
const NotificationLoading({Key? key}) : super(key: key);
@override
_NotificationLoadingState createState() => _NotificationLoadingState();
}
class _NotificationLoadingState extends State<NotificationLoading> {
@override
void initState() {
super.initState();
manageNotifications();
}
Future<void> manageNotifications() async {
await Future.delayed(
const Duration(seconds: 1),
); // Let time to build the widget
await Notifications(ctx: context).manageNotifications();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: const [
CircularProgressIndicator(),
Padding(
padding: EdgeInsets.fromLTRB(0, 15, 0, 0),
child: AutoSizeText(
"Loading notifs",
style: TextStyle(fontSize: 30),
),
)
],
),
),
);
}
}
class Notifications {
static const channelId = "coolID";
static const channelName = "cool";
Data data = Data();
int id = 0;
BuildContext ctx;
Notifications({required this.ctx});
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
// check if notifications are already setup, if not setup notifications
// otherwise notifications only need to be changed inside the timer_page
Future<void> manageNotifications() async {
final prefs = await SharedPreferences.getInstance();
bool isNotificationSetup = prefs.getBool('isNotificationSetup') ?? false;
if (!isNotificationSetup) {
await _initialization();
await _scheduleNotifications();
await prefs.setBool('isNotificationSetup', true);
Navigator.pop(ctx);
await Navigator.push(
ctx,
MaterialPageRoute<void>(builder: (context) => const HomePage()),
);
}
}
Future<void> _initialization() async {
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('app_icon');
const InitializationSettings initializationSettings =
InitializationSettings(
android: initializationSettingsAndroid,
);
await flutterLocalNotificationsPlugin.initialize(initializationSettings,
onSelectNotification: _selectNotification);
}
// Schedule notifications based on user settings
Future<void> _scheduleNotifications() async {
// Init the time zone, needed for notification scheduling
tz.initializeTimeZones();
final String? timeZoneName = await FlutterNativeTimezone.getLocalTimezone();
tz.setLocalLocation(tz.getLocation(timeZoneName!));
await data.getData();
int delta = (data.endTime.minute + data.endTime.hour * 60) -
(data.startTime.minute + data.startTime.hour * 60);
double interval = delta / data.reminderNumber;
data.checkedDays.forEach((day, values) {
if (values[1]) {
double minute = data.startTime.minute + (data.startTime.hour * 60);
for (int reminder = 0; reminder < data.reminderNumber; reminder++) {
int tmpHour = (minute - minute % 60) ~/ 60;
int tmpMinute = (minute.round()) % 60;
_createScheduledNotification(
_nextInstanceOfDayHourMinute(tmpHour, tmpMinute, values[0]), id);
minute += interval;
id++;
}
}
});
}
// Create a scheduled notification
void _createScheduledNotification(tz.TZDateTime time, int id) async {
await flutterLocalNotificationsPlugin.zonedSchedule(
id,
AppLocalizations.of(ctx)!.notificationTitle,
AppLocalizations.of(ctx)!.notificationMessage,
time,
const NotificationDetails(
android: AndroidNotificationDetails(
'weekly notification channel id',
'New citation message',
channelDescription:
'Notifications for new citations configured in the timer page.',
sound: RawResourceAndroidNotificationSound('notification_sound'),
groupKey: "meditation invitation",
),
),
androidAllowWhileIdle: true,
uiLocalNotificationDateInterpretation:
UILocalNotificationDateInterpretation.absoluteTime,
matchDateTimeComponents: DateTimeComponents.dayOfWeekAndTime);
}
// Find next instance DateTime object
tz.TZDateTime _nextInstanceOfHourMinute(int hour, int minute) {
final tz.TZDateTime now = tz.TZDateTime.now(tz.local);
tz.TZDateTime scheduledDate =
tz.TZDateTime(tz.local, now.year, now.month, now.day, hour, minute);
if (scheduledDate.isBefore(now)) {
scheduledDate = scheduledDate.add(const Duration(days: 1));
}
return scheduledDate;
}
// Find next instance DateTime object
tz.TZDateTime _nextInstanceOfDayHourMinute(int hour, int minute, int day) {
tz.TZDateTime scheduledDate = _nextInstanceOfHourMinute(hour, minute);
while (scheduledDate.weekday != day) {
scheduledDate = scheduledDate.add(const Duration(days: 1));
}
return scheduledDate;
}
// triggered function when the user tap on a notification
void _selectNotification(String? payload) async {
if (payload != null) {
debugPrint('notification payload: $payload');
}
await Navigator.push(
ctx,
MaterialPageRoute<void>(builder: (context) => const HomePage()),
);
}
}