Implementing a Dynamic Caching Framework in Flutter using Hive
In mobile development, caching plays a pivotal role in delivering fast and efficient app performance. Particularly in Flutter, with its expressive UI framework, managing data efficiently is crucial for a smooth user experience. In this blog, I’ll walk you through a dynamic caching framework I implemented in Flutter using Hive, a lightweight NoSQL database, to cache HTTP responses based on a unique key derived from the endpoint and request body. This cache can adaptively expire based on the user's network strength.
Why Use a Caching Framework?
Caching HTTP responses helps in reducing network requests, thereby improving app performance and saving bandwidth. The benefits of using a caching framework include:
Faster response times: Data can be retrieved directly from cache, reducing the time spent on network calls.
Cost savings: Reduced data usage benefits users with limited data plans.
Improved offline capabilities: Cached data allows the app to function even without an internet connection.
Overview of the Framework
Here's how the caching framework works:
Request Interception: Before making an HTTP request, the framework checks if a cached response exists.
Unique Key Generation: It creates a unique key based on the endpoint and body of the request to identify the cache.
Cache Expiry Management: If the cache is valid and hasn't expired, the cached response is returned. The expiry time is dynamically adjusted based on the user's network strength.
HTTP Request: If there is no valid cache, an HTTP request is made.
Cache Storage: The response is stored in the cache with the generated unique key and an expiration time.
Implementation Details
Dependencies
To set up the framework, you will need:
HTTP package: For making HTTP requests.
Hive: For local data storage and caching.
connectivity_plus: For checking the network connectivity.
You can add these dependencies to your pubspec.yaml
file:
dependencies:
http: ^0.13.5
hive_flutter: ^1.2.0
connectivity_plus: ^5.0.1
Setting Up Hive
First, initialise Hive in your Flutter app's main function:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Hive.initFlutter();
runApp(MyApp());
}
Then, create an instance of a Hive box for caching:
Box cacheBox = await Hive.openBox('http_cache');
Creating the Cache Key
To create a unique key, combine the endpoint and body of the HTTP request:
String createCacheKey(String endpoint, Map<String, dynamic>? body) {
final bodyString = body != null ? jsonEncode(body) : '';
return endpoint + bodyString;
}
Determining Expiration Time
The cache expiration time is dynamically adjusted based on the user's network strength. Here's how you can determine the appropriate expiration time:
Check Connectivity: Use a package like
connectivity_plus
to verify if the user's device is online.Measure DNS Lookup Time: If the device has connectivity, use
InternetAddress.lookup
to measure the DNS lookup time to a basic website likegoogle.com
.Determine Expiry Time: If the DNS lookup time exceeds 500 milliseconds, set the cache expiration time to 180 minutes. If the DNS lookup time is 500 milliseconds or less, set the cache expiration time to 60 minutes.
Here's how you can implement this:
Future<Duration> determineExpirationTime() async {
try {
final stopwatch = Stopwatch()..start();
await InternetAddress.lookup('google.com');
stopwatch.stop();
final lookupTime = stopwatch.elapsedMilliseconds;
if (lookupTime > 500) {
// If lookup time is greater than 500 ms, set expiration time to 180 minutes
return Duration(minutes: 180);
} else {
// If lookup time is 500 ms or less, set expiration time to 60 minutes
return Duration(minutes: 60);
}
} catch (e) {
throw Exception('Failed to connect to the internet');
}
}
Implementing the Cache Logic
Here's the method that intercepts the HTTP request and manages the cache:
Future<Response> makeCachedRequest(String endpoint, Map<String, dynamic>? body) async {
final key = createCacheKey(endpoint, body);
final cache = cacheBox.get(key);
// Check if cache exists and is still valid
if (cache != null && cache['expiration'].isAfter(DateTime.now())) {
return cache['response'];
}
// Make the HTTP request if cache is invalid or does not exist
final response = await http.post(Uri.parse(endpoint), body: body);
// Determine expiration time based on network strength
final expirationTime = await determineExpirationTime();
// Store response in cache with an expiration time
cacheBox.put(key, {
'response': response,
'expiration': DateTime.now().add(expirationTime)
});
return response;
}
Conclusion
By using a caching framework in your Flutter app, you can significantly improve user experience and performance. The dynamic cache expiration time allows your app to adapt based on the user's network strength, further optimizing the caching strategy. Hive, as a lightweight NoSQL database, seamlessly integrates with Flutter and provides an efficient way to manage local data storage.
Give this framework a try in your next Flutter project and see how it helps your app perform better!