Hive won't write to Box inside Audio Player Listener - flutter

I am developing a PodCast app. I want to save every index of a correlated episode that the user have started listening to, into a box in Hive.
So I am using a listener to catch the current/latest index of the players positionStream( I need the position as well ).
But Hive doesn't write to the box inside the listener. The same code is working when wrapped inside a button with an onTap event, and tapped of course. Why I that? Is there any way around it?
No error message is thrown what so ever...
Below is minimal reproduction example which doesn't write to the boxBools.
void main(){
WidgetsFlutterBinding.ensureInitialized();
final appDocDir = await getApplicationDocumentsDirectory();
await Hive.initFlutter(appDocDir.path);
await Hive.openBox<List<bool>>("Bools");
}
void listenToChanges() async {
final boxBools = await Hive.box<List<bool>>("Bools");
int? _index;
List<bool> randomList = [false,false,false,false,false,false,false,false,false,false];
_player.positionStream.listen((event) {
if (event.inSeconds != 0) {
_index = _player.currentIndex;
randomList[_index] = true;
print("RandomList => $randomList");
boxBools.put("randomPod", randomList);
}
});
}
The print statement "RandomList => $randomList" prints the correct values, but randomList doesn't get written to the boxBools.

Related

How make async api calls inside loop and complete loop with all data from api call. Due to async I'm losing that part of data

I'm reading json List from device memory and want to perform some operations on it's components.
When I load that list I start loop where I check each item of that list.
While in loop I add each item to new List to have updated List after loop ends so I could save it on device memory.
If some conditions are true then I use future async http call to get updated data
then theoretically I update that item of the List while staying inside loop. And thus after loop ends I must have updated Json List ready to be saved on device memory.
Problem is that While I http call inside loop, the answer delays, loop ends and new Json List is being constructed and saved on memory without the component that was supposed to be updated.
Is there any way to force wait the whole loop or something else ?
Here is the code
Future<void> readStoredData() async {
try {
final prefs = await SharedPreferences.getInstance();
_rawJsonListE = prefs.getStringList('storedData');
List<String> rawJsonListNEW = [];
bool _isNeedUpdate = false;
_rawJsonListE!.forEach((item) async {
if (someCondition with item Data) {
_isNeedUpdate = true;
await makeHttpCallFutureAwaitFunction(item).then((_) {
rawJsonListNEW.add(updatedItem);
});
} else {
rawJsonListNEW.add(item);
}
});
if (_isNeedUpdate) prefs.setStringList('storedData', rawJsonListNEW);
}
notifyListeners();
} catch (error) {
print('Error : ${error}');
throw error;
}
You can separate the refreshing data part to another function.
// Just need to check _rawJsonListE is empty or not
_isNeedUpdate = _rawJsonListE.isNotEmpty();
Create a new function.
Future<List<String>> checkDataAndRefresh(List<String> _rawJsonListE) async {
List<String> rawJsonListNEW = [];
_rawJsonListE!.forEach((item) async {
if (someCondition with item Data) {
final String newString = await makeHttpCallFutureAwaitFunction(item);
rawJsonListNEW.add(newString);
} else {
rawJsonListNEW.add(item);
}
});
return rawJsonListNEW;
}
And if _isNeedUpdate is true, do work.
if (_isNeedUpdate)
final List<String> newData = await checkDataAndRefresh(_rawJsonListE);
prefs.setStringList('storedData', newData);

Flutter check if stream is empty before close end

I'm using BehaviorSubject as a Stream controller.
In one of my functions, I want to .add more items only in case the Stream is empty of events.
#override
Future<void> fetchNextOverviewPolls() async {
if (await _pollOverviewStreamController.isEmpty) return; // My Problem
final lastDoc = await _pollOverviewStreamController.last;
final querySnapshot =
await _overviewPollsRef.startAfterDocument(lastDoc).limit(5).get();
for (final doc in querySnapshot.docs) {
_pollOverviewStreamController.add(doc);
}
}
The isEmpty property returns a value in case the Stream ends. I want to check it when the Stream is still running.
How do I do that?
BehaviorSubject supports hasValue.
In the above case, use this line instead:
if (_pollOverviewStreamController.hasValue) return;

how do i force Flutter to run all the lines inside the function?

