Best strategy for locally storing remote data in Flutter - json

I have a Flutter app that has to request a considerable volume of JSON data from the network. This data has to be converted into a Map.
The remote data changes like every week or so, so I am looking for a way to "cache" or permanently store it in order not to have to request it every time the user opens the app.
What would be the best way to achieve this?

If you want to do something quick, you can store that data in a file (source) using path_provider
Create a reference to the file location:
Future<File> get _localFile async {
final path = await getApplicationDocumentsDirectory();
return File('$path/counter.txt');
}
Write data:
Future<File> writeCounter(int counter) async {
final file = await _localFile;
return file.writeAsString('$counter');
}
Read data:
Future<int> readCounter() async {
try {
final file = await _localFile;
final contents = await file.readAsString();
return int.parse(contents);
} catch (e) {
return 0;
}
}
If you want to know all the options you have I suggest you read this: https://flutter.dev/docs/development/data-and-backend/state-mgmt/intro

You can use Hive lib to Save your data
import 'dart:io';
import 'package:hive/hive.dart';
part 'main.g.dart';
#HiveType(typeId: 1)
class Person {
Person({required this.name, required this.age, required this.friends});
#HiveField(0)
String name;
#HiveField(1)
int age;
#HiveField(2)
List<String> friends;
#override
String toString() {
return '$name: $age';
}
}
void main() async {
var path = Directory.current.path;
Hive
..init(path)
..registerAdapter(PersonAdapter());
var box = await Hive.openBox('testBox');
var person = Person(
name: 'Dave',
age: 22,
friends: ['Linda', 'Marc', 'Anne'],
);
await box.put('dave', person);
print(box.get('dave')); // Dave: 22
}

Related

What is app_flutter directory in dart/flutter

I'm working on a flutter application, and I want to write to a JSON file.
My JSON file is in the 'assets/' folder that I created and added to pubspec.yaml.
I can get the data using :
final String res2 = await rootBundle.loadString("assets/profile.json");
I went through here to get the path to the file: https://docs.flutter.dev/cookbook/persistence/reading-writing-files,
Like this :
Future<File> get _localFile async {
final path = await _localPath;
return File('$path/assets/profile.json');
}
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> writeJSON(newDatas) async {
final file = await _localFile;
// Write the file
return file.writeAsString('$newDatas');
}
But when I try to access the file, I get this error:
Cannot open file, path = '/data/user/0/com.example.myapp/app_flutter/assets/profile.json'
Do you know why?
Thank you!

Retrieve documentId from future

I have not been able to find an answer to my problem so I will ask here.
I created a document that contains one piece of data. Once that document is created I need to retrieve the id of that document so I can use that string to add to another document that will be created next. The code is below where I call the Future function "saveNewAgency" as well as the code for the Future function.
if (globals.newAgency == true) {
firestoreService.saveNewAgency(newAgency);
agentProvider.saveAgent();
globals.newAgency = false;
} else {
firestoreService.saveAgency(newAgency);
}
Future<String> saveNewAgency(Agency agency) async {
DocumentReference docRef = await _db
.collection('agency')
.add(agency.toMap())
.then((value) => value.id);
//globals.agencyId = docRef.id;
}
As you can see I tried to set a global variable inorder to get the documentId but that code never gets executed so I commented it out.
This is a small thing but it is just another step I have reached in my journey of learning flutter and firebase.
Thanks
String Id = _db .collection('agency').doc().id;
Future<String> saveNewAgency(Agency agency) async {
await _db
.collection('agency')
.doc(id)
.set(agency.toMap())
.then((value) => {
print(id);
});
}
Try this.
Future<String> saveNewAgency(Agency agency) async {
await _db
.collection('agency')
.add(agency.toMap())
.then((value) => {
globals.agencyId = value.id
});
}

Dart JSON Encode/Decode causing error due to extra bracket

So I have a Flutter app which I'm trying to save some data locally as a JSON file. I'm doing this using dart:convert and jsonEncode and jsonDecode and a Dart Map, but for some reason when I save the Map to a file using file.writeAsString(jsonEncode(map)), it seems to be adding a phantom end bracket to the end like so (not consistently either it doesn't seem):
{
"posts_in_progress":
{
"https://dts.podtrac.com/redirect.mp3/chtbl.com/track/9EE2G/pdst.fm/e/rss.art19.com/episodes/67461d56-cdd8-4b03-a957-3edb110232d4.mp3":73035
}
}
}
This then causes an error when trying to read and decode this file with jsonDecode(file.readAsString()) because of the extra bracket.
What is causing this extra bracket? And how can I prevent this from happening or handle for the extra bracket when its there on the decoding side?
Edit:
LocalServices file which handles all the local data json storage. It doesn't seem to always happen and be easily reproducible, but it has happened multiple times (before I was just handling the local file saving and reading within other methods, but tried to create this local services class to help fix it, still haven't figured out what causes it tho).
import 'dart:convert';
import 'package:path_provider/path_provider.dart';
import 'dart:io';
class LocalService {
bool _isInitialized = false;
Map data;
String filepath;
String filename = 'local_data.json';
File file;
initialize() async {
filepath = await getApplicationDocumentsDirectory().then((directory) => directory.path);
file = await File('$filepath/$filename').exists() ? File('$filepath/$filename') : null;
if(file != null) {
print('Local Data File Exists, start decoding... \n${await file.readAsString()}');
data = jsonDecode(await file.readAsString());
print('Decoding complete!');
} else {
file = new File('$filepath/$filename');
data = new Map<String, dynamic>();
}
_isInitialized = true;
}
update() async {
if(!_isInitialized) {
await this.initialize();
}
try {
data = jsonDecode(await file.readAsString());
} catch (e) {
print('Error Updating file: $e');
}
}
Future<void> setData(String key, dynamic value) async {
if(!_isInitialized) {
await this.initialize();
}
try {
data[key] = value;
await file.writeAsString(jsonEncode(data));
await update();
} catch (e) {
print('Error writing update to file: $e\n$key/$value');
}
}
}

Flutter local json

I copy this file in my local and try to parse it.
The following are my questions in mind:
1) how to parse the categories [sport, maths] for listview purpose/
2) how to parse item inside the category?
3) does it need to change the format of the json to have simpler codes?
Currently, this is the code
Future<dynamic> _future;
Future<String> _getJson() async {
var response = await rootBundle.loadString('assets/example_2.json');
var decodedJason = json.decode(response);
return (decodedJason); }
void initState() {
_future = _getJson();
super.initState(); }
Thanks in advance
Add Your JSON File To The pubspec.yaml
assets:
- assets/example_2.json
And Then You Can Use rootBundle To Load & Display It
import 'dart:async' show Future;
import 'package:flutter/services.dart' show rootBundle;
Future<String> loadAsset() async {
return await rootBundle.loadString('assets/config.json');
}
Make A Sure Json File Is Not Empty?

Where is the default save location Flutter

when I write this code:
onSubmit(){
if(csvname.isEmpty){
print('type name');
}else {
File csvFile = new File(csvname + ".csv");
print('yesssss');
}
}
Does it even create a csv file?
If yes where is it saved or how can I view it?
Full Code / pastebin
It is not saving it with the code you posted, see this doc. Here is an example on how to write to a local file:
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> get _localFile async {
final path = await _localPath; return File('$path/counter.txt');
}
Future<File> writeCounter(int counter) async {
final file = await _localFile; // Write the file return file.writeAsString('$counter');
}