When I was using firebase for initialization of data and setText on UI, It was delayed for 10~15 seconds.
On the other hand, When I use Volley, It was delayed for only 1 seconds.
why is it so slow when i'm using firebase and How can I modifying this code?
here is my code (using ValueEventListener) and JSON tree
"couple_profile" : {
"TEST999AhCBcHK32AQzU3JglVbAxhTD6Mn1" : {
"birthday_1" : "1994-06-29",
"birthday_2" : "19940629",
"couple_nick" : "TEST999",
"exp" : 0,
"gold" : 0,
"level" : 1,
"member" : {
"AhCBcHK32AQzU3JglVbAxhTD6Mn1" : {
"FCM" : "d5Y-fl_0VCs:APA91bHX7HA531PXc1e4clUg61uB3XsKlwmQ_2U9OaESUTP0r-dnwbitSvxQ4EDMqPzK-t_5b9qPOhLm01FRffgB9-Ot6bZmx1JzwZvc07yoyhashGUS79E7Dztr2J7NfR1NGXw1LT2V",
"birthday" : "1994-06-29",
"name" : "김준겸",
"phone_number" : "01050639201"
},
"FMsH7leNTOXBgbOFoWdaTMjt05T2" : {
"birthday" : "19940629",
"name" : "kimGod",
"phone_number" : "1541"
}
},
"mileage" : 0,
"name_1" : "김준겸",
"name_2" : "kimGod",
"uid_1" : "AhCBcHK32AQzU3JglVbAxhTD6Mn1",
"uid_2" : "FMsH7leNTOXBgbOFoWdaTMjt05T2"
}
private void get_home_info() {
valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(final DataSnapshot dataSnapshot) {
coupleProfile = dataSnapshot.getValue(CoupleProfile.class);
if (coupleProfile == null) {
Log.e(TAG, "User " + FirebaseAuth.getInstance().getCurrentUser().getEmail() + " is unexpectedly null_1");
Toast.makeText(Home_Fragment.this.getContext(), "Error_1", Toast.LENGTH_SHORT).show();
} else {
StorageReference storageRef2 = storage.getReferenceFromUrl("FirebaseURL").child("Profile_image/" + FirebaseAuth.getInstance().getCurrentUser().getUid());
Glide.with(getContext()).using(new FirebaseImageLoader()).load(storageRef2).centerCrop()
.bitmapTransform(new CropCircleTransformation(new CustomBitmapPool()))
.into(me_view);
SharedPreferences.Editor sh = home_info.edit();
if (My_UID.equals(coupleProfile.uid_1)) {
my_number = 1;
sh.putString("my_name",coupleProfile.name_1);
sh.putString("op_name",coupleProfile.name_2);
sh.apply();
my_name_text.setText(coupleProfile.name_1);
op_name_text.setText(coupleProfile.name_2);
state_text.setText(coupleProfile.state_1);
op_state_text.setText(coupleProfile.state_2);
StorageReference storageRef = storage.getReferenceFromUrl("FirebaseURL").child("Profile_image/" + coupleProfile.uid_2);
Glide.with(getContext()).using(new FirebaseImageLoader()).load(storageRef).centerCrop()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.bitmapTransform(new CropCircleTransformation(new CustomBitmapPool()))
.into(friend_view);
} else if (My_UID.equals(coupleProfile.uid_2)) {
my_number = 2;
sh.putString("my_name",coupleProfile.name_2);
sh.putString("op_name",coupleProfile.name_1);
sh.apply();
my_name_text.setText(coupleProfile.name_2);
op_name_text.setText(coupleProfile.name_1);
state_text.setText(coupleProfile.state_2);
op_state_text.setText(coupleProfile.state_1);
StorageReference storageRef = storage.getReferenceFromUrl("FirebaseURL").child("Profile_image/" + coupleProfile.uid_1);
Glide.with(getContext()).using(new FirebaseImageLoader()).load(storageRef).centerCrop().diskCacheStrategy(DiskCacheStrategy.SOURCE)
.bitmapTransform(new CropCircleTransformation(new CustomBitmapPool()))
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(friend_view);
} else {
Log.e(TAG, "User " + FirebaseAuth.getInstance().getCurrentUser().getEmail() + " is unexpectedly null_2");
Toast.makeText(Home_Fragment.this.getContext(), "Error", Toast.LENGTH_SHORT).show();
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "onCancelled: ", databaseError.toException());
}
};
ref = databaseReference.child("couple_profile").child(room_token);
ref.addValueEventListener(valueEventListener);
}
I think if you use this method from firebase you will have better loading of data:
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
Use the above code, explanation about it:
Firebase provides great support when comes to offline data. It automatically stores the data offline when there is no internet connection. When the device connects to internet, all the data will be pushed to realtime database. However enabling disk persistence stores the data offline even though app restarts.
Also try and retrieve the data in onStart()
Also, look for uses of .keepSynced(true). This likewise causes the entire node for which it is called to be fetched before it makes any updates. This can be very slow, depending on what node it is called for.
Related
I am writing data to the database using another class with a constructor, but I still need to read data from the database. In the documentation, when using other classes, you need to create HashMap lists for each element, but I have 2 classes (since I need to write more than 255 entries to the database) and in each class, I will have to write a HashMap. How can I load the name of a DB variable that is identical to the name in the file itself? For example int b = 0; and in the database - b: 0 and how can you get the value of each variable from the database?
I send data like this:
if (user != null) {
if(database.child(getEmail)==null) {
User newUser = new User(getEmail, coins, ....);
User1 newUser1 = new User1(a256, a257, ....);
database.child(getEmail).push().setValue(newUser1);
database.child(getEmail).push().setValue(newUser);
}
I read data like this:
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for(DataSnapshot ds : snapshot.getChildren()){
User user = ds.getValue(User.class);
//saving information witch will read from db in SharedPreferences
PreferenceConfig.GetEmail(getApplicationContext(), getEmail);
PreferenceConfig.GetCoin(getApplicationContext(), getEmail);
PreferenceConfig.GetA256(getApplicationContext(), a256);
...
}
}
database.addValueEventListener(valueEventListener);
But i can`t understend how can i get data from db without hashmap
JSON file:
{
"User": {
"mail#gmail:com": {
"-NHTVinbEVUAqJwK8Umt": {
"getEmail": "mail#gmail.com",
"coins": 100,
.....
},
"-NHTVinpCPOJ4UPZvgpN": {
"a256":0,
"a257":0
...............
}
}
}
}
You won't be able to read the data under fields that are dynamically created:
{
"User": {
"mail#gmail:com": {
"-NHTVinbEVUAqJwK8Umt": {
"getEmail": "mail#gmail.com",
"coins": 100,
},
"-NHTVinpCPOJ4UPZvgpN": {
"a256":0, //👈
"a257":0 //👈
}
}
}
}
You'll be able to read all the data if your second child will have the same fields as the first one:
{
"User": {
"mail#gmail:com": {
"-NHTVinbEVUAqJwK8Umt": {
"getEmail": "mail#gmail.com",
"coins": 100,
},
"-NHTVinpCPOJ4UPZvgpN": {
"getEmail": "other#gmail.com", //👈
"coins": 200, //👈
}
}
}
}
Now, to read the data from such a structure, you have to create a reference that points to mail#gmail:com node and make a get() call as you can see in the following lines of code:
DatabaseReference db = FirebaseDatabase.getInstance().getReference();
DatabaseReference emailRef = db.child("User").child("mail#gmail:com");
emailRef.get().addOnCompleteListener(new OnCompleteListener<DataSnapshot>() {
#Override
public void onComplete(#NonNull Task<DataSnapshot> task) {
if (task.isSuccessful()) {
for (DataSnapshot ds : task.getResult().getChildren()) {
String email = ds.child("getEmail").getValue(String.class);
Log.d("TAG", email);
}
} else {
Log.d("TAG", task.getException().getMessage()); //Never ignore potential errors!
}
}
});
The result in the logcat will be:
mail#gmail.com
other#gmail.com
Or you can map each DataSnapshot object into an object of type User:
User user = ds.getValue(User.class);
This operation will work, only if your User class contains two fields called getEmail and coins. The first being a string and the second one a number.
I am trying to get records from firebase database and return all the record within a array list but inside the for loop it will add records but when we check outside the loop it does not contain records. can anyone please help me i am new in android.Here is the code for fetching data..
public class DataBaseManagement {
public static ArrayList<Property> getAllProperties(Context context, DatabaseReference dbProperty){
ArrayList<Property> propertyList = new ArrayList<Property>();
dbProperty.get().addOnSuccessListener(new OnSuccessListener<DataSnapshot>() {
#Override
public void onSuccess(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()){
Property tempProp;
for (DataSnapshot aProp: dataSnapshot.getChildren())
{
tempProp = aProp.getValue(Property.class);
propertyList.add(tempProp);
}
Toast.makeText(context, "Total Properties : " + propertyList.size(), Toast.LENGTH_SHORT).show(); // Here it will show the number of records
}
else {
Toast.makeText(context, "No record found", Toast.LENGTH_SHORT).show();
}
}
});
Toast.makeText(context, "Total Properties : " + propertyList.size(), Toast.LENGTH_SHORT).show(); // here it will not show the number of records
return propertyList;
}
}
as I know in addOnSucessListener it works in background thread
the fun will return and finish the background thread I think if you want it change return fun to void and use out fun liveData and update it inside addOnSucessListener
This question already has answers here:
How to return a DocumentSnapShot as a result of a method?
(2 answers)
Closed 3 years ago.
Currently Running into an issue where I'm fetching data from firebase. I know it is because Firebase is asynchronous, so when I make my firebase call, it is executed on its own thread, and the current thread that it was called on continues to execute. I'm populating a list of objects with the data from firebase and I return that list of objects. The thing is, the list is always returning null because the execution of the firebase code isn't completed in time.
I created some asynchronous code that fetches from SQLite db that works fine, but this approach does not seem to work with firebase (I believe its due to firebases API being asynchronous) Here is my method to return a list of objects from firebase.
/** Method to get activity data from firebase.
* #param userInput the user query to select the data
* #return a list of activity models based on the query
* */
public List<ActivityModel> retrieveActivityData(String userInput) {
Log.d(TAG, "retrieveActivityData: starts");
List<ActivityModel> models = new ArrayList<ActivityModel>();
// execute the query in firebase
CollectionReference activfitCollection = db.collection("activity");
activfitCollection.orderBy("isoTimestamp")
.startAt(userInput)
.endAt(DateHelper.getDayEndingDate(userInput))
.get()
.addOnCompleteListener(task -> {
if (task.isSuccessful()) {
Log.d(TAG, "onComplete: Getting data successful!");
// check to see if it exists
if (!task.getResult().isEmpty()) {
for (DocumentSnapshot documentSnapshot : task.getResult().getDocuments()) {
Log.d(TAG, "retrieveActivityData: document = " + documentSnapshot.getId());
// cast the document to the activity model
Log.d(TAG, "retrieveActivityData: document data " + documentSnapshot.getData());
ActivityModel model = mapToActivityModel(documentSnapshot);
models.add(model);
Log.d(TAG, "retrieveActivityData: array size" + models.size());
}
}
} else {
Log.e(TAG, "onComplete: Error getting documents: ", task.getException());
}
});
Log.d(TAG, "retrieveActivityData: array size outside " + models.size());
return models;
}
Option - 1: You can use LiveData to achieve this. Post value to LiveData when operation complete and observe that inside your activity or fragment
MutableLiveData<List<ActivityModel>> listMutableLiveData = new MutableLiveData<>();
public MutableLiveData<List<ActivityModel>> retrieveActivityData(String userInput) {
List<ActivityModel> models = new ArrayList<ActivityModel>();
....
if (task.isSuccessful()) {
for (DocumentSnapshot documentSnapshot : task.getResult().getDocuments()) {
....
models.add(model);
}
//Post value to live data from here
listMutableLiveData.postValue(models);
}
....
return listMutableLiveData;
}
And then observe like this
retrieveActivityData(userInput).observe(this, new Observer<List<ActivityModel>>() {
#Override
public void onChanged(List<ActivityModel> activityModels) {
//you can use list here
}
});
Option - 2: You can use callback function to get result when firebase operation complete.
Create an interface for callback
interface FirebaseResultListener {
void onComplete(List<ActivityModel> activityModels);
}
Configure your retrieveActivityData to handle this callback
public void retrieveActivityData(String userInput, FirebaseResultListener callback) {
List<ActivityModel> models = new ArrayList<ActivityModel>();
....
if (task.isSuccessful()) {
for (DocumentSnapshot documentSnapshot : task.getResult().getDocuments()) {
....
models.add(model);
}
//Invoke callback with result from here
callback.onComplete(models);
}
....
}
Implement this interface in your activity or fragment
retrieveActivityData(userInput, new FirebaseResultListener() {
#Override
public void onComplete(List<ActivityModel> activityModels) {
//you can use list here
}
});
Since the data is loaded async you cannot return the data, you should pass callback(Interface) in retrieveActivityData method, and use callback of interface to load the data, check the code bellow
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
MyFirebaseCallback myFirebaseCallback = new MyFirebaseCallback() {
#Override
public void dataLoaded(List<ActivityModel> activityModels) {
//set the data in recycler view
}
};
retrieveActivityData("myInput",myFirebaseCallback);
}
public void retrieveActivityData(String userInput, final MyFirebaseCallback callback) {
Log.d(TAG, "retrieveActivityData: starts");
// execute the query in firebase
CollectionReference activfitCollection = db.collection("activity");
activfitCollection.orderBy("isoTimestamp")
.startAt(userInput)
.endAt(DateHelper.getDayEndingDate(userInput))
.get()
.addOnCompleteListener(task -> {
if (task.isSuccessful()) {
List<ActivityModel> models = new ArrayList<ActivityModel>();
Log.d(TAG, "onComplete: Getting data successful!");
// check to see if it exists
if (!task.getResult().isEmpty()) {
for (DocumentSnapshot documentSnapshot : task.getResult().getDocuments()) {
Log.d(TAG, "retrieveActivityData: document = " + documentSnapshot.getId());
// cast the document to the activity model
Log.d(TAG, "retrieveActivityData: document data " + documentSnapshot.getData());
ActivityModel model = mapToActivityModel(documentSnapshot);
models.add(model);
Log.d(TAG, "retrieveActivityData: array size" + models.size());
}
}
callback.dataLoaded(models);
} else {
Log.e(TAG, "onComplete: Error getting documents: ", task.getException());
}
});
Log.d(TAG, "retrieveActivityData: array size outside " + models.size());
}
interface MyFirebaseCallback{
void dataLoaded(List<ActivityModel> activityModels);
}
You have guessed it right! The query is asynchronous so retrieveActivityData() shouldn't return List<ActivityModel> or it would always be null. You would have to use an Event Bus to fire an event as soon as your List is compiled inside onComplete() or use LiveData and observe it.
LiveData
ViewModel
EventBus
I've looked at a few other answers for similar problems but don't understand why mine isn't working.
I'm trying to get my app to read commands from Firebase and move a drone. The command in firebase comes from a separate software. The app is built on top of the Parrot Drone SDK Sample code.
It seems to be able to get the text from the command object and append it to a textview, but when a new child is added it just crashes. I'm getting this error when a new child is added.
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.parrot.sdksample, PID: 10592
com.google.firebase.database.DatabaseException: Can't convert object of type java.lang.String to type com.parrot.sdksample.activity.CommandObject
at com.google.android.gms.internal.zg.zzb(Unknown Source)
at com.google.android.gms.internal.zg.zza(Unknown Source)
at com.google.firebase.database.DataSnapshot.getValue(Unknown Source)
at com.parrot.sdksample.activity.MiniDroneActivity$13.onChildAdded(MiniDroneActivity.java:383)
at com.google.android.gms.internal.px.zza(Unknown Source)
at com.google.android.gms.internal.vj.zzHX(Unknown Source)
at com.google.android.gms.internal.vp.run(Unknown Source)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
A sample of my data structure in firebase is below.
{
"drones" : {
"commands" : {
"-L-n9HwaQktOdI2VEVlH" : {
"executed" : false,
"text" : "TAKE_OFF",
"timestamp" : 1.512686825309134E9
},
"-L-nAuK5Ifde7Cdnan8K" : {
"executed" : false,
"text" : "LAND",
"timestamp" : 1.512687248764272E9
}
}
}
}
The function in my activity to get data from firebase looks like this.
private void initFirebase(){
mCommandTextView = (TextView) findViewById(R.id.commandTextView);
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference commandsRef = database.getReference("drones/commands");
ChildEventListener childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildAdded:" + dataSnapshot.getKey());
CommandObject command = dataSnapshot.getValue(CommandObject.class);
mCommandTextView.append(command.text + "\n");
// I've tried commenting out the if statements below this, but it doesn't seem to make a difference.
if ("TAKE_OFF".equals(command.text)) {
mMiniDrone.takeOff();
} else if ("LAND".equals(command.text)) {
mMiniDrone.land();
}
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName){
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName){
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
commandsRef.addChildEventListener(childEventListener);
}
My CommandObject class looks like this.
public class CommandObject {
public String text;
public float timestamp;
public boolean executed;
public CommandObject() {
}
public CommandObject(boolean executed, String text, float timestamp){
this.executed = executed;
this.text = text;
this.timestamp = timestamp;
}
}
I've also tried using a value event listener instead, but the same problem occured.
You are getting this error:
Can't convert object of type java.lang.String to type com.parrot.sdksample.activity.CommandObject
Because you are trying to read the data of type String which is of type CommandObject and that why you are getting this error.
A more simple way to get those values would be to use the String class like this:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference commandsRef = rootRef.child("drones").child("commands");
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()) {
boolean executed = ds.child("executed").getValue(Boolean.class);
String text = ds.child("text").getValue(String.class);
double timestamp = ds.child("timestamp").getValue(Double.class);
Log.d("TAG", executed + " / " + text + " / " + timestamp);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
commandsRef.addListenerForSingleValueEvent(eventListener);
And this the approach using an object of CommandObject class:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference commandsRef = rootRef.child("drones").child("commands");
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()) {
CommandObject commandObject = ds.getValue(CommandObject.class);
Log.d("TAG", commandObject.getExecuted() + " / " +
commandObject.getText() + " / " +
commandObject.getTimestamp());
}
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
commandsRef.addListenerForSingleValueEvent(eventListener);
In both cases your output will be:
false / TAKE_OFF / 1.512686825309134E9
false / LAND / 1.512687248764272E9
The solution provided by Alex worked but didn't quite answer why I couldn't get store my data in an object, and for my app while the child added listener, the app is able to read data that was already on Firebase but when new child is added, the value is empty.
onChildAdded:DataSnapshot { key = -L0JjGo-3QMYDsuTMQcN, value = }
I've done a little more digging to find out what might be causing this and found that it is probably caused because the values were not all written at the same time. And looking at firebase it seems that the key is added first, then the values are added. This is why the error says can't convert, it is because it doesn't exist.
I'm using the Python Firebase Admin SDK to add the data to Firebase, so I'm not sure if this is the reason for that.
So to fix my problem I moved my code to the onChildChanged function and added a check so that the code only runs when all of the data I need exists. This way I can get the values stored in an object straight away.
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName){
if (dataSnapshot.child("text").exists() &&
dataSnapshot.child("executed").exists() &&
dataSnapshot.child("timestamp").exists()){
Log.d(TAG, "onChildChanged:" + dataSnapshot.toString());
CommandObject command = dataSnapshot.getValue(CommandObject.class);
if ("TAKE_OFF".equals(command.text)) {
mMiniDrone.takeOff();
} else if ("LAND".equals(command.text)) {
mMiniDrone.land();
}
}
}
Alex posted the right solution for me, but since I was using firebase-ui and kotlin, the code used is different. More info here
val options = FirebaseRecyclerOptions.Builder<ChatMessage>()
.setQuery(query, ChatMessage::class.java)
.build()
// equivalent options object with manual parsing, use it to debug which field gives error
val options = FirebaseRecyclerOptions.Builder<ChatMessage>()
.setQuery(query, object : SnapshotParser<ChatMessage> {
override fun parseSnapshot(snapshot: DataSnapshot): ChatMessage {
val senderId = snapshot.child("senderId").getValue(String::class.java)
val receiverId = snapshot.child("receiverId").getValue(String::class.java)
val senderName = snapshot.child("senderName").getValue(String::class.java)
val text = snapshot.child("text").getValue(String::class.java)
val timestamp = snapshot.child("timestamp").getValue(Long::class.java)
return ChatMessage(senderId, receiverId, senderName, text, timestamp)
}
})
.build()
adapterMessages = object : FirebaseRecyclerAdapter<ChatMessage, ChatHolder>(options) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChatHolder {
val rootView = LayoutInflater.from(parent.context).inflate(R.layout.chat_message_item, parent, false)
return ChatHolder(rootView)
}
override fun onBindViewHolder(holder: ChatHolder, position: Int, model: ChatMessage) {
holder.populateItem(model)
}
}
if u are using map object in your database should use get method directly with your object
doc: DocumentSnapshot
val data = doc.get("location", SaleLocations::class.java)
I faced a similar issue where I could not retrieve the data from the database; having a DatabaseException error with a message
can't convert from this type to that type.
The mistake I was making was I was writing incorrectly to the database. I wrote something like ...
mdatabaseReference.setValue(myObject)
instead of
mdatabaseReference.child(myObject.getId()).setValue(myObject)
So essentially the answer I am suggesting is: you should ensure your data is written correctly to the database at the right node in the JSON tree if not you would likely get this kind of error when you are reading from the database.
you can use constructor oop normally like this
it's the same and no Error anymore
CommandObject command = new CommandObject(ds.child("").getValue()....
fill it and make sure your reference in firebase data should not be empty
In my case the problem was, that I using Kotlin class, and there were no default constructor such as
constructor() : this(0, "")
I have done the following in Swift:
let currentUser = Auth.auth().currentUser
currentUser?.getTokenForcingRefresh(true) {idToken, error in
if let error = error {
// Handle error
print("error (below)")
print(error)
return;
}
print("idToken = " + idToken!) // token looks like this: kpJhbGRiOiJSUzI1NiIsIntpZCI9Ijg0MjIuYzc3NTWkOWZmTjI3OBQxZTkyNTpkNWZjZjUwNzg2YTFmNGIifQ.eyJpc3MiOiJodHRwczovL3NlY3Vy... (it's really long)
//..do stuff with token
}
I am now trying to do the equivalent for Android. The firebase documentation touches on the topic but does not explain getting the token extensively. I have tried the following:
Log.d(TAG, user.getIdToken(true));
However, this gives me the following error when I attempt to authenticate this alone on my backend server:
Error: Decoding Firebase ID token failed. Make sure you passed the
entire string JWT which represents an ID token. See
https://firebase.google.com/docs/auth/admin/verify-id-tokens for
details on how to retrieve an ID token.
at FirebaseAuthError.Error (native)
at FirebaseAuthError.FirebaseError [as constructor] (/user_code/node_modules/firebase-admin/lib/utils/error.js:25:28)
at new FirebaseAuthError (/user_code/node_modules/firebase-admin/lib/utils/error.js:90:23)
at FirebaseTokenGenerator.verifyIdToken (/user_code/node_modules/firebase-admin/lib/auth/token-generator.js:155:35)
at Auth.verifyIdToken (/user_code/node_modules/firebase-admin/lib/auth/auth.js:104:37)
at admin.database.ref.child.child.child.child.child.child.orderByChild.once.then.snapshot
(/user_code/index.js:1430:22)
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
I believe this is because there needs to be an onSuccessListener but am not sure, nor have had success implementing it as follows:
user.getIdToken(true).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
Log.d(TAG, "onSuccess: taskSnapshot = " + taskSnapshot);
}
});
Your second approach is close, you just need to use <GetTokenResult> instead of <UploadTask.TaskSnapshot> as that is for uploading images using Firebase Storage.
Try this:
user.getIdToken(true).addOnSuccessListener(new OnSuccessListener<GetTokenResult>() {
#Override
public void onSuccess(GetTokenResult result) {
String idToken = result.getToken();
//Do whatever
Log.d(TAG, "GetTokenResult result = " + idToken);
}
});
You can get the user token like below code
FirebaseAuth mAuth = FirebaseAuth.getInstance();
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
information
FirebaseUser user = Objects.requireNonNull(task.getResult()).getUser();
assert user != null;
user.getIdToken(true).addOnSuccessListener(result -> {
String idToken = result.getToken();
//Do whatever
Log.d(TAG, "GetTokenResult result = " + idToken);
});
} else {
if (task.getException() instanceof FirebaseAuthInvalidCredentialsException) {
Toast.makeText(getApplicationContext(), "Your code is not correct!", Toast.LENGTH_SHORT).show();
code.");
}
}
}
});
}