I have a this function that I need to run during initstate() in its entirety before building the widget. I have used this kind of code before in some parts of my app and it works there, but in this case, flutter jumps out before executing .then , goes to build the widget tree, and then returns back to the function but skips the remaining lines. I'm confused where I should properly put async-awaits to force it to finish the block. Also, can I ask where I can read an explanation of the proper flow of execution for flutter so that I can understand it more?
Future <bool> checkVendorStatus (buyerId) async {
var _result;
var vendorDocRef = await buyersInfoColl.doc(buyerId)
.collection("vendorsCalled")
.doc(auth.currentUser!.uid)
.get()
.then((value) async {
return await value.exists ? _result = true : _result = false;
}
);
return _result;
await is meant to interrupt the process flow until the async method has finished. then however does not interrupt the process flow (meaning the next instructions will be executed) but enables you to run code when the async method is finished.
you can write your code like this-
Future <bool> checkVendorStatus (buyerId) async {
var _result;
var vendorDocRef = await buyersInfoColl.doc(buyerId)
.collection("vendorsCalled")
.doc(auth.currentUser!.uid)
.get();
vendorDocRef.exists ? _result = true : _result = false;
return _result;
}

flutter audio_service and just_audio not working on ios

I have list of song on song screen. If user click the one item in the list, I call the loadFirstPlaylist() to load the list of songs(all song in album) into queue and then skip the queue and play. It is working on android but I got following error on iOS.
GitHub Sources Code
[NowPlaying] [MRNowPlaying] Ignoring setPlaybackState because application does not contain entitlement com.apple.mediaremote.set-playback-state for platform
Future<void> loadFirstPlayList(List<MediaItem> playlist, int index) async {
await emptyPlaylist();
if (playlist.isNotEmpty) {
await _audioHandler.addQueueItems(playlist);
await _audioHandler.skipToQueueItem(index);
await _audioHandler.play();
}
}
Audio Handler Method
#override
Future<void> addQueueItems(List<MediaItem> mediaItems) async {
// manage Just Audio
final audioSource = mediaItems.map(_createAudioSource);
_playlist.addAll(audioSource.toList());
// notify system
final newQueue = queue.value..addAll(mediaItems);
queue.add(newQueue);
}
#override
Future<void> skipToQueueItem(int index) async {
if (index < 0 || index >= queue.value.length) return;
if (_player.shuffleModeEnabled) {
index = _player.shuffleIndices![index];
}
_player.seek(Duration.zero, index: index);
}
#override
Future<void> play() => _player.play();
I do not know if you have figured it out or not already. However, I had the same issue when trying to load an empty playlist. I was following this example, which includes a _loadEmptyPlaylist method. However, when I implemented it this caused the player to fail silently. It now seems to be working by not calling loadAudioSource on an empty audio sequence.

Flutter - How to add and retrieve data to/from hive?

I know it sounds simple and I went through the example given in the documentation. Yet somehow I am unable to get it right.
This is what I have:
void main() async {
await Hive.initFlutter();
//Hive.openBox('workoutBox');
runApp(const MyApp());
}
...
Next Screen:
var box;
...
Trying to add to the box
Future<void> _save() async{
// save doc id somewhere
final Id = doc.id;
//box = await Hive.openBox('workoutBox');
box.put("Id", Id);
}
Trying to retrieve in another function:
var someId = box.get("Id");
Current error: get was called on null
My confusion is, where/how do you declare, open and retrieve from the box in this situation?
It seems you are forgetting to initialize a Box param and assign the value returned by the openBox function to it.
After Hive initialization you should have something like this:
Box<myValue> boxValue = await Hive.openBox("myKey");
Important: the retrieval method will dependend based on what you need to do and, more importantly, how you saved your data in the first place.
Let's say you saved data like this:
await boxValue.add(value);
By adding data like this, the key assigned to the value will be an auto-incremented one, so that trying to retrieve it with a specific key that never was assigned in the first place will fail.
If you did add the data like this:
await boxValue.put("myKey", value);
then you will be able to successfully fetch it using the intended key.
You can do the following:
void main() async {
await Hive.initFlutter();
await Hive.openBox('workoutBox'); //<- make sure you await this
runApp(const MyApp());
}
...
_save() { // <- can be a synchronous function
final box = Hive.box('workoutBox'); //<- get an already opened box, no await necessary here
// save doc id somewhere
final Id = doc.id;
box.put("Id", Id);
}
I have written an example app and a Flutter Cubits + Hooks + Hive DB tutorial. I have the following AppDatabase class there:
const String _bookBox = 'book';
#Singleton()
class AppDatabase {
AppDatabase._constructor();
static final AppDatabase _instance = AppDatabase._constructor();
factory AppDatabase() => _instance;
late Box<BookDb> _booksBox;
Future<void> initialize() async {
await Hive.initFlutter();
Hive.registerAdapter<BookDb>(BookDbAdapter());
_booksBox = await Hive.openBox<BookDb>(_bookBox);
}
Future<void> saveBook(Book book) async {
await _booksBox.put(
book.id,
BookDb(
book.id,
book.title,
book.author,
book.publicationDate,
book.about,
book.readAlready,
));
}
Future<void> deleteBook(int id) async {
await _booksBox.delete(id);
}
...