I am trying to save data to firebase with the following structure
root
--clothing
----clothingImgDownloadUrl
------title
------category
As I understand I need to make a reference to the path in my database where I want to save the new data.
FirebaseApp app = FirebaseApp.getInstance();
assert app != null;
mDatabase = FirebaseDatabase.getInstance(app);
mClothingRef = mDatabase.getReference("clothing");
I want to add new clothing using the clothing reference created above
mClothingRef.child(clothingImgDownloadUrl).setValue(clothing);
However the code above is only ran once the clothing image is uploaded to firebase storage and its download url is returned to the app where it can be used as the unique identifier for the entries in the firebase database. Below is the code to upload the image to firebase storage.
FirebaseStorage storage = FirebaseStorage.getInstance();
StorageReference storageRef = storage.getReference(FIREBASE_STORAGE_CLOTHING_REFERENCE);
StorageReference photoRef = storageRef.child(mSelectedImageUri.getLastPathSegment());
photoRef.putFile(mSelectedImageUri)
.addOnSuccessListener(this, new OnSuccessListener<UploadTask.TaskSnapshot>() {
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
// When the image has successfully uploaded, we get its download URL
Log.d("ADMIN_ACTIVITY", "Called");
Uri downloadUrl = taskSnapshot.getDownloadUrl();
assert downloadUrl != null;
String imageUrl = downloadUrl.toString();
Clothing clothing = new Clothing(imageUrl, title, mCategory);
mClothingRepository.addClothing(clothing);
}
});
When the app is ran and I add a clothing item from the admin part of the app, the image is indeed added to the firebase storage, however the Log call in the last code snippet is not called. Surely if the image is added then the onSuccess listener should be called and then the addClothing method should be ran.
Why is the onSuccess listener not being called and am I saving to the real time database correctly?
You are using the activity-scoped form of addOnSuccessListener(). The documentation notes that:
The listener will be automatically removed during onStop()
The most likely explanation for the listener not being called is that the activity passed as the first argument (this) has completed and its onStop() method called. To confirm that this is the case, remove the this argument and see if the listener is called.
Related
FirebaseDatabase fb = FirebaseDatabase.getInstance();
DatabaseReference IDrefs = fb.getReference("ID_Numbers");
IDrefs.addListenerForSingleValueEvent(new ValueEventListener(){
String name;
#Override
public void onDataChange(#NotNull DataSnapshot shot){
Toast toasty = Toast.makeText(getApplicationContext(),"name",Toast.LENGTH_LONG);
toasty.show();
for(DataSnapshot ds : shot.getChildren()) {
name = ds.child("First_Name").getValue(String.class);
}
TextView txtName = findViewById(R.id.lblName);
txtName.setText(name);
}
#Override
public void onCancelled(#NotNull DatabaseError err){
throw err.toException();
}
});
Hi so I am new to firebase in general. I am trying to read data from the real time database when the application loads in. This code works sometimes. For some reason the ValueEventListener does not run and the results come out as blank. What I want it to do is extract the First_Name fields value from my database to display it in my application. There are no errors provided it just doesn't seem to work.
Image of my firebase database
EDIT:
So its working now turns out I was using the wrong event listener
I was using addListenerForSingleValueEvent not addValueEventListener. The former calls the values from the devices local cache instead of going straight to the database (At least that is what I can understand from the documentation) while the latter goes straight to firebase to get the data. It works now consistently. With no issues from what I can see.
I have been working on getting my database backing up to work and I have reached a point where I am not sure what to do.
Basically at first the application opens a Login activity, the user logs in and their database file (if it exists) is downloaded from the Firebase Storage, and then the application navigates to the MainActivity.
In the MainActivity I call a method that sends the user's database file to Firebase Storage. I tried to manage the process by closing the database but since i couldn't fix an error of "E/ROOM: Invalidation tracker is initialized twice :/.", then I found an answer to use a checkpoint (Backup Room database). Now I implemented the forced checkpoint method.
(MarkerDao)
#RawQuery
int checkpoint(SupportSQLiteQuery supportSQLiteQuery);
(MarkerRepository)
public void checkPoint(){
Thread thread= new Thread(() -> markerDao.checkpoint(new SimpleSQLiteQuery("pragma wal_checkpoint(full)")));
thread.start();
}
(ViewModel)
public void setCheckpoint(){
repository.checkPoint();
}
(Database back-up method in the MainActivity)
private void copyDbToFirebase(){
String currentDBPath = "/data/data/"+ getPackageName() + "/databases/locations_table";
File dbBackupFile = new File(currentDBPath);
if (dbBackupFile.exists()){
markerViewModel.setCheckpoint();
// create file from the database path and convert it to a URI
Uri backupDB = Uri.fromFile(new File(currentDBPath));
// Create a StorageReference
StorageReference dbReference = storageRef.child("users").child(userId).child("user database").child("locations_table");
// Use the StorageReference to upload the file
if (userId != null){
dbReference.putFile(backupDB).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
Log.d(TAG, "onSuccess: "+4 + taskSnapshot);
Toast.makeText(getApplicationContext(), "Database copied to Firebase 4", Toast.LENGTH_LONG).show();
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.d(TAG, "onFailure: "+ e.getMessage());
}
});
}
}
}
If the user logs out, then the files in the "/data/data/"+ getPackageName() + "/databases/" are deleted, which I have manually confirmed by looking at the databases folder of the application.
My issue is that after the databases are deleted and a new user logs in, then the previous database data remains but when I manually check the app's data folder, then the /databases/ folder shows that the files were deleted and a new file is created but it doesn't show any WAL or SHM files and also I get the data of another database which is created when the application first runs, but that file is also not shown in the databases/ folder.
Can anyone explain why the folder doesn't show the files that should be present, where is the application getting the data that was deleted and how to fix it.
Edit: My application has multiple Room databases and I just realized that all the data is still readable after the files were deleted.
The method to delete the database files
private boolean deleteDatabaseFiles(File path) {
if(path.exists() ) {
File[] files = path.listFiles();
for(int i=0; i<files.length; i++) {
if(files[i].isDirectory()) {
deleteDatabaseFiles(files[i]);
}
else {
files[i].delete();
}
}
}
return true;
}
If you are using the same exact RoomDatabase object simply building another one over the same object will prevent any hold over cached data from showing up. I've tested this using multiple database swaps large and small and there is no bleed over.
If you are using a new Instance of the RoomDatabase object for every login try closing the old one after the user logs out. Room will typically close when not needed but if you need it to happen immediately, manually closing it is your best bet.
roomDb.getOpenHelper().close();
I am using File System Storage adapter to save uploaded files on the parse server.
In my app each user can have profile photo. when the user wants to change his photo, the old one should be deleted from the server. But the old image remains unchanged. It leads to fill the server storage after some time. Here is my code:
public void update (Uri uri)
{
ParseUser user = ParseUser.getCurrentUser();
if(uri!=null){
InputStream iStream=getContentResolver().openInputStream(uri);
byte[]image=Helper.getBytes(iStream);
ParseFile file=new ParseFile("profile.png",image);
file.saveInBackground();
user.put("photo",file);
user.saveInBackground();
}
}
Unfortunately Android SDK does not have a function to delete the file but you can do that using Cloud Code Functions or maybe a trigger. Something like this should solve your problem:
Parse.Cloud.beforeSave('_User', ({ original, object }) => {
if (original.get('photo').url() !== object.get('photo').url()) {
original.get('photo').destroy();
}
});
You should propably delete the line "file.saveInBackground();".
Because its runs in background. And when you put that file in user object saving file is not complete and parse server will upload same file to server again with the user object. and You will end having two duplicate files.
Change your code to this:
public void update (Uri uri)
{
ParseUser user = ParseUser.getCurrentUser();
if(uri!=null){
InputStream iStream=getContentResolver().openInputStream(uri);
byte[]image=Helper.getBytes(iStream);
ParseFile file=new ParseFile("profile.png",image);
user.put("photo",file);
user.saveInBackground();
}
}
With this code you upload file only once
I want to get the Download Url from uploadTask.addOnProgressListener method of Firebase. How can I get the Download Url using following code?
UploadTask uploadTask = storageRef.putBytes(data);
uploadTask.addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>()
{
#Override
public void onProgress(UploadTask.TaskSnapshot taskSnapshot)
{
Log.d("aaaaasessin",""+taskSnapshot.getTask().getResult());
}
});
I used taskSnapshot.getTask().getResult() but that is not working.
Edit Aug 22th 2019:
There is a new method recently added to StorageReference's class in the Android SDK named list().
To solve this, you need to loop over the ListResult and call getDownloadUrl() to get the download URLs of each file. Remember that getDownloadUrl() method is asynchronous, so it returns a Task object. See below for details. I have even written an article regarding this topic called:
How to upload an image to Cloud Storage and save the URL in Firestore?
In order to get the download url, you need to use addOnSuccessListener, like in the following lines of code:
uploadTask.addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
storageRef.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
String url = uri.toString();
//Do what you need to do with url
}
});
}
});
As in the Firebase release notes on May 23, 2018 is mentioned that:
Cloud Storage version 16.0.1
Removed the deprecated StorageMetadata.getDownloadUrl() and UploadTask.TaskSnapshot.getDownloadUrl() methods. To get a current download URL, use StorageReference.getDownloadUr().
So now when calling getDownloadUrl() on a StorageReference object it returns a Task object and not an Uri object anymore.
Please also rememeber, neither the success listener nor the failure listener (if you intend to use it), will be called if your device cannot reach Firebase Storage backend. The success/failure listeners will only be called once the data is committed to, or rejected by the Firebase servers.
I am developing an app in which i have an integrated google drive. I want to store images captured by the device under a folder in google drive.
By doing so in result.getstatus() method from google service is returning {statusCode=Failed to retrieve item from a network}
I am using following function,
final ResultCallback<DriveIdResult> idCallback = new ResultCallback<DriveIdResult>() {
#Override
public void onResult(DriveIdResult result) {
System.out.println("result.getStatus()----"+ result.getStatus());
System.out.println("result.getStatus() code----"+ result.getStatus().getStatusCode());
if (!result.getStatus().isSuccess()) {
showMessage("Cannot find DriveId. Are you authorized to view this file?");
return;
}
DriveFolder folder = Drive.DriveApi
.getFolder(getGoogleApiClient(), result.getDriveId());
MetadataChangeSet changeSet = new MetadataChangeSet.Builder()
.setTitle("NewFolder").build();
folder.createFolder(getGoogleApiClient(), changeSet)
.setResultCallback(createFolderCallback);
}
};
In first println---> I am getting {statusCode=Failed to retrieve item from a network}
In second println--> I am getting 7
Please help me...
I have the same status code when the file is permanently deleted. Remove any cached DriveId / resource id and create the new file.