Flutter:SQFlite数据库在使用Android上的交易时被锁定

发布于 2025-01-21 01:27:10 字数 5487 浏览 0 评论 0原文

我有一个本机Android应用程序,该应用程序每50ms通过EventChannel将MAP()数据发送到嵌入式的颤动模块,然后颤动模块将接收到的数据添加到数据库中(Flutter模块没有UI)。

在Android活动中,按下按钮将在一分钟内每5ms每5ms发送数据。

Android活动

public class MainActivity extends FlutterActivity implements View.OnClickListener {
    private static final String ENGINE_ID = "engine_id";
    private static final String CHANNEL_EVENT = "com.example.eventchannel";
    private FlutterEngine flutterEngine;
    private EventChannel eventChannel;
    private EventChannel.EventSink eventSink;

    private Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        flutterEngine = new FlutterEngine(this);
        flutterEngine.getDartExecutor().executeDartEntrypoint(DartExecutor.DartEntrypoint.createDefault());
        FlutterEngineCache.getInstance().put(ENGINE_ID, flutterEngine);

        eventChannel = new EventChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL_EVENT);
        eventChannel.setStreamHandler(new EventChannel.StreamHandler() {
            @Override
            public void onListen(Object arguments, EventChannel.EventSink events) {
                eventSink = events;
            }

            @Override
            public void onCancel(Object arguments) {
                eventSink = null;
            }
        });

        button = findViewById(R.id.btn_send);
        button.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        if (view.getId() == R.id.btn_send){
            Handler handler = new Handler(Looper.getMainLooper());
            handler.post(() -> {
                int i = 0;
                MapData mapData = new MapData();
                while (i < 1200){
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    if (eventSink != null){
                        eventSink.success(mapData.createMap());
                    }
                    i++;
                }
            });
        }
    }
}


public class MapData {
    public Map<String, Object> createMap(){
        return new HashMap<String, Object>(){
            {
                put("name", "aaaaaa");
                put("age", "aaaaaa");
                put("gender", "aaaaaa");
                put("birthday", "aaaaaa");
                put("phone", "aaaaaa");
                put("address", "aaaaaa");
            }
        };
    }
}

和Flutter模块插入接收到数据库的数据。

pubspec.yaml

dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^1.0.2
  sqflite: ^2.0.2
  path_provider: ^2.0.9
  synchronized: ^3.0.0+2

main.dart

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  DatabaseHelper databaseHelper = DatabaseHelper.instance;
  FlutterEventChannel.instance.configureChannel(databaseHelper);
}

数据库助手类

class DatabaseHelper {
  DatabaseHelper._privateConstructor();
  static final DatabaseHelper instance = DatabaseHelper._privateConstructor();

  static Database? _database;
  final _dbLock = Lock();

  Future<Database> get database async {
    if (_database != null) {
      return _database!;
    } else {
      await _dbLock.synchronized(() async {
        _database ??= await _initDatabase();
      });
      return _database!;
    }
  }

  _initDatabase() async {
    Directory documentDirectory = await getApplicationDocumentsDirectory();
    String path = join(documentDirectory.path, 'sample');

    return await openDatabase(path, version: 1, onCreate: _onCreate);
  }

  Future _onCreate(Database db, int version) async {
    await db.execute('''
    CREATE TABLE ${DbDefines.tripTable} (
    $'_id' INTEGER PRIMARY KEY,
    $'name' TEXT NOT NULL,
    $'age' TEXT,
    $'gender' TEXT,
    $'birthday' TEXT,
    $'phone' TEXT,
    $'address' TEXT
    )
    ''');
  }

  Future<void> insert(String table, Map<String, dynamic> row) async {
    Database db = await instance.database;
    await db.transaction((txn) async {
      await txn.insert(table, row);
    });
  }
}

EventChannel类

class FlutterEventChannel {
  late DatabaseHelper databaseHelper;
  static const channelName = 'com.example.eventchannel';
  late EventChannel _eventChannel;
  late StreamSubscription _streamSubscription;

  static final FlutterEventChannel instance = FlutterEventChannel._init();
  FlutterEventChannel._init();

  void configureChannel(DatabaseHelper databaseHelper) {
    this.databaseHelper = databaseHelper;

    _eventChannel = const EventChannel(channelName);
    _streamSubscription = _eventChannel.receiveBroadcastStream().listen(
      (event) {
      databaseHelper.insert(
          'sample', Map<String, dynamic>.from(event));
      },
      onError: (error) {}, cancelOnError: true);
  }
}

按下按钮一次,然后将变速箱成功,但是第二次中间发生了错误。

I/flutter: Warning database has been locked for 0:00:10.000000. Make sure you always use the transaction object for database operations during a transaction

现在我很困惑,因为我找不到任何解决方案... 任何帮助将不胜感激!

I have native Android application which send Map() data to embedded flutter module every 50ms through EventChannel, and flutter module add received data to Database (flutter module has no UI).

In android activity, pressing a button will send the data to the module every 5ms in a minute.

Android Activity

public class MainActivity extends FlutterActivity implements View.OnClickListener {
    private static final String ENGINE_ID = "engine_id";
    private static final String CHANNEL_EVENT = "com.example.eventchannel";
    private FlutterEngine flutterEngine;
    private EventChannel eventChannel;
    private EventChannel.EventSink eventSink;

    private Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        flutterEngine = new FlutterEngine(this);
        flutterEngine.getDartExecutor().executeDartEntrypoint(DartExecutor.DartEntrypoint.createDefault());
        FlutterEngineCache.getInstance().put(ENGINE_ID, flutterEngine);

