Not getting the correct Firebase String Android - java

I am trying to get a String reference from a nested Collection but it generates a random String instead, I don't understand why because i have it set up in another class and it works correctly (but that is atop level collection.
I am saving as follows:
String folderFirebaseString;
-----------------------
folderFirebaseString = collectionReference.document("User_" + JournalApi.getInstance().getUserId()).collection("Created_Folders").document().getId();
final FolderJournal folderJournal = new FolderJournal();
folderJournal.setTitle(title);
folderJournal.setUserId(currentUserId);
folderJournal.setFolderId(folderFirebaseString);
Log.d(TAG, "folderFireBaseString: " + folderFirebaseString);
//Collection Reference --> Journal <-- document --> unique userID + username entered at registration <-- Collection for Titles --> titleTextView
db.collection("Journal").document("User_" + JournalApi.getInstance().getUserId()).collection("Created_Folders").document().set(folderJournal).addOnSuccessListener(new OnSuccessListener<Void>() {
public void onSuccess(Void aVoid) {
Log.d(TAG, "onSuccess FULL PATH: "+ db.collection("Journal").document("User_" + JournalApi.getInstance().getUserId()).collection("Created_Folders").document().getId());
progressBar.setVisibility(View.INVISIBLE);
Intent intent = new Intent(FolderCreation.this, FoldersActivity.class);
startActivity(intent);
finish();
}
})
My folderFirebaseString returns a random String as wel as the LogD i have set up returns a different random string but the db.collection...(etc...) random generated string in firebase is actually something else.
In another class I have this set up but just as collectionReference = db.collection("CollectionNameHere").getDocument().getId(); and this works and gets the correct String. what am i doing wrong?

