目前,我正在使用加載頁面來避免在用戶被重定向到主頁而通知是在同一執行緒(導致大量丟幀的 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()),
);
}
}
uj5u.com熱心網友回復:
在 iOS 平臺上你不能同時處理太多的通知。取而代之的是,您需要在收到一些舊通知后再次設定或安排通知,否則舊通知會重疊并且不會安排。
您可以查看此鏈接和我的回答,希望對您有所幫助。
Dart/Flutter 是單執行緒的,不可能是多執行緒的。因為每個隔離都有自己的記憶體、空間和一切。為了使它像多執行緒一樣作業,您必須使用隔離,并且將通過埠相互發送訊息來使用通信。如果您不想使用 Future,您可以使用隔離。
Read
https://medium.com/flutter-community/flutter-threading-5c3a7b0c065f
https://www.tutorialspoint.com/dart_programming/dart_programming_concurrency.htm
https://pub.dev/packages/threading
所以你可以使用FutureOr isolate。
uj5u.com熱心網友回復:
偉大的弗朗索瓦。你已經在一個好的道路上。我想我可以給你一些提示來完成你想要的。
- 首先,Flutter 需要頂級函式來運行隔離,因此您必須將其放在類之外。
- 要將資料傳輸到隔離,它必須被序列化。在我的示例中,我使用 jsonEncode 將其作為字串發送并使用 jsonDecode 對其進行決議,以作為隔離運行器內的動態串列進行檢索。
- 當我寫這段代碼時,我讀到了在隔離中使用插件的一些限制(我不知道當前狀態)。所以我使用 Flutter Isolate 插件找到了一個解決方案(https://pub.dev/packages/isolate_handler)
- 我使用函式 killScheduleNotifications 作為控制代碼何時運行并避免創建重復的方法。我總是取消所有計劃并每次都重新創建它。
供參考(https://gist.github.com/taciomedeiros/50472cf94c742befba720853e9d598b6)
final IsolateHandler isolateHandler = IsolateHandler();
void scheduleNotificationsIsolate(String _reminders) async {
await new Future.delayed(new Duration(milliseconds: 500));
// ... (describe settings)
flutterLocalNotificationsPlugin.initialize(
settings,
onSelectNotification: onSelectNotification,
);
await flutterLocalNotificationsPlugin.cancelAll();
List<dynamic> _remindersParsed = jsonDecode(_reminders);
for (// iterate over your entities to show the message) {
int generatedId = id ?? random.nextInt(1000000000);
await flutterLocalNotificationsPlugin.schedule(
generatedId,
title,
message,
scheduledNotificationDateTime,
platformSpecifics,
payload: payload,
);
}
killCurrentScheduleNotifications();
}
startScheduleNotifications(String _remindersAsString) {
killCurrentScheduleNotifications();
isolateHandler.spawn<String>(
entryPoint,
name: "scheduleNotifications",
onReceive: scheduleNotificationsIsolate,
onInitialized: () => isolateHandler.send(
_remindersAsString,
to: "scheduleNotifications",
),
);
}
void killCurrentScheduleNotifications() {
if (isolateHandler.isolates.containsKey('scheduleNotifications'))
isolateHandler.kill('scheduleNotifications');
}
void entryPoint(Map<String, dynamic> context) {
final messenger = HandledIsolate.initialize(context);
messenger.listen((message) {
messenger.send(message);
});
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/361159.html
上一篇:決議子行程的輸出
下一篇:評估numpy陣列時的兩個不同值
