рдлрд╝реНрд▓рдЯрд░ рдореЛрдмрд╛рдЗрд▓ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ MVVM рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░

рдореИрдВрдиреЗ рдлрд╝реНрд▓рдЯрд░ рд╕реАрдЦрдирд╛ рд╢реБрд░реВ рдХрд░ рджрд┐рдпрд╛ рдФрд░ рд╣рд╛рд▓ рд╣реА рдореЗрдВ рдкреВрд░рд╛ рджрд┐рди рдмрд┐рддрд╛рдпрд╛ рд╣реИ рдХрд┐ рдореИрдВ рдЕрдкрдиреЗ рдлрд╝реНрд▓рдЯрд░ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ рдореЙрдбрд▓-рд╡реНрдпреВ-рд╡реНрдпреВрдореЙрдбрд▓ рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░ рдХреЛ рд╢рд╛рдорд┐рд▓ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░ рд░рд╣рд╛ рд╣реВрдВред рдЖрдорддреМрд░ рдкрд░ рдореИрдВ рдЬрд╛рд╡рд╛ рдореЗрдВ рдПрдВрдбреНрд░реЙрдЗрдб рдХреЗ рд▓рд┐рдП рд▓рд┐рдЦрддрд╛ рд╣реВрдВ, рдореИрдВ AndroidViewModel рдФрд░ LiveData / MutableLiveData рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ MVVM рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддрд╛ рд╣реВрдВред рдпрд╣реА рд╣реИ, рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдФрд░ рдкреИрдЯрд░реНрди рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдореЗрдВ рдЕрдиреБрднрд╡ рд╣реИ, рдЖрд╡реЗрджрди рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдЯрд╛рдЗрдорд░ рд╣реИред рдЗрд╕рд▓рд┐рдП рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдХрд╛рд░реНрдп рдкрд░ рдЗрддрдирд╛ рд╕рдордп рд╡реНрдпрддреАрдд рдХрд░рдиреЗ рд╕реЗ рдХреБрдЫ рдирд╣реАрдВ рд╣реЛрддрд╛ред


Flutter рдореЗрдВ MVVM рдкрд░ рд▓реЗрдЦреЛрдВ рдФрд░ рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХреА рдЦреЛрдЬ (RxDart рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдмрд┐рдирд╛) рдиреЗ рдПрдХ рдЙрджрд╛рд╣рд░рдг рджрд┐рдпрд╛, рдЬрд┐рд╕рдореЗрдВ рдкреВрд░реНрдг рд╕реНрд░реЛрдд рдХрд╛ рдХреЛрдИ рд╕рдВрджрд░реНрдн рдирд╣реАрдВ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдореИрдВ рдЙрди рд▓реЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдЗрд╕реЗ рдереЛрдбрд╝рд╛ рдЖрд╕рд╛рди рдмрдирд╛рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ, рдЬреЛ рдлрд╝реНрд▓рдЯрд░ рдореЗрдВ рдЗрд╕ рдкреИрдЯрд░реНрди рдХрд╛ рдЕрдзреНрдпрдпрди рдХрд░рдиреЗ рдореЗрдВ рд░реБрдЪрд┐ рд░рдЦрддреЗ рд╣реИрдВред


рдкрд░рд┐рдпреЛрдЬрдирд╛


MVVM рдХреЗ рдмрд┐рдирд╛ рдПрдХ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдПрдХ рд╕рд┐рдВрдЧрд▓ рд╕реНрдХреНрд░реАрди рд╣реИ рдЬрд┐рд╕рдореЗрдВ рдХрд╛рдЙрдВрдЯрдбрд╛рдЙрди рдЯрд╛рдЗрдорд░ рд╣реИред рдмрдЯрди рджрдмрд╛рдХрд░, рдЯрд╛рдЗрдорд░ рд╢реБрд░реВ рд╣реЛрддрд╛ рд╣реИ рдпрд╛ рд░рд╛рдЬреНрдп рдкрд░ рдирд┐рд░реНрднрд░ рдХрд░рддрд╛ рд╣реИред рдЬрдм рд╕рдордп рд╕рдорд╛рдкреНрдд рд╣реЛрддрд╛ рд╣реИ, рддреЛ рдПрдХ рдЕрдзрд┐рд╕реВрдЪрдирд╛ рдЬрд╛рд░реА рдХреА рдЬрд╛рддреА рд╣реИ рдпрд╛ рдзреНрд╡рдирд┐ рдмрдЬрд╛рдИ рдЬрд╛рддреА рд╣реИред


