# Building a Testable Network Layer and Three-Tier State Management in Flutter

DevFeed: [Building a Testable Network Layer and Three-Tier State Management in Flutter](<https://devfeed.tech/articles/building-a-testable-network-layer-and-three-tier-state-management-in-flutter-23048.md>)

Original publisher: [Read original article](<https://medium.com/flutter-community/building-a-testable-network-layer-and-three-tier-state-management-in-flutter-bebdd831cf25?source=rss----86fb29d7cc6a---4>)

Author: Veli Bacık

Published: 2026-07-08T15:56:52Z

Content type: tutorial

Language: en

Sources: [Flutter Community - Medium](<https://devfeed.tech/sources/flutter-community-medium.md>)

Topics: [Flutter](<https://devfeed.tech/topics/flutter.md>), [Network](<https://devfeed.tech/topics/network.md>), [API](<https://devfeed.tech/topics/api.md>), [HTTP](<https://devfeed.tech/topics/http.md>), [Refactoring](<https://devfeed.tech/topics/refactoring.md>), [Error Handling](<https://devfeed.tech/topics/error-handling.md>), [JSON](<https://devfeed.tech/topics/json.md>), [ui](<https://devfeed.tech/topics/ui.md>), [App](<https://devfeed.tech/topics/app.md>)

Tags: [api](<https://devfeed.tech/tags/api.md>), [backend](<https://devfeed.tech/tags/backend.md>), [building](<https://devfeed.tech/tags/building.md>), [code](<https://devfeed.tech/tags/code.md>), [dart](<https://devfeed.tech/tags/dart.md>), [error-handling](<https://devfeed.tech/tags/error-handling.md>), [flutter](<https://devfeed.tech/tags/flutter.md>), [how-to](<https://devfeed.tech/tags/how-to.md>), [http](<https://devfeed.tech/tags/http.md>), [implementation](<https://devfeed.tech/tags/implementation.md>), [integration](<https://devfeed.tech/tags/integration.md>), [json](<https://devfeed.tech/tags/json.md>), [masterclass](<https://devfeed.tech/tags/masterclass.md>), [network](<https://devfeed.tech/tags/network.md>), [refactoring](<https://devfeed.tech/tags/refactoring.md>), [server](<https://devfeed.tech/tags/server.md>), [state-management](<https://devfeed.tech/tags/state-management.md>)

## AI overview

This tutorial explains how to refactor a Flutter application's network and state-management architecture. It introduces a generic, testable network manager and service/model layers, then applies a three-tier state model using Cubit for business state, BlocSelector for targeted rebuilds, and ValueNotifier for widget-local UI state.

## Source excerpt

How to wrap HTTP behind a generic, testable network manager with sealed results -- then drive your screens with a three-tier state model: global Cubit, page Cubit, and widget-local ValueNotifier. Flutter Refactoring Masterclass -- Part 3 GitHub - VB10/flight_booking: Flight App for refactoring real project PRs: #11, #12 📺 Video Series: Network & Service Layer https://medium.com/media/2d40d555e4d8968f1d15fb35e2e91553/hrefhttps://medium.com/media/3d8a8a32a77c98177ba10492a892aed6/href 🤖 Want to apply these changes to your project? See the AI prompt at the end. The Problem In Part 2 we split the login page into View, ViewModel, and Mixin -- but the ViewModel still new'd up a Dio() instance and hard-coded http://localhost:8080 inline. Every screen that talked to the backend did the same thing: create a fresh Dio, paste the base URL, decode JSON by hand, and copy-paste the same if (statusCode == 200) ... else ... catch (e) ladder. That pattern rots fast. A URL change means a project-wide search. A new header (auth token, API version) has to be added everywhere. Error handling drifts -- one screen returns 'Server hatası', another swallows the exception. And nothing is testable, because the network call is welded to the widget. As the video puts it: the person writing the code shouldn't be able to say "this only works with internet" -- the network is a dependency, and dependencies must be managed. There's a second rot: state. setState rebuilds the whole widget on every field change. A page with a loading flag, an error string, and a list re-renders all three even when only one changed. And there's no consistent home for "where does the loading state live" -- sometimes a ValueNotifier, sometimes a bool, sometimes buried in _PageState. This article fixes both on the same module. PR #11 builds a generic network + service + model layer. PR #12 layers a three-tier state model on top -- Cubit for business, BlocSelector for surgical rebuilds, ValueNotifier for widget-local UI. What We Change