Giới thiệu

Trong phát triển ứng dụng Flutter, việc quản lý trạng thái là một vấn đề quan trọng mà các nhà phát triển thường phải đối mặt. Hai trong số các mô hình quản lý trạng thái phổ biến là ScopedModelBLoC Pattern. Bài viết này sẽ đi sâu vào hai mô hình này, giúp bạn hiểu rõ hơn về cách thức hoạt động cũng như cách sử dụng chúng trong ứng dụng Flutter.

ScopedModel

ScopedModel là một thư viện quản lý trạng thái đơn giản, giúp các widget trong Flutter chia sẻ và cập nhật trạng thái mà không cần phải sử dụng các cơ chế phức tạp.

Cách thức hoạt động

ScopedModel cho phép bạn định nghĩa một model (mô hình) có thể được chia sẻ giữa nhiều widget mà không cần phải truyền dữ liệu qua constructor. Các widget có thể lắng nghe sự thay đổi trong model và tự động cập nhật khi có sự thay đổi.

Cài đặt ScopedModel

Để sử dụng ScopedModel, trước tiên bạn cần thêm nó vào file pubspec.yaml:

dependencies:
  scoped_model: ^1.0.1

Sau đó, bạn có thể định nghĩa model của mình. Ví dụ:

import 'package:scoped_model/scoped_model.dart';

class CounterModel extends Model {
  int _count = 0;

  int get count => _count;

  void increment() {
    _count++;
    notifyListeners(); // Thông báo cho các widget lắng nghe rằng dữ liệu đã thay đổi
  }
}

Sử dụng ScopedModel trong Widget

Để sử dụng model trong widget của bạn, bạn cần bao bọc widget gốc trong ScopedModel:

import 'package:flutter/material.dart';
import 'package:scoped_model/scoped_model.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ScopedModel<CounterModel>(
      model: CounterModel(),
      child: MaterialApp(
        home: Scaffold(
          appBar: AppBar(title: Text('ScopedModel Example')),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                ScopedModelDescendant<CounterModel>(
                  builder: (context, child, model) {
                    return Text('Count: ${model.count}');
                  },
                ),
                ElevatedButton(
                  onPressed: () {
                    ScopedModel.of<CounterModel>(context).increment();
                  },
                  child: Text('Increment'),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

BLoC Pattern

BLoC (Business Logic Component) là một mô hình kiến trúc giúp tách biệt logic kinh doanh khỏi giao diện người dùng, cho phép dễ dàng kiểm thử và tái sử dụng mã. BLoC sử dụng các Stream để quản lý trạng thái.

Cách thức hoạt động

Mô hình BLoC giúp bạn quản lý trạng thái ứng dụng bằng cách sử dụng các stream để giao tiếp giữa UI và logic kinh doanh. UI sẽ gửi sự kiện đến BLoC thông qua Sink và nhận trạng thái cập nhật thông qua Stream.

Cài đặt BLoC

Để sử dụng BLoC, bạn có thể cài đặt thư viện flutter_bloc bằng cách thêm vào file pubspec.yaml:

dependencies:
  flutter_bloc: ^8.0.1

Tạo BLoC

Đầu tiên, bạn cần tạo một class BLoC. Ví dụ:

import 'package:flutter_bloc/flutter_bloc.dart';

// Các sự kiện cho BLoC
abstract class CounterEvent {}
class Increment extends CounterEvent {}

// Trạng thái cho BLoC
abstract class CounterState {}
class CounterInitial extends CounterState {
  final int count;
  CounterInitial(this.count);
}

// BLoC cho Counter
class CounterBloc extends Bloc<CounterEvent, CounterState> {
  CounterBloc() : super(CounterInitial(0));

  @override
  Stream<CounterState> mapEventToState(CounterEvent event) async* {
    if (event is Increment) {
      final currentState = state as CounterInitial;
      yield CounterInitial(currentState.count + 1);
    }
  }
}

Sử dụng BLoC trong Widget

Để sử dụng BLoC trong widget của bạn, bạn cần sử dụng BlocProvider để cung cấp BLoC cho widget:

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: BlocProvider(
        create: (context) => CounterBloc(),
        child: CounterPage(),
      ),
    );
  }
}

class CounterPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('BLoC Example')),
      body: Center(
        child: BlocBuilder<CounterBloc, CounterState>(
          builder: (context, state) {
            if (state is CounterInitial) {
              return Text('Count: ${state.count}');
            }
            return CircularProgressIndicator();
          },
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          BlocProvider.of<CounterBloc>(context).add(Increment());
        },
        child: Icon(Icons.add),
      ),
    );
  }
}

So sánh giữa ScopedModel và BLoC Pattern

  • Đơn giản và nhanh chóng: ScopedModel dễ sử dụng và phù hợp cho các ứng dụng nhỏ, nơi mà việc quản lý trạng thái không quá phức tạp.
  • Quản lý trạng thái phức tạp: BLoC Pattern phù hợp hơn cho các ứng dụng lớn với nhiều logic kinh doanh phức tạp, giúp tách biệt rõ ràng giữa UI và logic.
  • Kiểm thử: BLoC dễ dàng kiểm thử hơn so với ScopedModel nhờ vào việc tách biệt logic.

Kết luận

Cả ScopedModelBLoC Pattern đều là những lựa chọn mạnh mẽ cho việc quản lý trạng thái trong Flutter. Lựa chọn mô hình nào phụ thuộc vào quy mô và độ phức tạp của ứng dụng của bạn. Hy vọng rằng bài viết này đã giúp bạn hiểu rõ hơn về hai mô hình này và cách áp dụng chúng trong ứng dụng của mình.