FireBase Realtime DB Not Inserting Data - firebase

This is my register activity. It works before this point
FirebaseDatabase.getInstance().getReference("Users")
.child(FirebaseAuth.getInstance().getCurrentUser().getUid())
.setValue(user).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if(task.isSuccessful()){
Toast.makeText(RegisterActivity.this, "Successful", Toast.LENGTH_LONG).show();
progressBar.setVisibility(View.GONE);
} else {
Toast.makeText(RegisterActivity.this, "Failed", Toast.LENGTH_LONG).show();
progressBar.setVisibility(View.GONE);
}
}
});`
I'm following this tutorial:
https://www.youtube.com/watch?v=Z-RE1QuUWPg&ab_channel=CodeWithMazn
I followed that tutorial and also tried taking the first code snippet out with the example in tools>firebase>realtime db and no results. I also tried getReferenceFromUrl() and that didn't work either.
I'm building a sudoku vocabulary game and just looking to save users now. Later on I will want to query and find the top 10 scores. The user is timed with a stopwatch until they complete the game. Should I change to a sqlite datebase? It seems to be more function with less chances of a roadblock down the road.

Related

Flutter - Is it possible to show the number of users online?

I want to show how many people are using my mobile application instantly in my application. For example: "342 people are currently using the application." or "342 people are online right now." I could not find a solution for this.
I store users data with Firebase. So what I want to do is possible by extracting data from the firebase?
You're simplest and most cost effective way, is to create a document, put in a collection for example called .collection(general), when a user logsIn, add 1 to that value, when they logout, subtract 1, and put this in a stream builder.
After success login, run the following function
await FirebaseFirestore.instance
.collection('general')
.doc('onlineCount)
.update({'membersOnline': FieldValue.increment(1)})//this will increase the number by 1.
);
On logout, substract 1.
this is very easy to handle this logic just save the status when users open your app for eg: on homepage and when they kill your app just update that collection to that particular is offline and at the and do query
where(user:online)
and check the number of users you got and simply show that number.
I hope you got this logic.
A little late to the party. But I would personally recommend making use of the App Lifecycle. Meaning:
detached: The application is still hosted on a flutter engine but is detached from any host views.
inactive: The application is in an inactive state and is not receiving user input. For example during a phone call.
paused: The application is not currently visible to the user and running in the background. This is when you press the Home button.
resumed: The application is visible and responding to user input. In this state, the application is in the foreground.
So you will have to create a StatefulWidget and WidgetsBindingObserver:
import 'package:flutter/material.dart';
class LifeCycleManager extends StatefulWidget {
LifeCycleManager({Key key, #required this.child}) : super(key: key);
final Widget child;
#override
_LifeCycleManagerState createState() => _LifeCycleManagerState();
}
class _LifeCycleManagerState extends State<LifeCycleManager> with WidgetsBindingObserver {
#override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
print('AppLifecycleState: $state');
}
#override
Widget build(BuildContext context) {
return widget.child;
}
#override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
}
And then just check the states as follows:
AppLifecycleState _appLifecycleState;
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
setState(() {
_appLifecycleState = state;
});
if(state == AppLifecycleState.paused) {
print('AppLifecycleState state: Paused audio playback');
//update user file eg. online_status: offline
}
if(state == AppLifecycleState.resumed) {
print('AppLifecycleState state: Resumed audio playback');
//update user file eg. online_status: online
}
print('AppLifecycleState state: $state');
}

Getting firebase data in a stream

I built an application, which gets data from the firebase (realtime db). I did it whith this code, but I want, that I always get the new data. In the internet I found something like in a stream, but I didn't find a manual for that.
Does somebody know how this works?
This is my code:
void readData() {
FirebaseDatabase.instance.reference().child('CHECK').once().then(
(DataSnapshot dataSnapShot) {
print(dataSnapShot.value);
},
);
}
I want to get the data for example every 0.5 seconds
That's not really how Firebase works. But if you want to get the data from the database once right away, and then whenever it is updated, you can use onValue for that.
That'd look something like:
FirebaseDatabase.instance.reference().child('CHECK').onValue.listen((event) {
print(event.snapshot.value);
});
Give it a try: just set up the listener with this code, run the app, and then make a change to the database in the Firebase console. You'll see the data be printed once as soon as you run the app, and then again whenever you make a change.
From what I've read in your comments, you want the function to be executed repeatedly every 0.5 seconds.
A stream is not appropriate for that. However, you can use Timer
#override
void initState() {
super.initState();
timer = Timer.periodic(Duration(seconds: 15), (Timer t) => readData());
}
#override
void dispose() {
timer?.cancel();
super.dispose();
}
Your build() function will be called more than once once Timer.periodic is created.

Geolocation GetLastKnownLocationAsync() permission exception from Xamarin Forms - call fails and no permission prompt

GetLocationAsync fails on my Xamarin.Forms app.
I've got the latest Xamarin.Essentials nuget package.
I've set the necessary permissions in the info.plist.
I am calling this from my ViewModel.
The call is super simple:
var location = await Geolocation.GetLastKnownLocationAsync();
but it's both failing AND failing to prompt a user permission dialog even though my info.plist has been setup correctly with:
NSLocationWhenInUseUsageDescription
Insert reason
I'm asking and answering this question because it was a head scratcher, and I wasn't exactly sure what to be searching for or what the issue was.
My various searches pointed to many related issues but nothing that actually gets to the main problem.
The closest I got was actually this issue on the Essentials github page:
https://github.com/xamarin/Essentials/issues/634
This answer is inspired by Xamarin/Azure evangelist, Brandon Minnick --> take a look at his project where he handles a similar situation with the following code:
So what can we take away from the above? If you look at the context, he has connected his Views with his ViewModels in MVVM style. However, various libraries require that certain methods be called from the Main thread. This is the essence of the issue, and this is what this code can solve.
So to adopt the above code for the geolocation issue addressed in the question, I did the following:
Task<Xamarin.Essentials.Location> GetLocationFromPhone()
{
var locationTaskCompletionSource = new TaskCompletionSource<Xamarin.Essentials.Location>();
Device.BeginInvokeOnMainThread(async () =>
{
locationTaskCompletionSource.SetResult(await Geolocation.GetLastKnownLocationAsync());
});
return locationTaskCompletionSource.Task;
}
I'm using the above from my ViewModel from within a Task. Something like the following.
async Task ExecuteGetGeoLocationCommand()
{
try
{
var locationFromPhone = await GetLocationFromPhone().ConfigureAwait(false);
if (locationFromPhone is null)
return;
_location = locationFromPhone;
if (_location != null)
{
Console.WriteLine($"Latitude: {_location.Latitude}, Longitude {_location.Longitude}, Altitude: {_location.Altitude}");
}
else
{
Console.WriteLine($"Exiting geolocation");
}
catch (FeatureNotSupportedException fnsEx)
{
}
catch (Exception ex)
{
}
}
}
I hope it's helpful to someone else!
If you're using Xamarin.Essentials and aren't being prompted for permission on Android, make sure you've added all the necessary code to the Android Main Activity.
See https://learn.microsoft.com/en-us/xamarin/essentials/get-started?tabs=windows%2Candroid for details.
From the docs:
protected override void OnCreate(Bundle savedInstanceState) {
//...
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState); // add this line to your code, it may also be called: bundle
//...
and
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}

How to retrieve limited documents in firestore depending on the time they were added(For a chat app)?

Basically I want to align the messages as they are supposed to be in the usual chat app.
UPDATE: Now messages are aligned properly in the recyclerview. But whenever I send the new message it puts them on the top of the other messages. And whenever I go back and come again to that activity messages are arranged properly(even the top ones).
I just want the message which I send to show up at the bottom. Any help will be appreciated.
mLinearLayout.setReverseLayout(true);
Then:
private void loadmessage() {
mFirestore.collection("Users").orderBy("Timestamp", Query.Direction.DESCENDING).limit(10).addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot snapshots,
#Nullable FirebaseFirestoreException e) {
if (e != null) {
Log.w("TAG", "listen:error", e);
return;
}
for (DocumentChange dc : snapshots.getDocumentChanges()) {
switch (dc.getType()) {
case ADDED:
Message message = dc.getDocument().toObject(Message.class);
messageList.add(message);
mAdapter.notifyDataSetChanged();
mMessagesList.scrollToPosition(messageList.size()-10);
break;
}
}
}
});
}
You should continue retrieving the information as you are currently doing, and then invert the order on client side, it isn't an expensive task, and trying to do what you want in Firestore is not implemented yet.
After retrieving the list, you can do something like:
Collections.reverse(messageList.clone());
Here is the same case scenario and it has the answer too. So in case anyone looking for the answer.
And This is the github repository for the features of the firestore chat app.

Gathering data from Firebase asynchronously: when is the data-set complete?

in a Firebase Android app that I'm currently developing I would like to provide an export feature. This feature should allow the user to export a set of data that is stored in Firebase.
My plan is to gather all required data into a intermediate object (datastructure) that can be (re-)used for multiple export types.
I am running into the issue that because of the flat Firebase data structure that I am using (as explained in https://www.firebase.com/docs/android/guide/structuring-data.html), it's difficult to know when all the data required for the export has been collected.
Example: when retrieving all objects that are referenced using 'indices' (name: key, value true), for each of these I set an addListenerForSingleValueEvent listener, but because this returns asynchronous, it's impossible to determine when all the indices are retrieved. This way it's not possible to determine the correct moment to start the export.
Who has best practices for coping with this?
Posting this to show a worked out example of the comment of #FrankvanPuffelen that seems to do the job quite well:
#Override
public void onDataChange(DataSnapshot indexListDataSnapshot) {
final long participantsRequired = indexListDataSnapshot.getChildrenCount();
for (DataSnapshot ds : indexListDataSnapshot.getChildren()) {
DataUtil.getParticipantByKey( mEventKey, ds.getKey() ).addListenerForSingleValueEvent( new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Participant p = dataSnapshot.getValue(Participant.class);
mParticipants.add( p );
if (participantsRequired == mParticipants.size()){
executeExport();
}
}
#Override
public void onCancelled(FirebaseError firebaseError) {
mListener.onDataLoadFailure( firebaseError.toException() );
}
});
}
}

Resources