[Flutter] Ui_Event_Save

Comely·2024년 11월 18일

Flutter

목록 보기
18/26

메모를 저장하는 형태의 어플을 만들었습니다.
Event를 활용하여 입력된 값을 저장하는 기능을 추가하려고 합니다.

  • Freezed
  • showSnackBar
  • StreamController
  • Navigator.pop

AddEditNoteUiEvent

part 'add_edit_note_ui_event.freezed.dart';


abstract class AddEditNoteUiEvent with _$AddEditNoteUiEvent {
  const factory AddEditNoteUiEvent.saveNote() = SaveNote;
  const factory AddEditNoteUiEvent.showSnackBar(String message) = ShowSnackBar;
}

AddEditNoteViewModel

eventController

final _eventController = StreamController<AddEditNoteUiEvent>.broadcast();

  Stream<AddEditNoteUiEvent> get eventStream => _eventController.stream;

  AddEditNoteViewModel(this.repository);

saveNote

Future<void> _saveNote(int? id, String title, String content) async {
    if (title.isEmpty || content.isEmpty) {
      _eventController.add(const AddEditNoteUiEvent.showSnackBar('제목이나 내용이 비어 있습니다'));
      return;
    }

    if (id == null) {
      await repository.insertNote(
        Note(
            title: title,
            content: content,
            color: _color,
            timestamp: DateTime.now().millisecondsSinceEpoch),
      );
    } 

    _eventController.add(const AddEditNoteUiEvent.saveNote());
  }

AddEditNoteScreen

Stream.listen을 계속하면 메모리 활용에 좋지 않은 방법입니다.

  • 해결방법
  1. StreamSubscription타입의 _streamSubscription 변수 추가
  2. _streamSubscription = viewModel.eventStream.listen((event)
  3. dispose()에 _streamSubscription?.cancel();를 추가
  4. 여러 메모를 저장할 때 다시 listen 하지 않는 오류의 해결 방법
    ViewModel의 StreamController에 broadcast 추가
    여러 번 listen을 할 수 있는 형태로 만듭니다.
    final _eventController = StreamController.broadcast();
  StreamSubscription? _streamSubscription;

void initState() {
    super.initState();

    if (widget.note != null) {
      _titleController.text = widget.note!.title;
      _contentController.text = widget.note!.content;
    }

    Future.microtask(() {
      final viewModel = context.read<AddEditNoteViewModel>();

      _streamSubscription = viewModel.eventStream.listen((event) {
        event.when(
          saveNote: () {
            Navigator.pop(context, true);
          },
          showSnackBar: (String message) {
            final snackBar = SnackBar(content: Text(message));
            ScaffoldMessenger.of(context).showSnackBar(snackBar);
          },
        );
      });
    });
  }
  
  
  void dispose() {
    _streamSubscription?.cancel();
    _titleController.dispose();
    _contentController.dispose();
    super.dispose();
  }

isSaved

//AddEditNoteScreen
Navigator.pop(context, true);

//NotesScreen
bool? isSaved = await Navigator.push
  • Navigator.pop으로 저장값을 보냅니다.
    • 저장하지 않고 뒤로가기를 누르면 .pop(null)을 보냅니다.
    • saveNote가 실행되면서 .pop(true)값을 보냅니다.

NotesScreen

  • isSaved가 true일 경우 loadNotes로 화면을 새로고침합니다.
floatingActionButton: FloatingActionButton(
        onPressed: () async {
          bool? isSaved = await Navigator.push(
            context,
            MaterialPageRoute(builder: (context) => const AddEditNoteScreen()),
          );

          if (isSaved != null && isSaved) {
            viewModel.onEvent(const NotesEvent.loadNotes());
          }
        },
profile
App, Web Developer

0개의 댓글