1 Востаннє редагувалося flatliner (19.04.2024 13:58:53)

Тема: Хтось тут шарить у Dart/Flutter? Збереження даних у json.

Я оце почав вивчати, вже доволі давно, але схоже, я гальмо і вже не можу вивчити щось складніше за PHP. Спотикаюся на елементарних моментах постійно.

Для навчання вибрав собі задачу - створити простенький todolist. Так от коли додаєш таску воно його зберігає у файл, а коли перезапускаєш - не може перечитати, бо виявляється невірний формат (насилу вдалося з'ясувати, бо дебажить це я теж ще не навчився нормально).

Короче код. Є такий клас:

class Task extends Object {
  final int id;
  String title;

  Task(this.id, this.title);

  Task.fromJson(Map<String, dynamic> json)
    : id = json['id'] as int,
      title = json['title'] as String;

  Map<String, dynamic> toJson() => {
      'id': id,
      'title': title
    };
}

Як це робити я підгледів отут:
https://docs.flutter.dev/data-and-backend/serialization/json#manual-encoding

Ось, клас, що відповідає за збереження даних:

import 'dart:async';
import 'dart:io';
import 'dart:convert';

import 'package:path_provider/path_provider.dart';

import 'package:todolist/task.dart';

class TodoStorage {
  Future<String> get _localPath async {
    final directory = await getApplicationDocumentsDirectory();

    return directory.path;
  }

  Future<File> get _localFile async {
    final path = await _localPath;

    final file = File('$path/todolist/todo.txt');

    if (!(await file.exists())) {
      file.create(recursive: true);
    }

    return file;
  }

  Future<List<Task>> getTodo() async {
    List<Task> tasks = [];

    try {
      final file = await _localFile;
      final contents = await file.readAsString();

      LineSplitter ls = const LineSplitter();
      List<String> jsons = ls.convert(contents);

      tasks = jsons.map((el) {
        var taskMap = jsonDecode(el);
        return Task.fromJson(taskMap);
      }).toList();
    } catch (e) {
      // @TODO: show error message
      print(e);
    }

    return tasks;
  }

  Future<File> putTodo(List<Task> todo) async {
    final file = await _localFile;

    List<String> jsons = todo.map((el) {
      return el.toJson().toString();
    }).toList();

    try {
      file.writeAsString(jsons.join('\n'));
    } catch (e) {
      // @TODO: show error message
      return file;
    }

    return file;
  }
}

По суті, воно працює, але проблема в тому, що оте putTodo() зберігає якийсь неправильний json без лапок. Коли я пофіксив файл вручну, додавши лапки, воно запрацювало, тобто getTodo() повернуло дані без виключення.

Як його змусити зберігати json з лапками?

Ось приклад, як воно зберігає:

{id: 1713375875, title: Test01}
{id: 1713375893, title: Happiness!!!}
{id: 1713526370, title: Next}

А ось, як мало би бути, щоб потім могло прочитати:

{"id": 1713375875, "title": "Test01"}
{"id": 1713375893, "title": "Happiness!!!"}
{"id": 1713526370, "title": "Next"}
Подякували: leofun011

2

Re: Хтось тут шарить у Dart/Flutter? Збереження даних у json.

Ну, раз поки що ніхто не обізвався, буду я вважатися головним, хто в цьому шарить ;)
Коротше, я розібрався сам.

У першому класі Task оця шняга:

Map<String, dynamic> toJson() => {
      'id': id,
      'title': title
    };

не повинна викликатися напряму, а потрібна лише для того, щоб з цим класом міг правильно працювати jsonEncode().

Відповідно, у класі TodoStorage у методі putTodo() оцей шматочок:

return el.toJson().toString();

має бути переписаний як

return jsonEncode(el);

От і все!

Подякували: leofun011