        eventChannel = new EventChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL_EVENT);
        eventChannel.setStreamHandler(new EventChannel.StreamHandler() {
            @Override
            public void onListen(Object arguments, EventChannel.EventSink events) {
                eventSink = events;
            }

            @Override
            public void onCancel(Object arguments) {
                eventSink = null;
            }
        });

        button = findViewById(R.id.btn_send);
        button.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        if (view.getId() == R.id.btn_send){
            Handler handler = new Handler(Looper.getMainLooper());
            handler.post(() -> {
                int i = 0;
                MapData mapData = new MapData();
                while (i < 1200){
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    if (eventSink != null){
                        eventSink.success(mapData.createMap());
                    }
                    i++;
                }
            });
        }
    }
}


public class MapData {
    public Map<String, Object> createMap(){
        return new HashMap<String, Object>(){
            {
                put("name", "aaaaaa");
                put("age", "aaaaaa");
                put("gender", "aaaaaa");
                put("birthday", "aaaaaa");
                put("phone", "aaaaaa");
                put("address", "aaaaaa");
            }
        };
    }
}

And flutter module insert received data to Database.

pubspec.yaml

dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^1.0.2
  sqflite: ^2.0.2
  path_provider: ^2.0.9
  synchronized: ^3.0.0+2

main.dart

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  DatabaseHelper databaseHelper = DatabaseHelper.instance;
  FlutterEventChannel.instance.configureChannel(databaseHelper);
}

Database Helper Class

class DatabaseHelper {
  DatabaseHelper._privateConstructor();
  static final DatabaseHelper instance = DatabaseHelper._privateConstructor();

  static Database? _database;
  final _dbLock = Lock();

  Future<Database> get database async {
    if (_database != null) {
      return _database!;
    } else {
      await _dbLock.synchronized(() async {
        _database ??= await _initDatabase();
      });
      return _database!;
    }
  }

  _initDatabase() async {
    Directory documentDirectory = await getApplicationDocumentsDirectory();
    String path = join(documentDirectory.path, 'sample');

    return await openDatabase(path, version: 1, onCreate: _onCreate);
  }

  Future _onCreate(Database db, int version) async {
    await db.execute('''
    CREATE TABLE ${DbDefines.tripTable} (
    

EventChannel Class

class FlutterEventChannel {
  late DatabaseHelper databaseHelper;
  static const channelName = 'com.example.eventchannel';
  late EventChannel _eventChannel;
  late StreamSubscription _streamSubscription;

  static final FlutterEventChannel instance = FlutterEventChannel._init();
  FlutterEventChannel._init();

  void configureChannel(DatabaseHelper databaseHelper) {
    this.databaseHelper = databaseHelper;

    _eventChannel = const EventChannel(channelName);
    _streamSubscription = _eventChannel.receiveBroadcastStream().listen(
      (event) {
      databaseHelper.insert(
          'sample', Map<String, dynamic>.from(event));
      },
      onError: (error) {}, cancelOnError: true);
  }
}

Then pressing the button once and the transmission is successful, but an error occurs in the middle of the second time.

I/flutter: Warning database has been locked for 0:00:10.000000. Make sure you always use the transaction object for database operations during a transaction

Now I'm confused because I can't find any solution...
Any help would be appreciated!

_id' INTEGER PRIMARY KEY,

EventChannel Class


Then pressing the button once and the transmission is successful, but an error occurs in the middle of the second time.


Now I'm confused because I can't find any solution...
Any help would be appreciated!

name' TEXT NOT NULL,

EventChannel Class


Then pressing the button once and the transmission is successful, but an error occurs in the middle of the second time.


Now I'm confused because I can't find any solution...
Any help would be appreciated!

age' TEXT,

EventChannel Class


Then pressing the button once and the transmission is successful, but an error occurs in the middle of the second time.


Now I'm confused because I can't find any solution...
Any help would be appreciated!

gender' TEXT,

EventChannel Class


Then pressing the button once and the transmission is successful, but an error occurs in the middle of the second time.


Now I'm confused because I can't find any solution...
Any help would be appreciated!

birthday' TEXT,

EventChannel Class


Then pressing the button once and the transmission is successful, but an error occurs in the middle of the second time.


Now I'm confused because I can't find any solution...
Any help would be appreciated!

phone' TEXT,

EventChannel Class


Then pressing the button once and the transmission is successful, but an error occurs in the middle of the second time.


Now I'm confused because I can't find any solution...
Any help would be appreciated!

address' TEXT ) '''); } Future<void> insert(String table, Map<String, dynamic> row) async { Database db = await instance.database; await db.transaction((txn) async { await txn.insert(table, row); }); } }

EventChannel Class

Then pressing the button once and the transmission is successful, but an error occurs in the middle of the second time.

Now I'm confused because I can't find any solution...
Any help would be appreciated!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

饮惑 2025-01-28 01:27:10

我修复了 java 代码如下并且它有效。

Handler handler = new Handler(Looper.getMainLooper());
Runnable runnable = new Runnable() {
    @Override
    public void run() {
        if (eventSink != null){
            eventSink.success(new MapData().createMap());
            handler.postDelayed(this, 50);
        }
    }
};
handler.post(runnable);

I fixed java code as below and it worked.

Handler handler = new Handler(Looper.getMainLooper());
Runnable runnable = new Runnable() {
    @Override
    public void run() {
        if (eventSink != null){
            eventSink.success(new MapData().createMap());
            handler.postDelayed(this, 50);
        }
    }
};
handler.post(runnable);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文