I managed to solve this by pre-generating a firebase string and then passing it to its self.
String folderFirebaseString;
-----------------------
folderFirebaseString = collectionReference.document("User_" + JournalApi.getInstance().getUserId()).collection("Created_Folders").document().getId();
final FolderJournal folderJournal = new FolderJournal();
folderJournal.setTitle(title);
folderJournal.setUserId(currentUserId);
folderJournal.setFolderId(folderFirebaseString);
//Collection Reference --> Journal <-- document --> unique userID + username entered at registration <-- Collection for Titles --> titleTextView
db.collection("Journal").document("User_" + JournalApi.getInstance().getUserId()).collection("Created_Folders").document(**folderFirebaseString**).set(folderJournal).addOnSuccessListener(new OnSuccessListener<Void>() {
public void onSuccess(Void aVoid) {
Log.d(TAG, "onSuccess FULL PATH: "+ db.collection("Journal").document("User_" + JournalApi.getInstance().getUserId()).collection("Created_Folders").document(*###folderFirebaseString###*).getId());
progressBar.setVisibility(View.INVISIBLE);
Intent intent = new Intent(FolderCreation.this, FoldersActivity.class);
startActivity(intent);
finish();
}
})

Related

How to retrieve multiple username from Firestore and assign the username to the correct markers on map

The code shown below is the code used to retrieve the multiple users location from Realtime Firebase and assign to the markers on map:
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
mMap.getUiSettings().setZoomControlsEnabled(true);
DatabaseReference db = FirebaseDatabase.getInstance().getReference();
DatabaseReference userLocationRef = db.child("User_Location");
db.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
userLocationRef.get().addOnCompleteListener(new OnCompleteListener<DataSnapshot>() {
#Override
public void onComplete(#NonNull Task<DataSnapshot> task) {
if (task.isSuccessful()) {
try {
for (DataSnapshot ds : task.getResult().getChildren()) {
String userID = String.valueOf(ds.child("userID").getValue());
String encryptedLatitude = ds.child("You").child("l").child("0").getValue(String.class);
String encryptedLongitude = ds.child("You").child("l").child("1").getValue(String.class);
Log.d("encryptedLocation", encryptedLatitude + ", " + encryptedLongitude); //Check the values
Log.d("userid", userID); //Check the values
//decrypt
LocationEncryption locationEncryption = new LocationEncryption();
String decryptedLatitude = null;
String decryptedLongitude = null;
decryptedLatitude = locationEncryption.decrypt(encryptedLatitude);
decryptedLongitude = locationEncryption.decrypt(encryptedLongitude);
Log.d("Decrypted", decryptedLatitude + ", " + decryptedLongitude); //Check the values
double lat = Double.valueOf(decryptedLatitude);
double lng = Double.valueOf(decryptedLongitude);
//Add location on Google Map
LatLng location = new LatLng(lat, lng);
if (hm.containsKey(userID)) {
hm.get(userID).remove();
}
currentLocationMarker = mMap.addMarker(new MarkerOptions().position(location).title(userID));
currentLocationMarker.showInfoWindow();
hm.put(userID, currentLocationMarker);
}
}
catch (Exception e){
e.printStackTrace();
}
} else {
Log.d("TAG", task.getException().getMessage()); //Don't ignore potential errors!
}
}
});
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
The structure of the real-time firebase is as follow:
The result of the code is as follow:
When I click on the marker, it only shows the userID of the user. I want the marker to show the name of the user together with the userID. But the problem is that the multiple users' names are stored in Firestore.
The structure of the Firestore is as follow:
The admin details and the user details are stored in the same collection "Users". The fields "isAdmin" and "isUser" are the method to differentiate them. I only need the username and the admin name is not required.
So, how to retrieve multiple users' names from Firestore and assign the names to the correct markers on the map.
When I click on the marker, it only shows the userID of the user. I want the marker to show the name of the user together with the userID.
The best option that you have is to store the name of the user right near the userID. There is no need to create another database call to only get the name of the user. So your new database schema should look like this:
Firebase-root
|
--- User_Location
|
--- $uid
|
--- userID: "Jk8i...1jy2"
|
--- userName: "Zi Zian Yeo" 👈
And in code should look like this:
String userID = ds.child("userID").getValue(String.class);
String userName = ds.child("userName").getValue(String.class);
And to add these values as a title of the marker please use the following lines of code:
String title = userID + "/" + userName;
currentLocationMarker = mMap.addMarker(new MarkerOptions().position(location).title(title));

How to create a Firebase short dynamic link

I'm successfully creating a Firebase dynamic link in Java on Android. My code to do so is in a button click listener.
shareButton.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
DynamicLink dynamicLink = FirebaseDynamicLinks.getInstance().createDynamicLink()
.setLink(Uri.parse("https://www.mycompany.com/"))
.setDomainUriPrefix("https://mycompany.page.link/test")
.setAndroidParameters(
new DynamicLink.AndroidParameters.Builder("com.mycompany.app")
.setFallbackUrl(Uri.parse("https://www.mycompany.com/"))
.setMinimumVersion(1)
.build())
.buildDynamicLink();
Uri dynamicLinkUri = dynamicLink.getUri();
shareDynamicLink(dynamicLinkUri);
}
});
public void shareDynamicLink(Uri dynamicLink)
{
Intent shareIntent = new Intent();
String msg = "Check this out: " + dynamicLink;
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_TEXT, msg);
shareIntent.setType("text/plain");
startActivity(shareIntent);
}
This sends a LONG dynamic link that works just fine. Now I'd like to shorten the link, so I replaced the 'shareDynamicLink' method with this code.
public void shareDynamicLink(Uri dynamicLink)
{
Task<ShortDynamicLink> shortLinkTask = FirebaseDynamicLinks.getInstance().createDynamicLink()
.setLongLink(dynamicLink)
.buildShortDynamicLink()
.addOnCompleteListener(Objects.requireNonNull(this.getActivity()), new OnCompleteListener<ShortDynamicLink>()
{
#Override
public void onComplete(#NonNull Task<ShortDynamicLink> task)
{
if (task.isSuccessful())
{
// Short link created
Uri shortLink = Objects.requireNonNull(task.getResult()).getShortLink();
Uri flowchartLink = task.getResult().getPreviewLink();
Log.e("DynamicLink", "shortLink: " + shortLink + System.lineSeparator());
Log.e("DynamicLink", "flowChartLink: " + flowchartLink + System.lineSeparator());
Intent shareIntent = new Intent();
String msg = "Check this out: " + shortLink;
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_TEXT, msg);
shareIntent.setType("text/plain");
startActivity(shareIntent);
}
else
{
Toast.makeText(context, "Failed to share event.", Toast.LENGTH_SHORT).show();
}
}
});
}
This second method produces an error that I don't understand.
"400: Cannot shorten a short Dynamic Link:
https://mycompany.page.link/test?afl=https%3A%2F%2Fwww.mycompany.com%2F&amv=1
&apn=com.mycompany.app&ibi=com.mycompany.app&ifl=https%3A%2F%2F
www.mycompany.com%2F&isi=963543827&ipfl=https%3A%2F%2F
www.mycompany.com%2F&link=https%3A%2F%2Fwww.mycompany.com%2F
[https://firebase.google.com/docs/dynamic-links/rest#create_a_short_link_from_parameters]
What am I missing here? This seems like it should work.
Note: I don't need the long dynamic link, just the short one. I tried changing the onClickListener as follows.
shareButton.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
Task<ShortDynamicLink> dynamicLink = FirebaseDynamicLinks.getInstance().createDynamicLink()
.setLink(Uri.parse("https://www.mycompany.com/"))
.setDomainUriPrefix("https://mycompany.page.link/test")
.setAndroidParameters(
new DynamicLink.AndroidParameters.Builder("com.mycompany.app")
.setFallbackUrl(Uri.parse("https://www.mycompany.com/"))
.setMinimumVersion(1)
.build())
.buildShortDynamicLink()
.addOnCompleteListener(Objects.requireNonNull(getActivity()), new OnCompleteListener<ShortDynamicLink>()
{
#Override
public void onComplete(#NonNull Task<ShortDynamicLink> task)
{
if (task.isSuccessful())
{
Uri shortLink = Objects.requireNonNull(task.getResult()).getShortLink();
Uri flowchartLink = task.getResult().getPreviewLink();
Log.e("DynamicLink", "shortLink: " + shortLink + System.lineSeparator());
Log.e("DynamicLink", "flowChartLink: " + flowchartLink + System.lineSeparator());
}
else
{
Log.e("DynamicLink", "Link failed: " + task.getException().getMessage() + System.lineSeparator());
}
}
});
}
});
But I still get the same 400 error.
400: Cannot shorten a short Dynamic Link:
https://mycompany.page.link/test?afl=https%3A%2F%2Fwww.mycompany.com%2F&amv=1
&apn=com.mycompany.app&ibi=com.mycompany.app&ifl=https%3A%2F%2F
www.mycompany.com%2F&isi=963543827&ipfl=https%3A%2F%2Fwww.mycompany.com%2F
&link=https%3A%2F%2Fwww.mycompany.com%2F
[https://firebase.google.com/docs/dynamic-links/rest#create_a_short_link_from_parameters]
For anyone who finds this, my problem stemmed from a misunderstanding of how programmatically generated links work vs. predefined links. In my case I was trying to use a pre-defined link from the Firebase console ("https://mycompany.page.link/test") as the PREFIX for my generated link. That caused some sort of confusion on the back end when I tried to shorten it. I still don't understand exactly what it didn't like, but point is it failed.
So the solution for generating links was to use only the base prefix from the Firebase console - .setDomainPrefix("https://mycompany.page.link/"). Using that I can create either ".buildShortDynamicLink()" or "buildDynamicLink()".
The link I created in the Firebase console ("http://mycompany.page.link/test") can only be used verbatim -- no need to generate anything. Just put it in a text message literally and you're done.
Are you going to use the longer version at all, or only the short one? If so, does it work if you use .buildShortDynamicLink() instead of .buildDynamicLink() in your onClick(...) method without the conversion in shareDynamicLink(...)?

Saving data to Firebase with a Username Reference

I am developing a quiz application whereby a User takes a quiz and after 10 questions the score is saved to a database in Firebase.
Here is my code at present:
String user_id = mAuth.getCurrentUser().getUid();
DatabaseReference current_user_db =
FirebaseDatabase.getInstance().getReference().child("Score").child(user_id);
final int score = mScore;
**databaseUserName = FirebaseDatabase.getInstance().getReference().child("Users").child(user_id).child("username");
databaseUserName.addValueEventListener(new com.google.firebase.database.ValueEventListener() {
#Override
public void onDataChange(com.google.firebase.database.DataSnapshot dataSnapshot) {
String username = dataSnapshot.getValue().toString();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});**
//Ensures everything saves at the same time
Map newPost = new HashMap();
newPost.put("Score", score);
**newPost.put("Username", username);**
current_user_db.setValue(newPost);
The part enclosed in ** ** is where I am having some difficulties.
The user signs up to my app using FirebaseAuth, then using the UID I have stored name and username in a 'Users' realtime database.
I would like the score databse to save the final score with the username not the autogenerated UID. I'm just not sure how to get the username and then save it to the new database.
I have also attached a screenshot of how my current database looks.
I have only been using Firebase and Android Studio a few weeks so any help/links are all appreciated.
You can do something like this
final String userName = "userX";
final int score = 55;
FirebaseDatabase db = FirebaseDatabase.getInstance();
db.getReference("Score").child(userName).child("Score").setValue(score).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.d(TAG, "onSuccess: updated " + userName + "'s score (" + score + ")");
}
});
Change your String userName to a member.
String user_id = mAuth.getCurrentUser().getUid();
// you can remove child(user_id) if you want to put username directly under Score
DatabaseReference current_user_db = FirebaseDatabase.getInstance().getReference().child("Score").child(user_id);
final int score = mScore;
DatabaseReference databaseUserName = FirebaseDatabase.getInstance().getReference().child("Users").child(user_id).child("username");
databaseUserName.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
userName = dataSnapshot.getValue().toString();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
//Ensures everything saves at the same time
Map newPost = new HashMap();
newPost.put("Score", score);
newPost.put("Username", username); // I don't think you need this.
current_user_db.child(username).setValue(newPost);
Let me know if it works.
There is no way in which you can simply use username outside onDataChange() method because this method has an asynchronous behaviour which means that is called even before you are trying to get the data from the database. A quick fix to you are problem would be to move the follwing lines of code:
Map newPost = new HashMap();
newPost.put("Score", score);
newPost.put("Username", username);
current_user_db.child(username).setValue(newPost);
Inside onDataChange() method and your problem will be solved but if you need to use the value of username outside the onDataChange() method, then you need to create your own callback and for that I recomend you see the last part of my answer from this post.

