I need to group all operations of a Hivebd crud get, put, delete and update in one class but when I try this get a error because Hive.openBox() need an await but constructors not allowed async.How I would do that corectely?
My class below.
class HomeListRepository {
var _homelistStore = await Hive.openBox<HomeList>("homelists");
Future insert(String id, HomeList homelist) async {
await _homelistStore.put(id,homelist.toMap());
}
Future update(HomeList homelist) async {
await _homelistStore.put(homelist.id,homelist.toMap());
}
Future delete(HomeList homelist) async {
await _homelistStore.delete(homelist.id);
}
Future<List<HomeList>> getAll() async {
return _homelistStore.values;
}
}
Edit:
I solved this and the final code is:
class HomeListRepository {
Box _homelistStore;
Future<void> insert(String id,HomeList homelist) async {
_homelistStore = await Hive.openBox<HomeList>("homelists");
_homelistStore.put(id,homelist);
}
Future<void> update(HomeList homelist) async {
_homelistStore = await Hive.openBox<HomeList>("homelists");
await _homelistStore.put(homelist.id,homelist);
}
Future<void> delete(HomeList homelist) async {
_homelistStore = await Hive.openBox<HomeList>("homelists");
await _homelistStore.delete(homelist.id);
}
Future<List<HomeList>> readAll() async {
_homelistStore = await Hive.openBox<HomeList>("homelists");
return _homelistStore.values.toList();
}
}
finded on Hive github page:GitHub
Related
I am buiding an app were I want to run a batch operation in firestore and I want to run it in a different isolate. Here is my code for spawning the isolate:
Future<void> _startAnotherIsolate(String mediaUrl) async {
final isolate = await FlutterIsolate.spawn(isolate1,"hello"); // i need to pass 2 more
arguments
Timer(Duration(seconds: 5), () {
print("Pausing Isolate 1");
isolate.pause();
});
Timer(Duration(seconds: 10), () {
print("Resuming Isolate 1");
isolate.resume();
});
Timer(Duration(seconds: 20), () {
print("Killing Isolate 1");
isolate.kill();
});
}
My code for the isolate:
void isolate1(String data1, String data2) async {
await Firebase.initializeApp();
print("changing profile picture: $phone");
Timer.periodic(Duration(seconds: 1), (timer) => print("Timer Running From Isolate 1"));
var db = FirebaseFirestore.instance;
var batch = db.batch();
FirebaseFirestore.instance.collection("posts").doc(phone).collection("userPosts")
.get().then((querySnapshot) {
for (var document in querySnapshot.docs) {
try {
batch.update(document.reference,{'user_image': mediaUrl});
} on FormatException catch (error) {
// If a document ID is unparsable. Example "lRt931gu83iukSSLwyei" is unparsable.
// print("The document ${error.source} could not be parsed.");
return null;
}
}
return batch.commit();
});
}
I have seen This link and this link but they are not helpful
import 'dart:isolate';
class RequiredArgs {
late final SendPort sendPort;
late int id;
RequiredArgs(this.id, this.sendPort);
}
Future<void> main() async {
ReceivePort receivePort = ReceivePort();
RequiredArgs requiredArgs = RequiredArgs(1122, receivePort.sendPort);
Isolate isolate = await Isolate.spawn(download, requiredArgs);
var resp = await receivePort.first;
print(resp);
}
void download(RequiredArgs requiredArgs) {
final SendPort sendPort = requiredArgs.sendPort;
final id = requiredArgs.id;
print(id);
sendPort.send("yes");
}
We pass the value using the RequiredArgs class. Hope my answer helps.
How do you check if an async void method is completed in Dart?
Method 1:
await voidFoo();
print("the above function was completed");
Future<void> voidFoo() async{
await Future.delayed(Duration(seconds:1));
}
Method 2:
Using a boolean variable like this,
bool isCompleted = false;
...
await voidFoo();
Future<void> voidFoo() async{
await Future.delayed(Duration(seconds:1));
isCompleted = true; //assuming isCompleted can be accessed here
}
There are too many methods to do this
i prefer to do this
Future<void> myFunction() async {
await Future.delayed(Duration(seconds: 3)); // your future operation
}
main() async {
await myFunction();
print("finished");
}
You can use dart Completer.
import 'dart:async';
void main() async {
final completer = Completer<String>();
Future<String> getHttpData()async{
return Future.delayed(const Duration(seconds: 1), () => "Future Result");
}
Future<String> asyncQuery()async {
final httpResponse = await getHttpData();
completer.complete(httpResponse);
return completer.future;
}
print('IsCompleted: ${completer.isCompleted}');
await asyncQuery();
print('IsCompleted: ${completer.isCompleted}');
}
Result;
IsCompleted: false
IsCompleted: true
I am using the shared_preferences package. https://pub.dev/packages/shared_preferences/example
In my repository class, for each function, I am doing this to get the instance.
SharedPreferences prefs = await SharedPreferences.getInstance();
class AuthenticationRepository {
Future<dynamic> logIn({required String email, required String password}) async {
SharedPreferences prefs = await SharedPreferences.getInstance(); <--------
....
prefs.clear();
prefs.setString('user', encodedUser);
}
Future<String> logOut() async {
SharedPreferences prefs = await SharedPreferences.getInstance(); <---------
prefs.clear();
if(prefs.containsKey('user')){
return 'failed';
}else{
return 'cleared';
}
}
}
I am just wondering if this is initiating a new sharedPreference object or as the function implies, we are only getting the same instance?
Is there a better way to create the instance once, maybe as a class variable like below?
class AuthenticationRepository {
SharedPreferences prefs = await SharedPreferences.getInstance();
Future<dynamic> logIn({required String email, required String password}) async {
....
this.prefs.clear();
prefs.setString('user', encodedUser);
}
Future<String> logOut() async {
this.prefs.clear();
if(prefs.containsKey('user')){
return 'failed';
}else{
return 'cleared';
}
}
}
Please advice, thanks in advance :)
Yes, you can get the same instance. In the shared_preference.dart file, there is a static value _completer. Here is getInstance() function. You can see the if (_completer == null), and it immediately returns a value when the _completer had been initialized.
static Completer<SharedPreferences>? _completer;
...
static Future<SharedPreferences> getInstance() async {
if (_completer == null) {
final completer = Completer<SharedPreferences>();
try {
final Map<String, Object> preferencesMap =
await _getSharedPreferencesMap();
completer.complete(SharedPreferences._(preferencesMap));
} on Exception catch (e) {
// If there's an error, explicitly return the future with an error.
// then set the completer to null so we can retry.
completer.completeError(e);
final Future<SharedPreferences> sharedPrefsFuture = completer.future;
_completer = null;
return sharedPrefsFuture;
}
_completer = completer;
}
return _completer!.future;
}
I think it is a better way to use the getInstance() function not to create another class.
I´m trying mock the function getExternalStorageDirectory, but alway return the error:
"UnsupportedError (Unsupported operation: Functionality only available on Android)"
I´m using the method setMockMethodCallHandler to mock it, but the erro occurs before the method be called.
test method
test('empty listReportModel', () async {
TestWidgetsFlutterBinding.ensureInitialized();
final directory = await Directory.systemTemp.createTemp();
const MethodChannel channel =
MethodChannel('plugins.flutter.io/path_provider');
channel.setMockMethodCallHandler((MethodCall methodCall) async {
if (methodCall.method == 'getExternalStorageDirectory') {
return directory.path;
}
return ".";
});
when(Modular.get<IDailyGainsController>().listDailyGains())
.thenAnswer((_) => Future.value(listDailyGainsModel));
when(Modular.get<IReportsController>().listReports())
.thenAnswer((_) => Future.value(new List<ReportsModel>()));
var configurationController = Modular.get<IConfigurationController>();
var response = await configurationController.createBackup();
expect(response.filePath, null);
});
method
Future<CreateBackupResponse> createBackup() async {
CreateBackupResponse response = new CreateBackupResponse();
var dailyGains = await exportDailyGainsToCSV();
var reports = await exportReportsToCSV();
final Directory directory = await getApplicationDocumentsDirectory();
final Directory externalDirectory = await getExternalStorageDirectory();
if (dailyGains.filePath != null && reports.filePath != null) {
File dailyGainsFile = File(dailyGains.filePath);
File reportsFile = File(reports.filePath);
var encoder = ZipFileEncoder();
encoder.create(externalDirectory.path + "/" + 'backup.zip');
encoder.addFile(dailyGainsFile);
encoder.addFile(reportsFile);
encoder.close();
await _removeFile(dailyGainsFile.path);
await _removeFile(reportsFile.path);
response.filePath = directory.path + "/" + 'backup.zip';
}
return response;
}
As in pub.dev stated:
path_provider now uses a PlatformInterface, meaning that not all
platforms share the a single PlatformChannel-based implementation.
With that change, tests should be updated to mock PathProviderPlatform
rather than PlatformChannel.
That means somewhere in your test directory you create the following mock class:
import 'package:mockito/mockito.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path_provider_platform_interface/path_provider_platform_interface.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
const String kTemporaryPath = 'temporaryPath';
const String kApplicationSupportPath = 'applicationSupportPath';
const String kDownloadsPath = 'downloadsPath';
const String kLibraryPath = 'libraryPath';
const String kApplicationDocumentsPath = 'applicationDocumentsPath';
const String kExternalCachePath = 'externalCachePath';
const String kExternalStoragePath = 'externalStoragePath';
class MockPathProviderPlatform extends Mock
with MockPlatformInterfaceMixin
implements PathProviderPlatform {
Future<String> getTemporaryPath() async {
return kTemporaryPath;
}
Future<String> getApplicationSupportPath() async {
return kApplicationSupportPath;
}
Future<String> getLibraryPath() async {
return kLibraryPath;
}
Future<String> getApplicationDocumentsPath() async {
return kApplicationDocumentsPath;
}
Future<String> getExternalStoragePath() async {
return kExternalStoragePath;
}
Future<List<String>> getExternalCachePaths() async {
return <String>[kExternalCachePath];
}
Future<List<String>> getExternalStoragePaths({
StorageDirectory type,
}) async {
return <String>[kExternalStoragePath];
}
Future<String> getDownloadsPath() async {
return kDownloadsPath;
}
}
And build your tests the following way:
void main() {
group('PathProvider', () {
TestWidgetsFlutterBinding.ensureInitialized();
setUp(() async {
PathProviderPlatform.instance = MockPathProviderPlatform();
// This is required because we manually register the Linux path provider when on the Linux platform.
// Will be removed when automatic registration of dart plugins is implemented.
// See this issue https://github.com/flutter/flutter/issues/52267 for details
disablePathProviderPlatformOverride = true;
});
test('getTemporaryDirectory', () async {
Directory result = await getTemporaryDirectory();
expect(result.path, kTemporaryPath);
});
}
}
Here you can check out the complete example.
I am developing a simple chat application, and I had to check-end API with specific time intervals.
but in my BLOC logic I used Observable
So how can I change codes to make this stream periodic?
final bloc = ConversationBloc();
class ConversationBloc {
final repository = Repository();
final conversationFetcher = PublishSubject<ConversationModel>();
final conversationFetcherStatus = PublishSubject<MessageModel>();
Observable<ConversationModel> get userConversation =>
conversationFetcher.stream;
dispose() async {
await conversationFetcher.drain();
conversationFetcher.close();
conversationFetcherStatus.close();
}
fetchUserConversation(toUsernameController) async {
ConversationModel conversationModel =
await repository.fetchUserConversation(toUsernameController);
conversationFetcher.sink.add(conversationModel);
}
saveConversation(Data conversation) async {
try {
MessageModel conversationModel =
await repository.saveConversation(conversation);
conversationFetcherStatus.sink.add(conversationModel);
} catch (e) {
conversationFetcherStatus.sink.addError(e);
}
}
fetchUserConversationList(int toUsernameController) async {
ConversationModel conversationModel =
await repository.fetchUserConversationList(toUsernameController);
conversationFetcher.sink.add(conversationModel);
}
}