Flutter Isar 在热重启后停止工作

huangapple go评论62阅读模式
英文:

Flutter Isar stops working after hot restart

问题

我昨天开始学习Flutter Isar,我非常喜欢它。我用它创建了一个演示应用,但出现了一些问题。

这个应用有两个部分:原始(包含虚拟数据)和数据库(包含Isar数据库中的数据)。

当在原始部分中对项目进行标记为"starred"时,它会被添加到数据库中,并且图标会更改为"filled_star"。当在原始部分中取消对项目的标记时,期望它会从数据库部分中删除,并且图标会更改为"star_outline"。这一部分正常工作。

然而,当应用程序热重新启动时,我无法取消对项目的标记。请查看下面的GIF:

Flutter Isar 在热重启后停止工作

我尝试降级Isar的版本,但没有成功。

英文:

I started learning flutter isar yesterday and I couldn't love it more. I created a demo app with it and for some reason, it is not working as expected.

The app has two sections: Original(This contain the dummyData) and the Database(this contains data in the isar database).

When an item is starred in the original, it is added in the database and the icon is changed to filled_star. When the item is unstarred in the original section, it is expected to be removed from the database section and the icon is expected to change to star_outline. This is works fine.

However, when the app is hot-restarted, I am unable to unstar the items. Check the GIF below.

Flutter Isar 在热重启后停止工作

main.dart

import 'package:flutter/material.dart';
import 'package:isardemo/isar_files/course.dart';
import 'package:isardemo/isar_files/isar.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return ProviderScope(
      child: MaterialApp(
        debugShowCheckedModeBanner: false,
        title: 'Flutter Demo',
        theme: ThemeData(
          brightness: Brightness.dark,
          primarySwatch: Colors.blueGrey,
        ),
        home: const MyHomePage(),
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final dummyData = [
    Course()
      ..title = 'MTH 212'
      ..courseId = '1ab',
    Course()
      ..title = 'STS 432'
      ..courseId = '2bc',
    Course()
      ..title = 'SHS 555'
      ..courseId = '3de',
    Course()
      ..title = 'HMM 999'
      ..courseId = '4fg',
    Course()
      ..title = 'EEE 666'
      ..courseId = '5hi',
  ];
  Future<void> onFavTap(IsarService courseData, Course course) async {
    if (await courseData.isItemDuplicate(course)) {
      await courseData.deleteCourse(course);
      setState(() {});
      debugPrint('${course.courseId} deleted');
    } else {
      await courseData.addCourse(course);
      setState(() {});
      debugPrint('${course.courseId} added');
    }
  }

  final courseData = IsarService();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Isar'),
      ),
      body: ListView(
        padding: const EdgeInsets.all(20),
        children: [
          Center(
            child: FutureBuilder(
              initialData: courseData,
              future: courseData.favoritesCount(),
              builder: (BuildContext context, AsyncSnapshot snapshot) {
                if (snapshot.hasData) {
                  return Text(
                    snapshot.data.toString(),
                    style:
                        const TextStyle(fontSize: 25, color: Colors.lightGreen),
                  );
                } else {
                  return const LinearProgressIndicator();
                }
              },
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: ElevatedButton(
                onPressed: () {
                  courseData.cleanDb();
                  setState(() {});
                },
                child: const Text('Destroy Database')),
          ),
          const Text('Original',
              style: TextStyle(fontSize: 30, color: Colors.green)),
          ListView.separated(
            shrinkWrap: true,
            separatorBuilder: (context, index) => const SizedBox(height: 5),
            itemCount: dummyData.length,
            itemBuilder: (BuildContext context, int index) {
              return ListTile(
                tileColor: Colors.blueGrey,
                title: Text(dummyData[index].title),
                trailing: IconButton(
                    icon: FutureBuilder(
                      // initialData: courseData.isItemDuplicate(dummyData[index]),
                      future: courseData.isItemDuplicate(dummyData[index]),
                      builder: (BuildContext context, AsyncSnapshot snapshot) {
                        if (snapshot.connectionState == ConnectionState.done) {
                          if (snapshot.data) {
                            return const Icon(Icons.star);
                          } else {
                            return const Icon(Icons.star_border_outlined);
                          }
                        }
                        return const Icon(Icons.g_mobiledata,
                            color: Colors.green);
                      },
                    ),
                    onPressed: () => onFavTap(courseData, dummyData[index])),
              );
            },
          ),
          const SizedBox(height: 20),
          const Text(
            'database',
            style: TextStyle(fontSize: 30, color: Colors.green),
          ),
          FutureBuilder(
              future: courseData.getAllCourses(),
              builder: (context, snapshot) {
                if (snapshot.hasData) {
                  return ListView.builder(
                    shrinkWrap: true,
                    itemCount: snapshot.data!.length,
                    itemBuilder: (BuildContext context, int index) {
                      return ListTile(
                        title: Text(snapshot.data![index].title),
                        trailing: InkWell(
                            onTap: () async {
                              await courseData
                                  .deleteCourse(snapshot.data![index]);
                              setState(() {});
                            },
                            child: const Icon(Icons.star)),
                      );
                    },
                  );
                } else {
                  return const Center(
                    child: LinearProgressIndicator(),
                  );
                }
              }),
        ],
      ),
    );
  }
}

