fix: database memory leaks (#4126)

This commit is contained in:
Lucas.Xu 2023-12-11 19:48:58 +07:00 committed by GitHub
parent 4e6643eca8
commit 81e09ae72e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 78 additions and 85 deletions

View File

@ -14,6 +14,8 @@
"env": {
"RUST_LOG": "debug",
},
// uncomment the following line to testing performance.
"flutterMode": "profile",
"cwd": "${workspaceRoot}/appflowy_flutter"
},
{

View File

@ -88,11 +88,11 @@ class TypeOptionController {
final result = await DatabaseEventUpdateFieldType(payload).send();
await result.fold(
(_) {
(_) async {
// Should load the type-option data after switching to a new field.
// After loading the type-option data, the editor widget that uses
// the type-option data will be rebuild.
reloadTypeOption();
await reloadTypeOption();
},
(err) => Future(() => Log.error(err)),
);

View File

@ -123,8 +123,9 @@ class DesktopBoardContent extends StatefulWidget {
class _DesktopBoardContentState extends State<DesktopBoardContent> {
final renderHook = RowCardRenderHook<String>();
late final ScrollController scrollController;
late final AppFlowyBoardScrollController scrollManager;
final ScrollController scrollController = ScrollController();
final AppFlowyBoardScrollController scrollManager =
AppFlowyBoardScrollController();
final config = const AppFlowyBoardConfig(
groupMargin: EdgeInsets.symmetric(horizontal: 4),
@ -139,8 +140,6 @@ class _DesktopBoardContentState extends State<DesktopBoardContent> {
void initState() {
super.initState();
scrollManager = AppFlowyBoardScrollController();
scrollController = ScrollController();
renderHook.addSelectOptionHook((options, groupId, _) {
// The cell should hide if the option id is equal to the groupId.
final isInGroup =
@ -154,6 +153,12 @@ class _DesktopBoardContentState extends State<DesktopBoardContent> {
});
}
@override
void dispose() {
scrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return BlocListener<BoardBloc, BoardState>(

View File

@ -1,5 +1,3 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
@ -12,6 +10,7 @@ import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:protobuf/protobuf.dart';
@ -110,7 +109,6 @@ class _CalendarLayoutSettingState extends State<CalendarLayoutSetting> {
width: 200,
child: ListView.separated(
shrinkWrap: true,
controller: ScrollController(),
itemCount: items.length,
separatorBuilder: (_, __) =>
VSpace(GridSize.typeOptionSeparatorHeight),

View File

@ -1,10 +1,12 @@
import 'dart:async';
import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
import 'package:appflowy/plugins/database_view/application/field/field_info.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_settings_entities.pb.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'dart:async';
import '../../application/field/field_service.dart';
part 'grid_header_bloc.freezed.dart';

View File

@ -3,10 +3,9 @@ import 'package:appflowy/plugins/database_view/grid/application/filter/select_op
import 'package:appflowy/plugins/database_view/grid/presentation/layout/sizes.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/filter/filter_info.dart';
import 'package:appflowy/plugins/database_view/widgets/row/cells/select_option_cell/extension.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/select_option.pb.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/select_option.pb.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@ -60,7 +59,6 @@ class SelectOptionFilterList extends StatelessWidget {
return ListView.separated(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
controller: ScrollController(),
itemCount: state.visibleOptions.length,
separatorBuilder: (context, index) {
return VSpace(GridSize.typeOptionSeparatorHeight);

View File

@ -1,8 +1,8 @@
import 'package:appflowy/plugins/database_view/grid/application/filter/select_option_filter_bloc.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/select_option_filter.pb.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@ -123,7 +123,6 @@ class _SelectOptionFilterEditorState extends State<SelectOptionFilterEditor> {
child: CustomScrollView(
shrinkWrap: true,
slivers: slivers,
controller: ScrollController(),
physics: StyledScrollPhysics(),
),
);

View File

@ -75,7 +75,6 @@ class _GridCreateFilterListState extends State<GridCreateFilterList> {
),
SliverToBoxAdapter(
child: ListView.separated(
controller: ScrollController(),
shrinkWrap: true,
itemCount: cells.length,
itemBuilder: (BuildContext context, int index) {
@ -90,7 +89,6 @@ class _GridCreateFilterListState extends State<GridCreateFilterList> {
return CustomScrollView(
shrinkWrap: true,
slivers: slivers,
controller: ScrollController(),
physics: StyledScrollPhysics(),
);
},

View File

@ -56,6 +56,12 @@ class _FieldEditorState extends State<FieldEditor> {
textController = TextEditingController(text: widget.field.name);
}
@override
void dispose() {
textController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return BlocProvider(

View File

@ -1,9 +1,9 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import '../../layout/sizes.dart';
import 'field_type_extension.dart';
@ -29,7 +29,6 @@ class FieldTypeList extends StatelessWidget with FlowyOverlayDelegate {
width: 140,
child: ListView.separated(
shrinkWrap: true,
controller: ScrollController(),
itemCount: cells.length,
separatorBuilder: (context, index) {
return VSpace(GridSize.typeOptionSeparatorHeight);

View File

@ -69,18 +69,12 @@ class _GridHeader extends StatefulWidget {
class _GridHeaderState extends State<_GridHeader> {
final Map<String, ValueKey<String>> _gridMap = {};
final _scrollController = ScrollController();
/// This is a workaround for [ReorderableRow].
/// [ReorderableRow] warps the child's key with a [GlobalKey].
/// It will trigger the child's widget's to recreate.
/// The state will lose.
ValueKey<String>? _getKeyById(String id) {
if (_gridMap.containsKey(id)) {
return _gridMap[id];
}
final newKey = ValueKey(id);
_gridMap[id] = newKey;
return newKey;
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
@override
@ -124,7 +118,7 @@ class _GridHeaderState extends State<_GridHeader> {
return RepaintBoundary(
child: ReorderableRow(
scrollController: ScrollController(),
scrollController: _scrollController,
buildDraggableFeedback: (context, constraints, child) => Material(
color: Colors.transparent,
child: child,
@ -150,6 +144,19 @@ class _GridHeaderState extends State<_GridHeader> {
);
}
/// This is a workaround for [ReorderableRow].
/// [ReorderableRow] warps the child's key with a [GlobalKey].
/// It will trigger the child's widget's to recreate.
/// The state will lose.
ValueKey<String>? _getKeyById(String id) {
if (_gridMap.containsKey(id)) {
return _gridMap[id];
}
final newKey = ValueKey(id);
_gridMap[id] = newKey;
return newKey;
}
Widget _cellLeading(FieldInfo? fieldInfo) {
if (PlatformExtension.isDesktop) {
return SizedBox(width: GridSize.leadingHeaderPadding);

View File

@ -1,14 +1,14 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database_view/application/field/type_option/date_bloc.dart';
import 'package:appflowy/plugins/database_view/application/field/type_option/type_option_context.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/date_entities.pbenum.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart' hide DateFormat;
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import '../../../layout/sizes.dart';
import '../../common/type_option_separator.dart';
import '../field_type_option_editor.dart';
@ -57,7 +57,6 @@ class DateTypeOptionWidget extends TypeOptionWidget {
return ListView.separated(
shrinkWrap: true,
controller: ScrollController(),
separatorBuilder: (context, index) {
if (index == 0) {
return const SizedBox();
@ -201,7 +200,6 @@ class DateFormatList extends StatelessWidget {
width: 180,
child: ListView.separated(
shrinkWrap: true,
controller: ScrollController(),
separatorBuilder: (context, index) {
return VSpace(GridSize.typeOptionSeparatorHeight);
},
@ -285,7 +283,6 @@ class TimeFormatList extends StatelessWidget {
width: 120,
child: ListView.separated(
shrinkWrap: true,
controller: ScrollController(),
separatorBuilder: (context, index) {
return VSpace(GridSize.typeOptionSeparatorHeight);
},

View File

@ -1,15 +1,14 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database_view/application/field/type_option/number_bloc.dart';
import 'package:appflowy/plugins/database_view/application/field/type_option/number_format_bloc.dart';
import 'package:appflowy/plugins/database_view/application/field/type_option/type_option_context.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/number_entities.pbenum.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import '../../../layout/sizes.dart';
import '../../common/type_option_separator.dart';
@ -150,7 +149,6 @@ class NumberFormatList extends StatelessWidget {
final list = ListView.separated(
shrinkWrap: true,
controller: ScrollController(),
separatorBuilder: (context, index) {
return VSpace(GridSize.typeOptionSeparatorHeight);
},

View File

@ -1,8 +1,9 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database_view/application/field/type_option/edit_select_option_bloc.dart';
import 'package:appflowy/plugins/database_view/widgets/row/cells/select_option_cell/extension.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/select_option.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
@ -11,8 +12,6 @@ import 'package:flowy_infra_ui/style_widget/text_field.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import '../../../layout/sizes.dart';
import '../../common/type_option_separator.dart';
@ -74,7 +73,6 @@ class SelectOptionTypeOptionEditor extends StatelessWidget {
width: 180,
child: ListView.builder(
shrinkWrap: true,
controller: ScrollController(),
physics: StyledScrollPhysics(),
itemCount: cells.length,
itemBuilder: (context, index) {

View File

@ -1,10 +1,10 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database_view/application/row/row_service.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/layout/sizes.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';

View File

@ -6,7 +6,6 @@ import 'package:appflowy/plugins/database_view/grid/application/sort/sort_create
import 'package:appflowy/plugins/database_view/grid/presentation/layout/sizes.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/field_type_extension.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
@ -75,7 +74,6 @@ class _GridCreateSortListState extends State<GridCreateSortList> {
),
SliverToBoxAdapter(
child: ListView.separated(
controller: ScrollController(),
shrinkWrap: true,
itemCount: cells.length,
itemBuilder: (BuildContext context, int index) {
@ -90,7 +88,6 @@ class _GridCreateSortListState extends State<GridCreateSortList> {
return CustomScrollView(
shrinkWrap: true,
slivers: slivers,
controller: ScrollController(),
physics: StyledScrollPhysics(),
);
},

View File

@ -88,6 +88,12 @@ class DatabaseTabBar extends StatefulWidget {
class _DatabaseTabBarState extends State<DatabaseTabBar> {
final _scrollController = ScrollController();
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return BlocBuilder<DatabaseTabBarBloc, DatabaseTabBarState>(

View File

@ -65,6 +65,12 @@ class _DatabaseTabBarViewState extends State<DatabaseTabBarView> {
);
}
@override
void dispose() {
_pageController?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return BlocProvider<DatabaseTabBarBloc>(

View File

@ -580,7 +580,6 @@ class _CalDateTimeSettingState extends State<_CalDateTimeSetting> {
width: 180,
child: ListView.separated(
shrinkWrap: true,
controller: ScrollController(),
separatorBuilder: (context, index) =>
VSpace(GridSize.typeOptionSeparatorHeight),
itemCount: children.length,

View File

@ -4,7 +4,6 @@ import 'package:appflowy/plugins/database_view/application/layout/layout_bloc.da
import 'package:appflowy/plugins/database_view/widgets/database_layout_ext.dart';
import 'package:appflowy/util/platform_extension.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/setting_entities.pb.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
@ -49,7 +48,6 @@ class _DatabaseLayoutSelectorState extends State<DatabaseLayoutSelector> {
.toList();
return ListView.separated(
controller: ScrollController(),
shrinkWrap: true,
itemCount: cells.length,
padding: const EdgeInsets.symmetric(vertical: 6.0),

View File

@ -1,5 +1,3 @@
import 'package:flutter/widgets.dart';
import 'package:appflowy/plugins/database_view/application/database_controller.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/layout/sizes.dart';
import 'package:appflowy/plugins/database_view/widgets/setting/database_setting_action.dart';
@ -8,6 +6,7 @@ import 'package:appflowy_backend/protobuf/flowy-database2/setting_entities.pbenu
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flutter/widgets.dart';
class DatabaseSettingsList extends StatefulWidget {
const DatabaseSettingsList({
@ -40,7 +39,6 @@ class _DatabaseSettingsListState extends State<DatabaseSettingsList> {
return ListView.separated(
shrinkWrap: true,
padding: EdgeInsets.zero,
controller: ScrollController(),
itemCount: cells.length,
separatorBuilder: (context, index) =>
VSpace(GridSize.typeOptionSeparatorHeight),

View File

@ -1,19 +1,18 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/presentation.dart';
import 'package:appflowy/mobile/presentation/widgets/flowy_paginated_bottom_sheet.dart';
import 'package:appflowy/plugins/database_view/application/field/field_info.dart';
import 'package:appflowy/plugins/database_view/calendar/presentation/toolbar/calendar_layout_setting.dart';
import 'package:flutter/material.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
import 'package:appflowy/plugins/database_view/application/field/field_info.dart';
import 'package:appflowy/plugins/database_view/application/setting/property_bloc.dart';
import 'package:appflowy/plugins/database_view/calendar/application/calendar_setting_bloc.dart';
import 'package:appflowy/plugins/database_view/calendar/presentation/toolbar/calendar_layout_setting.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/layout/sizes.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:protobuf/protobuf.dart' hide FieldInfo;
@ -90,7 +89,6 @@ class _MobileCalendarLayoutSettingState
return ListView.separated(
shrinkWrap: true,
controller: ScrollController(),
itemCount: items.length,
separatorBuilder: (context, index) =>
VSpace(GridSize.typeOptionSeparatorHeight),

View File

@ -58,7 +58,6 @@ class _TrashPageState extends State<TrashPage> {
scrollbarPadding: EdgeInsets.only(top: TrashSizes.headerHeight),
barSize: barSize,
child: StyledSingleChildScrollView(
controller: ScrollController(),
barSize: barSize,
axis: Axis.horizontal,
child: SizedBox(

View File

@ -38,7 +38,6 @@ class FlowyColorPicker extends StatelessWidget {
Widget build(BuildContext context) {
return ListView.separated(
shrinkWrap: true,
controller: ScrollController(),
separatorBuilder: (context, index) {
return VSpace(separatorSize);
},

View File

@ -1149,7 +1149,7 @@ dependencies = [
"cssparser-macros",
"dtoa-short",
"itoa",
"phf 0.11.2",
"phf 0.8.0",
"smallvec",
]
@ -3653,7 +3653,7 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
dependencies = [
"phf_macros 0.8.0",
"phf_macros",
"phf_shared 0.8.0",
"proc-macro-hack",
]
@ -3673,7 +3673,6 @@ version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
dependencies = [
"phf_macros 0.11.2",
"phf_shared 0.11.2",
]
@ -3741,19 +3740,6 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "phf_macros"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
dependencies = [
"phf_generator 0.11.2",
"phf_shared 0.11.2",
"proc-macro2",
"quote",
"syn 2.0.31",
]
[[package]]
name = "phf_shared"
version = "0.8.0"
@ -3957,7 +3943,7 @@ checksum = "8bdf592881d821b83d471f8af290226c8d51402259e9bb5be7f9f8bdebbb11ac"
dependencies = [
"bytes",
"heck 0.4.1",
"itertools 0.11.0",
"itertools 0.10.5",
"log",
"multimap",
"once_cell",
@ -3978,7 +3964,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "265baba7fabd416cf5078179f7d2cbeca4ce7a9041111900675ea7c4cb8a4c32"
dependencies = [
"anyhow",
"itertools 0.11.0",
"itertools 0.10.5",
"proc-macro2",
"quote",
"syn 2.0.31",