dart 插入sqlite flutter而不冻结接口

f3temu5u  于 5个月前  发布在  SQLite
关注(0)|答案(2)|浏览(82)

我尝试使用flutter在sqlite内存数据库中插入大量行(大约12k或更多)。
我从API获取数据,并使用计算函数来处理来自JSON的数据。现在我需要将这些数据添加到内存中的数据库中,为了做到这一点,我使用了带有批处理的事务。

batchInsertEventSong(List<EventSong> rows) async {
   Database db = await instance.database;
   db.transaction((txn) async {
      Batch batch = txn.batch();
      for (var song in rows) {
         Map<String, dynamic> row = {
           DatabaseHelper.columnIdSong: song.id,
           DatabaseHelper.columnTitle: song.title,
           DatabaseHelper.columnInterpreter: song.interpreter
         };
         batch.insert(table, row);
       }
      batch.commit();
   }
}

字符串
但是这个函数在插入过程中阻塞了我的UI,我也试过使用compute,但是我不能传递类db或类batch。我还没有弄清楚如何在另一个线程中执行这个过程或者(因为我不能使用isolates)执行而不阻塞我的UI。
有什么建议吗?

j8ag8udp

j8ag8udp1#

更新2020 - 05 - 15

这将不起作用,请参阅:

注意:完整代码在最后提供

x1c 0d1x的数据

第一步:将方法设为静态并设为void

static batchInsertEventSong(List<EventSong> rows) {
    Database db = await instance.database;
    db.transaction((txn) async {
        Batch batch = txn.batch();
        for (var song in rows) {
            Map<String, dynamic> row = {
            DatabaseHelper.columnIdSong: song.id,
            DatabaseHelper.columnTitle: song.title,
            DatabaseHelper.columnInterpreter: song.interpreter
            };
            batch.insert(table, row);
        }
        batch.commit();
    }
  }

字符串

第二步:创建新方法(通常情况下,但不是必须的,为相同的名称添加Async)

Future batchInsertEventSongAsync(List<EventSong> rows) {

  }

第三步:使用方法static调用compute并返回

return compute(batchInsertEventSong, rows);

Step [1,2,3] code review

Future batchInsertEventSongAsync(List<EventSong> rows) {
    return compute(_batchInsertEventSong, rows);
  }

  static _batchInsertEventSong(List<EventSong> rows) {
    Database db = await instance.database;
    db.transaction((txn) async {
        Batch batch = txn.batch();
        for (var song in rows) {
            Map<String, dynamic> row = {
            DatabaseHelper.columnIdSong: song.id,
            DatabaseHelper.columnTitle: song.title,
            DatabaseHelper.columnInterpreter: song.interpreter
            };
            batch.insert(table, row);
        }
        batch.commit();
    }
  }

完整代码

import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(body: MyHomePage(title: 'Flutter Demo Home Page')),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            FlatButton.icon(
              icon: Icon(Icons.backup),
              label: Text("Long Opreation"),
              onPressed: () async {
                var rows = await RsetApi.getRawsAsync();
                await Database._saveRaws(rows);
              },
            ),
            FlatButton.icon(
              icon: Icon(Icons.backup),
              label: Text("Short Opreation"),
              onPressed: () {
                Scaffold.of(context).hideCurrentSnackBar();
                Scaffold.of(context).showSnackBar(new SnackBar(
                  content: new Text(DateTime.now().toIso8601String()),
                ));
              },
            ),
          ],
        ),
      ),
    );
  }
}

class RsetApi {
  static Future<List<EventSong>> getRawsAsync() {
    return compute(_getRaws, null);
  }

  static List<EventSong> _getRaws(pram1) {
    var rows = List<EventSong>();
    for (var i = 1; i < 12000; i++) {
      rows.add(EventSong(i));
      print("fetching raws " + (i / 12000).toString());
    }
    return rows;
  }
}

class Database {
  static Future saveRawsAsync(List<EventSong> rows) {
    return compute(_saveRaws, rows);
  }

  static _saveRaws(List<EventSong> rows) {
    for (var i = 1; i < rows.length; i++) {
      print("saving raws " + (i / rows.length).toString());
    }
  }
}

class EventSong {
  int id;
  EventSong(this.id);
}

参考:

  • 在后台解析JSON- Flutter

非重要参考:

b4qexyjb

b4qexyjb2#

首先,你应该在主线程中运行你的代码,而不是使用计算。Sqflite已经在自己的线程中运行,隔离支持有点复杂(因为你需要在隔离中打开数据库...)
其次,你应该等待提交(如果你启用了lint unawaited_futures,你实际上应该得到一个警告)。
如果你的for循环持续了2秒,那么无论你做什么,都会冻结UI,所以你应该分成更小的批处理(比如100个)。
这应该是一个可能的解决方案:

await db.transaction((txn) async {
  var batch = txn.batch();

  Future<void> commitBatch() async {
    if (batch.length > 0) {
      await batch.commit();
    }
  }

  // Commit existing and start a new batch
  Future<void> commitBatchAndRestart() async {
    await commitBatch();
    batch = txn.batch();
  }

  for (var song in rows) {
    var row = <String, Object?>{
      DatabaseHelper.columnIdSong: song.id,
      DatabaseHelper.columnTitle: song.title,
      DatabaseHelper.columnInterpreter: song.interpreter
    };
    batch.insert(table, row);
    // Commit every 100 items
    if (batch.length > 100) {
      await commitBatchAndRestart();
    }
  }
  // Commit the remaining items if needed
  await commitBatch();
});

字符串

相关问题