简体   繁体   English

flutter:通过在 Android 上使用事务,sqflite 数据库被锁定

[英]flutter: sqflite database getting locked though using transaction on Android

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).我有本机 Android 应用程序,它通过 EventChannel 每 50 毫秒将 Map() 数据发送到嵌入式 flutter 模块,flutter 模块将接收到的数据添加到数据库(flutter 模块没有 UI)。

In android activity, pressing a button will send the data to the module every 5ms in a minute.在 android activity 中,按下一个按钮将在一分钟内每 5ms 向模块发送数据。

Android Activity 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");
            }
        };
    }
}

And flutter module insert received data to Database. flutter 模块将收到的数据插入数据库。

pubspec.yaml 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主要.dart

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

Database Helper Class数据库助手 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} (
    $'_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事件通道 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!现在我很困惑,因为我找不到任何解决方案......任何帮助将不胜感激!

I fixed java code as below and it worked.我按如下方式修复了 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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM