Introdução

O Flutter, framework open-source da Google, permite o desenvolvimento de aplicativos multiplataforma de forma rápida e eficaz. Com a base em Dart, ele oferece uma experiência de desenvolvimento produtiva e com interfaces altamente responsivas. Neste tutorial, vamos explorar como construir uma aplicação utilizando as boas práticas da arquitetura MVVM (Model-View-ViewModel) que melhora a separação de responsabilidades no código. Além disso, vamos integrar ferramentas populares como Riverpod para gerenciamento de estados e Dio para chamadas HTTP. Se você é um desenvolvedor que quer se aprofundar no Flutter e implementar boas práticas de programação, este guia é para você. Vamos juntos construir uma aplicação completa do zero!

Etapas

  1. Configuração do Ambiente de Desenvolvimento

    Antes de tudo, você precisa configurar seu ambiente de desenvolvimento. Primeiro, instale o Flutter SDK em sua máquina através do site oficial do Flutter. Após a instalação, verifique se o flutter está acessível no terminal utilizando o comando `flutter doctor`. Este comando irá verificar a instalação e mostrar se algum componente está faltando.

    commands
    # Verificar a instalação do Flutter
    flutter doctor

  2. Criação do Projeto Flutter

    Utilize o comando abaixo para criar um novo projeto Flutter. Substitua `my_flutter_app` pelo nome da sua aplicação. Este comando irá criar uma estrutura básica de diretórios para a aplicação.

    commands
    # Criar um novo projeto Flutter
    flutter create my_flutter_app
    # Navegue para o diretório do projeto
    cd my_flutter_app

  3. Configuração de Dependências

    Edite o arquivo `pubspec.yaml` para adicionar as dependências Riverpod e Dio. Essas dependências são necessárias para o gerenciamento de estado e requisições HTTP, respectivamente. Após adicionar as dependências, execute o comando `flutter pub get` para instalá-las.

    pubspec.yaml
    dependencies:
      flutter:
        sdk: flutter
      dio: ^5.0.0
      flutter_riverpod: ^1.0.0

  4. Criando a Estrutura MVVM

    Para seguir a arquitetura MVVM, comece criando as pastas `model`, `view`, e `view_model` dentro do diretório `lib`. Em seguida, crie um modelo `User` simples que representará o usuário na aplicação.

    User.dart
    class User {
      final String name;
      final String email;
    
      User({required this.name, required this.email});
    }

  5. Implementação do ViewModel com Riverpod

    Crie um arquivo chamado `user_view_model.dart` dentro da pasta `view_model`. Neste arquivo, implemente a classe `UserViewModel` que gerencia o estado do usuário utilizando Riverpod. A classe terá métodos para buscar os dados do usuário e notificar a view sobre alterações.

    user_view_model.dart
    import 'package:flutter_riverpod/flutter_riverpod.dart';
    import 'User.dart';
    import 'dio_client.dart';
    
    final userViewModelProvider = StateNotifierProvider<UserViewModel, User?>((ref) => UserViewModel());
    
    class UserViewModel extends StateNotifier<User?> {
      UserViewModel() : super(null);
    
      Future<void> fetchUser() async {
        final user = await DioClient().getUser();
        state = user;
      }
    }

  6. Implementando o Dio para Requisições HTTP

    Crie um arquivo chamado `dio_client.dart` no diretório raiz do `lib` para encapsular chamadas HTTP. Neste exemplo, faremos uma requisição GET para uma API fictícia que retorna dados de um usuário.

    dio_client.dart
    import 'package:dio/dio.dart';
    import 'User.dart';
    
    class DioClient {
      final Dio _dio = Dio();
    
      Future<User> getUser() async {
        final response = await _dio.get('https://api.example.com/user');
        return User(name: response.data['name'], email: response.data['email']);
      }
    }

  7. Construindo a View

    Crie uma tela que exibirá as informações do usuário. Para isso, no diretório `view`, crie um arquivo chamado `user_screen.dart`. Utilize o `ConsumerWidget` para escutar as mudanças do `UserViewModel` e exibir as informações do usuário.

    user_screen.dart
    import 'package:flutter/material.dart';
    import 'package:flutter_riverpod/flutter_riverpod.dart';
    import 'user_view_model.dart';
    
    class UserScreen extends ConsumerWidget {
      @override
      Widget build(BuildContext context, WidgetRef ref) {
        final user = ref.watch(userViewModelProvider);
    
        return Scaffold(
          appBar: AppBar(title: Text('User Info')), 
          body: Center(
            child: user == null 
                ? CircularProgressIndicator() 
                : Text('Name: ${user.name}, Email: ${user.email}'),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: () {
              ref.read(userViewModelProvider.notifier).fetchUser();
            },
            child: Icon(Icons.refresh),
          ),
        );
      }
    }

  8. Implementação dos Testes

    Para garantir que sua aplicação funcione conforme esperado, implemente testes para o ViewModel e a integração do Dio. Utilize o package `flutter_test` e o `mockito` para realizar os testes necessários.

    user_view_model_test.dart
    import 'package:flutter_test/flutter_test.dart';
    import 'package:mockito/mockito.dart';
    import 'user_view_model.dart';
    import 'dio_client.dart';
    
    class MockDioClient extends Mock implements DioClient {}
    
    void main() {
      test('fetch user updates state', () async {
        final mockDioClient = MockDioClient();
        when(mockDioClient.getUser()).thenAnswer((_) async => User(name: 'John Doe', email: 'john@example.com'));
        final userViewModel = UserViewModel();
    
        await userViewModel.fetchUser();
        expect(userViewModel.state?.name, 'John Doe');
      });
    }

  9. Executando a Aplicação

    Para executar a aplicação, utilize o comando abaixo. Certifique-se de que o emulador esteja ativo ou que um dispositivo físico esteja conectado. A aplicação estará disponível em seu emulador ou dispositivo.

    commands
    # Executar a aplicação em um emulador ou dispositivo
    flutter run

Conclusão

Neste tutorial, você aprendeu a criar uma aplicação Flutter utilizando a arquitetura MVVM com integração do Riverpod e Dio. Exploramos desde a configuração do ambiente até a implementação de testes unitários, cobrindo todos os aspectos necessários para desenvolver aplicações modernas e manuteníveis. A utilização de padrões arquiteturais e ferramentas de gerenciamento de estado permite uma melhor organização do código e facilita a escalabilidade das aplicações. Holisticamente, esses conhecimentos te preparam para criar aplicações mais complexas e robustas utilizando Flutter.

Hashtags

#Flutter #Dart #MVVM #Riverpod #Dio #DesenvolvimentoDeSoftware