Azure easy table given me package info in my ListView instead of data in the Azure table

When i query the azure table for a SEEDNAME (column in my Azure table) i get null back. when i put required data in the logcat like: Log.i(TAG, "Read object with ID " + item.id + " " + item.SEEDNAME); i get the proper ID and a null for the name.
and when i add the data to a list view i get what looks like the package name.
public class Azuretbl {
public String id;
public String SEEDNAME;
public String SEEDTYPE;
public int SEED_AMOUNT;
}
This is the client table which matches table on Azure.
the Code for querying:
public void viewFromAzure(){
button_view_from_azure = (Button)findViewById(R.id.btnViewDataFromAzure);
button_view_from_azure.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View v) {
final ArrayAdapter<Azuretbl> myAdapter = new ArrayAdapter<Azuretbl>
(getApplicationContext(), android.R.layout.simple_list_item_activated_1);
azure_list_view = (ListView) findViewById(R.id.listViewAzure);
azure_list_view.setAdapter(myAdapter);
new AsyncTask<Void, Void, MobileServiceList<Azuretbl>>(){
MobileServiceTable<Azuretbl> myTestAzuretbl = mClient.getTable(Azuretbl.class);
#Override
protected MobileServiceList<Azuretbl> doInBackground(Void... params) {
MobileServiceList<Azuretbl> result;
try {
result = myTestAzuretbl.where().field("SEEDNAME").eq("Tomato").execute().get();
/*where().field("SEEDNAME").eq("tomato").*/
final MobileServiceList<Azuretbl> finalResult = result;
runOnUiThread(new Runnable() {
#Override
public void run() {
myAdapter.clear();
for (Azuretbl item : finalResult) {
Log.i(TAG, "Read object with ID " + item.id + " " + item.SEEDNAME);
System.out.println("Item is " + finalResult);
myAdapter.add(item);
}
}
});
} catch (Exception exception) {
}
return null;
}
}.execute();
}
}
);
}
and i get this in the logcat:
04-09 13:21:29.232 3029-3029/? I/JonnysMessage: Read object with ID a822b906-5f84-4345-86d2-3031247e380a null
04-09 13:21:29.232 3029-3029/? I/System.out: Item is [com.jonnyg.gardenapp.Azuretbl#537e457c, com.jonnyg.gardenapp.Azuretbl#537e4b04]
Snapshot of listview on app
Result of the listview on app
snapshot of Azure table on cloud
Azure snapshot of table
just to add i am using the new portal on azure. i have permission set for read insert etc.. to allow anonymous access. I am not using an application key do i need one?
I have figured out my problem.
On azure the easy table i had created had the field SEEDNAME as seedNAME in the area where you add a column this was visible and not visible when viewing the table on azure. After solving this the Seed name was viewing in the logcat.
I also created a custom adapter to view the data in a listview.

Java/Parse - The app goes back to the main activity instead of creating new user or signing up

I have two buttons on my main screen activity that lead to two different activities, one to login and the other to sign up.
When I'm on the sign in activity or the sign up activity and press the buttons, even when the fields are empty it redirects it to the main screen activity...
For the signIn method
public void signIn(View View) {
String username = String.valueOf(this.username.getText());
String password = String.valueOf(this.password.getText());
Log.i("SignInInfo", username);
Log.i("SignInInfo", password);
ParseUser.logInInBackground(username, password, new LogInCallback() {
public void done(ParseUser user, ParseException e) {
if (user != null) {
// Hooray! The user is logged in.
Intent userList = new Intent(getApplicationContext(), UserListActivity.class);
startActivity(userList);
} else {
// Signup failed. Look at the ParseException to see what happened.
Toast.makeText(getApplicationContext(), "There was an error with your username/password combination. Please try again...", Toast.LENGTH_LONG).show();
}
}
});
}
For the signUp method
public void signUp(View View) {
String firstname = String.valueOf(this.firstname.getText());
String lastname = String.valueOf(this.lastname.getText());
String username = String.valueOf(this.username.getText());
String password = String.valueOf(this.password.getText());
String email = String.valueOf(this.email.getText());
Log.i("SignUpInfo", "First Name:\t " + firstname);
Log.i("SignUpInfo", "Last Name:\t " + lastname);
Log.i("SignUpInfo", "Username:\t " + username);
Log.i("SignUpInfo", "Password:\t " + password);
Log.i("SignUpInfo", "Email:\t\t " + email);
ParseUser newUser = new ParseUser();
newUser.put("First Name", firstname);
newUser.put("Last Name", lastname);
newUser.setUsername(username);
newUser.setPassword(password);
newUser.setEmail(lastname);
newUser.signUpInBackground(new SignUpCallback() {
#Override
public void done(ParseException e) {
if (e == null) {
// Hooray! Let them use the app now.
Log.i("SignUpInfo", "Sign Up Succesful");
Intent userList = new Intent(getApplicationContext(), UserListActivity.class);
startActivity(userList);
Toast.makeText(getApplicationContext(), "Welcome to our cult. Ah, I mean community!", Toast.LENGTH_LONG).show();
} else {
// Sign up didn't succeed.
Toast.makeText(getApplicationContext(), e.getMessage().substring(e.getMessage().indexOf(" ")), Toast.LENGTH_LONG).show();
}
}
});
}
I realized it had something to do with the Parse codes because when I comment the Parse codes for both the log in and sign up it prints the info to the logs, but when I uncomment it, the same issue. It crashes and goes back to the home view...
When getting a string from an EditText it is usually clearer to just write this.firstname.getText().toString().
It is odd that the your log messages only print if your ParseUser methods are commented out. Based on your code above they should print either way since the log messages are before parsing.
Looking at the code you shared you might not be properly assigning your EditText variables before using them which might cause a crash.
To be sure add the stack trace for the exception that is crashing the app and further help can be given.

Categories

Resources