This guide will take you through the process of storing data fetched from a remote API, ensuring it can be displayed even when there is no active internet connection. Additionally, it will cover synchronizing data once the connection is restored. In this guide, I'll be using Flutter and using Getx framework for state management.
- Getting Started.
- Folder Structure.
- Add Dependencies.
- Initialize Get Storage.
- Controller Class.
- Display Cached Data in screen.
- Technologies.
Before installing , make sure you have the following prerequisites installed:
- Flutter: See Flutter's installation guide for instructions on how to install Flutter.
Once you have the prerequisites installed, follow these steps to install:
- Clone the project repository to your local machine.
- Navigate to the root directory of the project.
- Run
flutter pub get
to install the required dependencies. - Run
flutter run
to launch the app.
This Project follows the Model-View-Controller (MVC) design pattern. The primary directory structure consists of three main folders: Common, Core, and Features.
getStorage
├─ ios/
├─ android/
├─ assets/
│ ├─ images/
│ ├─ icons/
│ ├─ lottie/
├─ lib/
│ ├─ common/
│ ├─ core/
│ │ ├─ binding/
│ │ ├─ constant/
│ │ ├─ localization/
│ │ ├─ route/
│ │ ├─ theme/
│ ├─ feature/
│ │ ├─ controller/
│ │ ├─ service/
│ │ ├─ model/
│ │ ├─ screen/
│ │ ├─ widget/
│ ├─ main.dart
├─ .env
├─ pubspec.yaml
Common file is directory typically contains code shared throughout the application. Common elements found here include utility classes and custom widgets.
Core file directory generally holds foundational code and essential business logic for the application. This may encompass functionalities like binding, routing, localization, themes, and other critical components that are used throughout the app.
All the features in the app are organized into folders named after each feature. Each of these folders contains related files, including controller, model, service, screen, and widget.
Open the pubspec.yaml
file located in the root of your project, and add the following line under the dependencies section.
get_storage: ^2.1.1
connectivity_plus: ^5.0.2
To initialize get storage, we need to call GetStorage().init
in the main function.
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await GetStorage.init();
runApp(const MyApp());
}
Before we continue, I assume you have created a model class, a service class, and a screen class and are fetching data from the API. Now, let’s create a controller class to handle the business logic of the app. I have created three functions to handle caching and synchronizing data as follows:
A function refresh to update the UI once the internet connection is restored.
refreshData() async {
await syncData();
}
The main purpose of the syncData
function is to check the internet connection. By using the Connectivity Plus
package.
Initially, the function checks the internet connection. If the connection is off, it displays data from the GetStorage. Otherwise, it fetches and displays data from the getAllWeather
function.
syncData() async {
try {
isLoading = true;
update();
var connectivityResult = await Connectivity().checkConnectivity();
if (connectivityResult == ConnectivityResult.none) {
final cachedWeather = getStorage.read('cachedWeather');
if (cachedWeather != null) {
weather = cachedWeather;
update();
}
} else {
await getAllWeather();
}
}
finally {
isLoading = false;
update();
}
}
This function is designed to retrieve data either from a remote server or locally, depending on the internet connectivity status. If the connection is successful, it fetches the data and saves it in the getstorge. In case of an error, it checks the getstorge and displays the stored data.
getAllWeather() async {
try {
await service.getAllWeather(
onDone: (value) {
weather = value;
getStorage.write('cachedWeather', weather);
update();
},
onError: (String error) {
final cachedWeather = getStorage.read('cachedWeather');
if (cachedWeather != null) {
weather = cachedWeather;
update();
}
},
);
}
finally {
isLoading = false;
update();
}
}
Now that we have cached the data in getStorage, we can display it in our app even when offline or when the API is not accessible.
Call the syncData
function to check the internet status. In this UI, there are three cases: first, read from getStorage and display it; second, if there is no internet, cache the data; finally, when the internet is available, update the data.
WeatherController().syncData();
return GetBuilder<WeatherController>(
builder: (controller) {
if (controller.weather == null) {
final cachedWeather = controller.getStorage.read('cachedWeather');
if (cachedWeather != null) {
return CityWidget();
}
else {
return const Text("No internet and no cached data");
}
}
else {
return CityWidget();
}
},
);
}
Sometimes, the Connectivity Plus
package may cause issues with CocoaPods. I recommend the following:
- Navigate to the /ios folder inside your Flutter project.
- Locate the
Podfile.lock
file and uncomment the lineplatform :ios, '12.0'
(usually in line 2). - Run
flutter clean
. - Run
flutter run
.
library | Usage |
---|---|
Getx | State management , Navigation, Dependency Management |
Get Storage | Store and Retrieve Data in Memory |
Connectivity Plus | Discover Network Connectivity |
Afnan Almohammadi