flutter:通过在安卓系统上使用事务,sqflite数据库被锁定



我有一个原生的Android应用程序,它通过EventChannel每50ms向嵌入式flutter模块发送Map((数据,flutter模块将接收到的数据添加到数据库中(flutter模块没有UI(。

在android活动中,按下一个按钮将在一分钟内每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");
}
};
}
}

颤振模块将接收到的数据插入数据库。

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

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

我修复了下面的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);

最新更新