рдореЙрдбрд▓ рд╡рд┐рд╡рд░рдг


рдЪрд▓рд┐рдП рдПрдорд╡реАрд╡реАрдПрдо рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЛ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВ, рдкрд╣рд▓реЗ рдореИрдВрдиреЗ рдЙрд╕ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛ рд╡рд░реНрдгрди рдХрд┐рдпрд╛ рд╣реИ рдЬрд┐рд╕реЗ рдореБрдЭреЗ рд╡рд┐рдЬреЗрдЯ рдФрд░ рдореЙрдбрд▓ (рдЯрд╛рдЗрдорд░_рд╡реНрдпреВ_рдореЙрдбрд▓.рдбрд╛рд░реНрдЯ рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдИ рдЧрдИ рдереА) рдХреЗ рдмреАрдЪ рдмрд╛рддрдЪреАрдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:

abstract class TimerViewModel { Stream<bool> get timerIsActive; Stream<String> get timeTillEndReadable; Stream<bool> get timeIsOver; void changeTimerState(); } 

рдпрд╣реА рд╣реИ, рдореИрдВ рдЙрди рдШрдЯрдирд╛рдУрдВ рдХреЛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдЬреЛ рдмрдЯрди рдХреА рд╕реНрдерд┐рддрд┐ рдХреЛ рдмрджрд▓рддреЗ рд╣реИрдВ (рдЯрд╛рдЗрдорд░ рдХреЛ рд░реЛрдХреЗрдВ - рдЬрд╛рд░реА рд░рдЦреЗрдВ), рдпрд╣ рдЬрд╛рдирдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рдЯрд╛рдЗрдорд░ рдХрдм рд╕рдорд╛рдкреНрдд рд╣реЛ рдЧрдпрд╛ рд╣реИ, рдЙрд╕ рд╕рдордп рдХреЛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд┐рд╕реЗ рд╕реНрдХреНрд░реАрди рдкрд░ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдореИрдВ рдЯрд╛рдЗрдорд░ рдХреЛ рд░реЛрдХрдирд╛ / рд╢реБрд░реВ рдХрд░рдирд╛ рднреА рдЪрд╛рд╣рддрд╛ рд╣реВрдВред рдХрдбрд╝рд╛рдИ рд╕реЗ рдмреЛрд▓рддреЗ рд╣реБрдП, рдЗрд╕ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛ рд╡рд░реНрдгрди рд╡реИрдХрд▓реНрдкрд┐рдХ рд╣реИ, рдпрд╣рд╛рдВ рдореИрдВ рдХреЗрд╡рд▓ рдпрд╣ рджрд┐рдЦрд╛рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдХрд┐ рдореЙрдбрд▓ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреНрдпрд╛ рд╣реИред

ViewModel рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди


рдореЙрдбрд▓ рдХрд╛ рдЖрдЧреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдЯрд╛рдЗрдорд░_рд╡реНрдпреВ_рдореЙрдбрд▓_рдЗрдореНрдкрд▓.рдбрд╛рд░реНрдЯ рдлрд╝рд╛рдЗрд▓ рд╣реИ


рдЯрд╛рдЗрдорд░ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдПрдХ рд╕рд┐рдВрдЧрд▓ рд╕рдмреНрд╕рдХреНрд░рд╛рдЗрдмрд░ рдХреЗ рд╕рд╛рде рд╕реНрдЯреНрд░реАрдордХрдВрдЯреНрд░реЛрд▓рд░ рдХреЗ рд░реВрдк рдореЗрдВ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рдХреЛрдб рдХреЗ рд▓рд┐рдП рдЖрдзрд╛рд░ рдЗрд╕ рд▓реЗрдЦ рд╕реЗ рд▓рд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред рдмрд╕ рдирд┐рдпрдВрддреНрд░рдХ рдХрд╛ рд╡рд┐рд╡рд░рдг рд╣реИ, рдЬреЛ рдПрдХ рдЯрд╛рдЗрдорд░ рдкрд░ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЗрд╕реЗ рдлрд┐рд░ рд╕реЗ рд░реЛрдХрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдФрд░ рдлрд┐рд░ рд╕реЗ рд╢реБрд░реВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░, рдПрдХ рд▓рдЧрднрдЧ рд╕рд╣реА рдореИрдЪред рдореЗрд░реЗ рдХрд╛рд░реНрдп рдХреЗ рд▓рд┐рдП рдХреЛрдб рдмрджрд▓ рдЧрдпрд╛:

 static Stream<DateTime> timedCounter(Duration interval, Duration maxCount) { StreamController<DateTime> controller; Timer timer; DateTime counter = new DateTime.fromMicrosecondsSinceEpoch(maxCount.inMicroseconds); void tick(_) { counter = counter.subtract(oneSec); controller.add(counter); // Ask stream to send counter values as event. if (counter.millisecondsSinceEpoch == 0) { timer.cancel(); controller.close(); // Ask stream to shut down and tell listeners. } } void startTimer() { timer = Timer.periodic(interval, tick); } void stopTimer() { if (timer != null) { timer.cancel(); timer = null; } } controller = StreamController<DateTime>( onListen: startTimer, onPause: stopTimer, onResume: startTimer, onCancel: stopTimer); return controller.stream; } 

рдЕрдм рдореЙрдбрд▓ рдХрд╛рдо рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЯрд╛рдЗрдорд░ рдХреА рд╢реБрд░реБрдЖрдд рдФрд░ рдард╣рд░рд╛рд╡ рдХреИрд╕реЗ рд╣реЛрддрд╛ рд╣реИ:

 @override void changeTimerState() { if (_timeSubscription == null) { print("subscribe"); _timer = timedCounter(oneSec, pomodoroSize); _timerIsEnded.add(false); _timerStateActive.add(true); _timeSubscription = _timer.listen(_onTimeChange); _timeSubscription.onDone(_handleTimerEnd); } else { if (_timeSubscription.isPaused) { _timeSubscription.resume(); _timerStateActive.add(true); } else { _timeSubscription.pause(); _timerStateActive.add(false); } } } 

рдЯрд╛рдЗрдорд░ рдХреЛ рдХрд╛рдо рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдЗрд╕реЗ _timeSubscription = _timer.listen(_onTimeChange); рд╕рджрд╕реНрдпрддрд╛ _timeSubscription = _timer.listen(_onTimeChange); ред рд░реЛрдХреЗрдВ / рдЬрд╛рд░реА рд░рдЦреЗрдВ рдХреЛ рдард╣рд░рд╛рд╡ / рдлрд┐рд░ рд╕реЗ рд╢реБрд░реВ рд╕рджрд╕реНрдпрддрд╛ ( _timeSubscription.pause(); / _timeSubscription.resume(); ) рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрд╣рд╛рдВ, _timerStateActive рдЯрд╛рдЗрдорд░ рдЧрддрд┐рд╡рд┐рдзрд┐ рд╕реНрдерд┐рддрд┐ рд╕реНрдЯреНрд░реАрдо рдореЗрдВ рдПрдХ рд░рд┐рдХреЙрд░реНрдб рд╣реИ рдФрд░ рдЯрд╛рдЗрдорд░ рдХреЗ рдЪрд╛рд▓реВ рд╣реЛрдиреЗ рдпрд╛ рдирд╣реАрдВ рд╣реЛрдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдХреА рдПрдХ рдзрд╛рд░рд╛ _timerIsEnded рд╣реИред

рд╕рднреА рдкреНрд░рд╡рд╛рд╣ рдирд┐рдпрдВрддреНрд░рдХреЛрдВ рдХреЛ рдЖрд░рдВрднреАрдХрд░рдг рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред рдпрд╣ рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдореВрд▓реНрдпреЛрдВ рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд╛рдпрдХ рднреА рд╣реИред

 TimerViewModelImpl() { _timerStateActive = new StreamController(); _timerStateActive.add(false); _timerIsEnded = new StreamController(); _timeFormatted = new StreamController(); DateTime pomodoroTime = new DateTime.fromMicrosecondsSinceEpoch(pomodoroSize.inMicroseconds); _timeFormatted.add(DateFormat.ms().format(pomodoroTime)); } 

рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдореЗрдВ рд╡рд░реНрдгрд┐рдд рдзрд╛рд░рд╛рдУрдВ рдХреЛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛:

 @override Stream<bool> get timeIsOver => _timerIsEnded.stream; @override Stream<bool> get timerIsActive { return _timerStateActive.stream; } @override Stream<String> get timeTillEndReadable => _timeFormatted.stream; 

рдпрд╣реА рд╣реИ, рд╕реНрдЯреНрд░реАрдо рдореЗрдВ рдХреБрдЫ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдПрдХ рдирд┐рдпрдВрддреНрд░рдХ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рд╡рд╣рд╛рдВ рдХреБрдЫ рднреА рд▓реЗрдирд╛ рдФрд░ рд░рдЦрдирд╛ рдЕрд╕рдВрднрд╡ рд╣реИ (рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ рд╕реНрдЯреНрд░реАрдо рдЙрддреНрдкрдиреНрди рд╣реЛрдиреЗ рдкрд░ рдПрдХ рдЕрдкрд╡рд╛рдж рд╣реИ)ред рдФрд░ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рд╡рд┐рдЬреЗрдЯ рддреИрдпрд╛рд░ рдкреНрд░рд╡рд╛рд╣ рдХреЛ рдЙрдард╛рддрд╛ рд╣реИ, рдЬреЛ рдореЙрдбрд▓ рдирд┐рдпрдВрддреНрд░рдХреЛрдВ рджреНрд╡рд╛рд░рд╛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред


рд╡рд┐рдЬреЗрдЯ рдФрд░ рд░рд╛рдЬреНрдп


рдЕрдм рд╡рд┐рдЬреЗрдЯ рдХреЗ рд▓рд┐рдПред рд░рд╛рдЬреНрдп рдирд┐рд░реНрдорд╛рдг рдореЗрдВ ViewModel рдХреЛ рдЖрд░рдВрднреАрдХреГрдд рдХрд┐рдпрд╛ рдЧрдпрд╛

 _MyHomePageState() { viewModel = new TimerViewModelImpl(); } 

рдлрд┐рд░, рдЖрд░рдВрднреАрдХрд░рдг рдореЗрдВ, рдереНрд░реЗрдб рдХреЗ рд▓рд┐рдП рд╢реНрд░реЛрддрд╛рдУрдВ рдХреЛ рдЬреЛрдбрд╝рд╛ рдЬрд╛рддрд╛ рд╣реИ:

  viewModel.timerIsActive.listen(_setIconForButton); viewModel.timeIsOver.listen(informTimerFinished); viewModel.timeTillEndReadable.listen(secondChanger); 

рд╢реНрд░реЛрддрд╛ рд▓рдЧрднрдЧ рдкрд╣рд▓реЗ рдХреА рддрд░рд╣ рд╣реА рдХрд╛рд░реНрдп рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рдХреЗрд╡рд▓ рдЕрд╢рдХреНрдд рдЬрд╛рдБрдЪ рдЬреЛрдбрд╝реА рдЧрдИ рд╣реИ рдФрд░ _setIconForButton рдХреЛ рдереЛрдбрд╝рд╛ рдмрджрд▓ рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ:

 Icon iconTimerStart = new Icon(iconStart); Icon iconTimerPause = new Icon(iconCancel); void _setIconForButton(bool started) { if (started != null) { setState(() { if (started) { iconTimer = iconTimerPause; } else { iconTimer = iconTimerStart; } }); } } 

Main.dart рдореЗрдВ рдмрд╛рдХреА рдмрджрд▓рд╛рд╡ рд╕рднреА рдЯрд╛рдЗрдорд░ рд▓реЙрдЬрд┐рдХ рдХреЛ рд╣рдЯрд╛рдиреЗ рдХрд╛ рд╣реИ - рдЕрдм рдпрд╣ ViewModel рдореЗрдВ рд░рд╣рддрд╛ рд╣реИред

рдирд┐рд╖реНрдХрд░реНрд╖


рдореЗрд░рд╛ MVVM рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдЕрддрд┐рд░рд┐рдХреНрдд рд╡рд┐рдЬреЗрдЯреНрд╕ (рдЬреИрд╕реЗ рдХрд┐ рд╕реНрдЯреНрд░реАрдордмреНрдпреВрд▓рд░) рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рд╡рд┐рдЬреЗрдЯреНрд╕ рдХреА рд╕рдВрд░рдЪрдирд╛ рд╕рдорд╛рди рд░рд╣рддреА рд╣реИред рд╕реНрдерд┐рддрд┐ рдпрд╣ рд╣реИ рдХрд┐ Android ViewModel рдФрд░ LiveData рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреИрд╕реЗ рдХрд░рддрд╛ рд╣реИред рдпрд╣реА рд╣реИ, рдореЙрдбрд▓ рдХреЛ рдЖрд░рдВрднреАрдХреГрдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдлрд┐рд░ рдЙрди рд╢реНрд░реЛрддрд╛рдУрдВ рдХреЛ рдЬреЛрдбрд╝рд╛ рдЬрд╛рддрд╛ рд╣реИ рдЬреЛ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдореЙрдбрд▓ рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдкрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХрд░рддреЗ рд╣реИрдВред


рд╕рднреА рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЗ рд╕рд╛рде рдкрд░рд┐рдпреЛрдЬрдирд╛ рднрдВрдбрд╛рд░

Source: https://habr.com/ru/post/hi427327/


All Articles