course.dart

import 'package:isar/isar.dart';

part 'course.g.dart';

@Collection()
class Course {
  Id id = Isar.autoIncrement;

  late String courseId;

  late String title;

  late bool isFavorite = false; // new property
}

isar.dart

import 'package:path_provider/path_provider.dart';
import 'course.dart';

class IsarService {
  late Future<Isar> _db;

  IsarService() {
    _db = openIsar();
  }

  Future<Isar> openIsar() async {
    if (Isar.instanceNames.isEmpty) {
      final directory = await getApplicationDocumentsDirectory();
      return await Isar.open([CourseSchema],
          inspector: true, directory: directory.path);
    } else {
      return await Future.value(Isar.getInstance());
    }
  }

  Future<void> addCourse(Course course) async {
    final isar = await _db;

    await isar.writeTxn(() async {
      await isar.courses.put(course);
    });
  }

  Future<bool> isItemDuplicate(Course course) async {
    final isar = await _db;
    final count =
        await isar.courses.filter().courseIdContains(course.courseId).count();
    return count > 0;
  }

  Future<List<Course>> getAllCourses() async {
    final isar = await _db;
    return isar.courses.where().findAll();
  }

  Future<void> deleteCourse(Course course) async {
    final isar = await _db;

    await isar.writeTxn(() async {
      await isar.courses.delete(course.id);
    });
  }

  Future<String> favoritesCount() async {
    final isar = await _db;
    final count = await isar.courses.count();
    return count.toString();
  }

  Future<void> cleanDb() async {
    final isar = await _db;
    await isar.writeTxn(() => isar.clear());
  }
}

I tried downgrading the isar version but it didn't work.

答案1

得分: 0

我修复了它!我改用了Course的id而不是自动递增的id。但是Id期望一个整数,所以我不得不使用fastHash将Course的id转换为整数。

了解更多

course.dart

@Collection()
class Course {
  late String id;

  Id get courseId => fastHash(id);

  late String title;
}

int fastHash(String string) {
  var hash = 0xcbf29ce484222325;

  var i = 0;
  while (i < string.length) {
    final codeUnit = string.codeUnitAt(i++);
    hash ^= codeUnit >> 8;
    hash *= 0x100000001b3;
    hash ^= codeUnit & 0xFF;
    hash *= 0x100000001b3;
  }

  return hash;
}
英文:

I fixed it! Instead of auto-incrementing the id, I used the Course's id instead. But Id expects an integer so I had to convert the Course's id into an integer using the fastHash.

Learn more

course.dart

<!-- language: lang-js -->

@Collection()
class Course {
  late String id;

  Id get courseId =&gt; fastHash(id);

  late String title;

}

int fastHash(String string) {
  var hash = 0xcbf29ce484222325;

  var i = 0;
  while (i &lt; string.length) {
    final codeUnit = string.codeUnitAt(i++);
    hash ^= codeUnit &gt;&gt; 8;
    hash *= 0x100000001b3;
    hash ^= codeUnit &amp; 0xFF;
    hash *= 0x100000001b3;
  }

  return hash;
}

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年2月19日 05:44:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/75496576.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定