I'm working on a Flutter project where I want to pre-cache images at the start of the app. The idea is when you start the app the first time, it downloads a list of images either cache / stored in DB / stored in local storage / or any other viable solution. I don't really know the best practice here. And then when you start the app the next time you already have the photos so you don't want to download them again (based on the version of the backend data). From what I saw;
My ideal choice would be the database as I'd have control over the data and it's a rather small app so the computation is minimal and I won't have to ask the user permission.
I've tried over the last days to implement this using every of the solution stated above and I can't make it work.
Right now I want to store an Image into the database (I'm using sqflite) without displaying it and then read it to display it as a Widget from another Screen. I have 2 screens, the first one that I called SplashScreen to fetch and save the images and the second one which is HomeScreen to read the images from the database and display them.
SplashScreen.dart:
class SplashScreen extends StatefulWidget {
@override
_SplashScreenState createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderStateMixin {
bool hasInternet = true;
var subscription;
double loading = 0;
@override
initState() {
super.initState();
getPhotos();
subscription = Connectivity().onConnectivityChanged.listen((ConnectivityResult connectivityResult) {
setState(() {
hasInternet = connectivityResult == ConnectivityResult.mobile || connectivityResult == ConnectivityResult.wifi;
});
});
}
dispose() {
super.dispose();
subscription.cancel();
}
Future getPhotos() async {
List<String> photoUrls = await fetchPhotos();
photoUrls.asMap().forEach((index, photoUrl) async {
var response = await http
.get(photoUrl);
loading = index / photoUrls.length;
// Convert Photo response and save them in DB
imageDBFormat = ...
savePhotosInDB(imageDBFormat)
});
}
@override
Widget build(BuildContext context) {
if(loading == 1) {
Navigator.pushNamed(context, '/');
}
return Center(
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/back.png"),
fit: BoxFit.cover,
)
),
child: Scaffold(
backgroundColor: Theme.of(context).backgroundColor,
body: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
width: 300,
child: LinearProgressIndicator(
value: loading,
valueColor: AlwaysStoppedAnimation<Color>(ProjectColors.primaryDark),
),
)
],
),
],
)
),
),
);
}
}
HomeScreen.dart:
class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> with SingleTickerProviderStateMixin {
List<Widget> images;
initState() {
super.initState();
getImages();
}
void getImages() async {
List imgs = getImagesFromDB();
setState(() {
images = imgs.map((image) {
// Convert imgs from db into Widget
Widget imageWidget = ...
return Container(
child: imageWidget,
);
}).toList();
});
}
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/back.png"),
fit: BoxFit.cover,
)
),
child: Scaffold(
backgroundColor: Theme.of(context).backgroundColor,
body: Column(
children: images == null ? images : <Widget>[],
),
)
);
}
}
I'm OK to reconsider any point to follow the best practices.
Thanks a lot for your help.
You can use https://pub.dev/packages/cached_network_image library,it's using sqlite as a storage already and you can configure duration of persistance.
class CustomCacheManager extends BaseCacheManager {
static const key = "customCache";
static CustomCacheManager _instance;
factory CustomCacheManager() {
if (_instance == null) {
_instance = new CustomCacheManager._();
}
return _instance;
}
CustomCacheManager._() : super(key,
maxAgeCacheObject: Duration(months: 6),
maxNrOfCacheObjects: 100);
Future<String> getFilePath() async {
var directory = await getTemporaryDirectory();
return p.join(directory.path, key);
}
}
and after that you can use in your build method:
CachedNetworkImage(
imageUrl: "http://via.placeholder.com/350x150",
placeholder: (context, url) => CircularProgressIndicator(),
errorWidget: (context, url, error) => Icon(Icons.error),
cacheManager: CustomCacheManager()
),
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With