Flutter: Ukládání dat
Z MiS
(Rozdíly mezi verzemi)
m (Vytvoření kostry stránky) |
(Lokální export do JSON pomocí jsonEncode/Decode().) |
||
| Řádka 1: | Řádka 1: | ||
[[Category:VSE]][[Category:Informatika]][[Category:Programování]][[Category:Flutter]] | [[Category:VSE]][[Category:Informatika]][[Category:Programování]][[Category:Flutter]] | ||
| − | == | + | Pro trvalé uložení dat i po vypnutí aplikace můžeme data uložit: |
| + | * na lokální disk konkrétního zařízení | ||
| + | * do síťového úložiště (databáze, cloudové úložiště) | ||
| + | * můžeme rozdělit aplikaci na frontend a backend, kde data budou uložena v backendu (opět obvykle v databázi). | ||
| + | |||
| + | Následuje několik příkladů možných řešení. | ||
| + | |||
| + | == Lokální export: jsonEncode/jsonDecode == | ||
| + | |||
| + | === Vlastnosti === | ||
| + | * Formát JSON lze zpracovávat i v dalších aplikacích – je vhodný pro výměnu dat mezi aplikacemi a je textový. | ||
| + | * Jednoduše lze uložit seznam objektů. Složitější vnořované struktury objektů je třeba ručně převádět. | ||
| + | * Není vhodné pro větší objem dat – převod na text může zvětšit objem dat. | ||
| + | * Vhodné zejména pro textová data: texty, celá čísla, logické hodnoty. Méně vhodné pro desetinná čísla, obrázky, ... z důvodu nutné konverze na text. | ||
| + | * Formát JSON neukládá datové typy. | ||
| + | * Výsledek je uložen lokálně – převod z mobilní aplikace na desktop apod. je třeba řešit ručně. | ||
| + | |||
| + | === Postup zápisu === | ||
| + | # Nalezení umístění souboru: | ||
| + | #* Využij balíček <code>path_provider</code> a metodu <code>getApplicationDocumentsDirectory()</code>. | ||
| + | #* Pro zápis do souboru použij třídu <code>File</code> a metodu <code>writeAsString</code>. | ||
| + | # Převod dat na JSON | ||
| + | #* Využij balíček <code>dart:convert</code>. | ||
| + | #* Pro parsování JSON využij metodu <code>jsonDecode(list)</code> – výsledkem bude textová reprezentace objektu ve formátu JSON. | ||
| + | |||
| + | === Postup čtení === | ||
| + | # Nalezení umístění souboru: | ||
| + | #* Využij balíček <code>path_provider</code> a metodu <code>getApplicationDocumentsDirectory()</code>. | ||
| + | #* Pro čtení souboru použij třídu <code>File</code> a metodu <code>readAsString</code>. | ||
| + | # Převod dat na JSON | ||
| + | #* Využij balíček <code>dart:convert</code>. | ||
| + | #* Pro ukládání využij metodu <code>jsonEncode(list)</code> – výsledkem bude textová reprezentace objektu ve formátu JSON. | ||
| + | |||
| + | === Ukázka použití v aplikaci === | ||
| + | import 'dart:io'; | ||
| + | import 'package:flutter/material.dart'; | ||
| + | import 'package:path_provider/path_provider.dart'; | ||
| + | import 'dart:convert'; | ||
| + | |||
| + | void main() { | ||
| + | runApp(const MyApp()); | ||
| + | } | ||
| + | |||
| + | class MyApp extends StatelessWidget { | ||
| + | const MyApp({super.key}); | ||
| + | |||
| + | @override | ||
| + | Widget build(BuildContext context) { | ||
| + | return MaterialApp( | ||
| + | title: 'Úložiště Demo', | ||
| + | home: HomePage('''storage: FileStorage()'''), | ||
| + | ); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | class Zaznam { | ||
| + | final String jmeno; | ||
| + | final int pocet; | ||
| + | |||
| + | const Zaznam({ required this.jmeno, required this.pocet, }); | ||
| + | |||
| + | // Převod do JSON | ||
| + | '''Map<String, dynamic> toJson() => {''' | ||
| + | 'jmeno': jmeno, | ||
| + | 'pocet': pocet, | ||
| + | }; | ||
| + | |||
| + | // Obnov z JSON | ||
| + | '''factory Zaznam.fromJson(Map<String, dynamic> json) {''' | ||
| + | return Zaznam( | ||
| + | jmeno: (json['jmeno']), | ||
| + | pocet: json['pocet'] as int, | ||
| + | ); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | /// Práce se soubory | ||
| + | '''class FileStorage {''' | ||
| + | '''Future<String> get _localPath''' async { | ||
| + | final directory = await getApplicationDocumentsDirectory(); | ||
| + | return directory.path; | ||
| + | } | ||
| + | |||
| + | '''Future<File> get _localFile''' async { | ||
| + | final path = await _localPath; | ||
| + | return File('$path/data.txt'); | ||
| + | } | ||
| + | |||
| + | '''Future<String> readFile()''' async { | ||
| + | final file = await _localFile; | ||
| + | return file.readAsString(); | ||
| + | } | ||
| + | |||
| + | '''Future<void> writeFile(String content)''' async { | ||
| + | final file = await _localFile; | ||
| + | await file.writeAsString(content); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | /// Stav aplikace včetně zápisu do souboru | ||
| + | class HomePage extends StatefulWidget { | ||
| + | final FileStorage storage; | ||
| + | const HomePage('''{required this.storage}'''); | ||
| + | @override | ||
| + | State<HomePage> createState() => _HomePageState(); | ||
| + | } | ||
| + | |||
| + | class _HomePageState extends State<HomePage> { | ||
| + | List<Zaznam> _seznam = []; | ||
| + | |||
| + | @override | ||
| + | void initState() { | ||
| + | super.initState(); | ||
| + | '''_loadData();''' // Načtení dat při startu | ||
| + | } | ||
| + | |||
| + | '''Future<void> _loadData() async {''' | ||
| + | try { | ||
| + | final jsonString = await widget.storage.readFile(); | ||
| + | final List<dynamic> decoded = jsonDecode(jsonString); | ||
| + | setState(() { | ||
| + | _seznam = decoded | ||
| + | .map((item) => Zaznam.fromJson(item as Map<String, dynamic>)) | ||
| + | .toList(); | ||
| + | }); | ||
| + | } catch (e) { | ||
| + | TODO: Zobraz chybové hlášení vhodným způsobem. | ||
| + | } | ||
| + | } | ||
| + | |||
| + | '''Future<void> _saveData() async {''' | ||
| + | final jsonString = jsonEncode( | ||
| + | _seznam.map((z) => z.toJson()).toList() | ||
| + | ); | ||
| + | await widget.storage.writeFile(jsonString); | ||
| + | } | ||
| + | |||
| + | void _addRecord() { | ||
| + | setState(() { | ||
| + | _seznam.add(Zaznam( | ||
| + | jmeno: 'Josef', | ||
| + | pocet: 1000, | ||
| + | )); | ||
| + | }); | ||
| + | '''_saveData();''' | ||
| + | } | ||
| + | |||
| + | @override | ||
| + | Widget build(BuildContext context) { | ||
| + | return Scaffold( | ||
| + | // ... vytvoř GUI | ||
| + | ); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | === Tip === | ||
| + | * Pro větší objemy dat či komplexnější data lze pro export do formátu JSON využít balíček <code>json_serializable</code>. | ||
| + | |||
| + | === Zdroje === | ||
| + | * [https://hatchjs.com/list-to-json-flutter/ HatchJS.com > How to Convert a List to JSON in Flutter] | ||
| + | * [https://docs.flutter.dev/data-and-backend/serialization/json Flutter Docs > JSON and serialization] | ||
| + | * [https://docs.flutter.dev/cookbook/persistence/reading-writing-files Flutter Docs > Read and write files] | ||
| + | |||
| + | |||
| + | == Lokální databáze: Hive == | ||
| + | |||
| + | === Zdroje === | ||
| + | * [https://medium.com/@ChanakaDev/hive-vs-shared-preferences-10353068a8a6 Medium.com: ChanakaDev > Hive vs. Shared Preferences] | ||
| + | |||
| + | == Google Firestore == | ||
| + | |||
| + | == Vlastní backend: ServerPod == | ||
Verze z 22. 2. 2026, 01:04
Pro trvalé uložení dat i po vypnutí aplikace můžeme data uložit:
- na lokální disk konkrétního zařízení
- do síťového úložiště (databáze, cloudové úložiště)
- můžeme rozdělit aplikaci na frontend a backend, kde data budou uložena v backendu (opět obvykle v databázi).
Následuje několik příkladů možných řešení.
Obsah |
Lokální export: jsonEncode/jsonDecode
Vlastnosti
- Formát JSON lze zpracovávat i v dalších aplikacích – je vhodný pro výměnu dat mezi aplikacemi a je textový.
- Jednoduše lze uložit seznam objektů. Složitější vnořované struktury objektů je třeba ručně převádět.
- Není vhodné pro větší objem dat – převod na text může zvětšit objem dat.
- Vhodné zejména pro textová data: texty, celá čísla, logické hodnoty. Méně vhodné pro desetinná čísla, obrázky, ... z důvodu nutné konverze na text.
- Formát JSON neukládá datové typy.
- Výsledek je uložen lokálně – převod z mobilní aplikace na desktop apod. je třeba řešit ručně.
Postup zápisu
- Nalezení umístění souboru:
- Využij balíček
path_providera metodugetApplicationDocumentsDirectory(). - Pro zápis do souboru použij třídu
Filea metoduwriteAsString.
- Využij balíček
- Převod dat na JSON
- Využij balíček
dart:convert. - Pro parsování JSON využij metodu
jsonDecode(list)– výsledkem bude textová reprezentace objektu ve formátu JSON.
- Využij balíček
Postup čtení
- Nalezení umístění souboru:
- Využij balíček
path_providera metodugetApplicationDocumentsDirectory(). - Pro čtení souboru použij třídu
Filea metodureadAsString.
- Využij balíček
- Převod dat na JSON
- Využij balíček
dart:convert. - Pro ukládání využij metodu
jsonEncode(list)– výsledkem bude textová reprezentace objektu ve formátu JSON.
- Využij balíček
Ukázka použití v aplikaci
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:convert';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Úložiště Demo',
home: HomePage(storage: FileStorage()),
);
}
}
class Zaznam {
final String jmeno;
final int pocet;
const Zaznam({ required this.jmeno, required this.pocet, });
// Převod do JSON
Map<String, dynamic> toJson() => {
'jmeno': jmeno,
'pocet': pocet,
};
// Obnov z JSON
factory Zaznam.fromJson(Map<String, dynamic> json) {
return Zaznam(
jmeno: (json['jmeno']),
pocet: json['pocet'] as int,
);
}
}
/// Práce se soubory
class FileStorage {
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> get _localFile async {
final path = await _localPath;
return File('$path/data.txt');
}
Future<String> readFile() async {
final file = await _localFile;
return file.readAsString();
}
Future<void> writeFile(String content) async {
final file = await _localFile;
await file.writeAsString(content);
}
}
/// Stav aplikace včetně zápisu do souboru
class HomePage extends StatefulWidget {
final FileStorage storage;
const HomePage({required this.storage});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
List<Zaznam> _seznam = [];
@override
void initState() {
super.initState();
_loadData(); // Načtení dat při startu
}
Future<void> _loadData() async {
try {
final jsonString = await widget.storage.readFile();
final List<dynamic> decoded = jsonDecode(jsonString);
setState(() {
_seznam = decoded
.map((item) => Zaznam.fromJson(item as Map<String, dynamic>))
.toList();
});
} catch (e) {
TODO: Zobraz chybové hlášení vhodným způsobem.
}
}
Future<void> _saveData() async {
final jsonString = jsonEncode(
_seznam.map((z) => z.toJson()).toList()
);
await widget.storage.writeFile(jsonString);
}
void _addRecord() {
setState(() {
_seznam.add(Zaznam(
jmeno: 'Josef',
pocet: 1000,
));
});
_saveData();
}
@override
Widget build(BuildContext context) {
return Scaffold(
// ... vytvoř GUI
);
}
}
Tip
- Pro větší objemy dat či komplexnější data lze pro export do formátu JSON využít balíček
json_serializable.
Zdroje
- HatchJS.com > How to Convert a List to JSON in Flutter
- Flutter Docs > JSON and serialization
- Flutter Docs > Read and write files