My goal is to add new product, for each product contain picture and pdf file to firebase storage, then save each link to firebase database.
I got a problem went upload a picture and pdf. I cant get download URL from each file and return null went I'm try post to database.
code:
private void bukafilemanager(View view) {
switch (view.getId()){
case R.id.pilih_gambar:
Intent gambar = new Intent();
gambar.setType("image/*");
gambar.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(gambar, PICK_IMAGE_REQUEST);
break;
case R.id.pilih_pdf:
Intent pdf = new Intent();
pdf.setType("application/*");
pdf.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(pdf, PICK_FILE_REQUEST);
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null && data.getData()!= null){
URI_Image = data.getData();
daftarupload.add(URI_Image);
Glide.with(this).load(URI_Image).into(preview_gambar);
preview_gambar.setImageURI(URI_Image);
} else if (requestCode == PICK_FILE_REQUEST && resultCode == RESULT_OK && data != null && data.getData()!= null){
URI_File = data.getData();
daftarupload.add(URI_File);
}
}
public String getMimeType(Context context, Uri uri) {
String extension;
//Check uri format to avoid null
if (uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
//If scheme is a content
MimeTypeMap mime = MimeTypeMap.getSingleton();
extension = mime.getExtensionFromMimeType(context.getContentResolver().getType(uri));
} else {
//If scheme is a File
//This will replace white spaces with %20 and also other special characters. This will avoid returning null values on file name with spaces and special characters.
extension = MimeTypeMap.getFileExtensionFromUrl(Uri.fromFile(new File(uri.getPath())).toString());
}
return extension;
}
protected void uploadfile(ArrayList<Uri> daftarupload){
progressDialog.setMessage("Harap Tunggu...");
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setIndeterminate(true);
progressDialog.setProgress(count);
progressDialog.setMax(daftarupload.size());
progressDialog.show();
String nama_produk = namaproduk.getText().toString();
String ket_produk = ketproduk.getText().toString();
if(!TextUtils.isEmpty(nama_produk) && !TextUtils.isEmpty(ket_produk)) {
for (Uri uri : daftarupload) {
switch (getMimeType(getBaseContext(), uri)) {
case "jpg":
final StorageReference lokasijpg = storage.child(id_produk + ".jpg");
lokasijpg
.putFile(uri)
.addOnCompleteListener(new OnCompleteListener<UploadTask.TaskSnapshot>() {
#Override
public void onComplete(#NonNull Task<UploadTask.TaskSnapshot> task) {
if (task.isComplete()){
lokasijpg
.getDownloadUrl()
.addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
URL_JPG = uri;
count += 1;
progressDialog.setProgress(count);
}
});
}
}
});
break;
case "pdf":
final StorageReference lokasipdf = storage.child(id_produk + ".pdf");
lokasipdf
.putFile(uri)
.addOnCompleteListener(new OnCompleteListener<UploadTask.TaskSnapshot>() {
#Override
public void onComplete(#NonNull Task<UploadTask.TaskSnapshot> task) {
if(task.isComplete()){
lokasipdf
.getDownloadUrl()
.addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
URL_PDF = uri;
count += 1;
progressDialog.setProgress(count);
}
});
}
}
});
break;
default:
progressDialog.dismiss();
Toast.makeText(getBaseContext(), "Format Tidak Sesuai", Toast.LENGTH_LONG).show();
break;
}
}
simpandata(id_produk, nama_produk, ket_produk , URL_JPG, URL_PDF);
progressDialog.dismiss();
} else {
progressDialog.dismiss();
Toast.makeText(tambahproduk.this,"Semua data harus diisi lengkap!", Toast.LENGTH_LONG).show();
}
}
protected void simpandata(String id_produk, final String nama_produk, String ket_produk, Uri URL_JPG, Uri URL_PDF){
produk produk = new produk(id_produk,nama_produk,ket_produk,URL_JPG.toString(),URL_PDF.toString());
database.child(id_produk).setValue(produk).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
progressDialog.dismiss();
Toast.makeText(tambahproduk.this, "Produk "+nama_produk.toString()+" Berhasil Ditambahkan", Toast.LENGTH_LONG).show();
finish();
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
progressDialog.dismiss();
Toast.makeText(tambahproduk.this, e.toString(), Toast.LENGTH_LONG).show();
}
});
}
error:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.user.katalog.lulu.user, PID: 27391
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.net.Uri.toString()' on a null object reference
at com.user.katalog.lulu.user.tambahproduk.simpandata(tambahproduk.java:237)
at com.user.katalog.lulu.user.tambahproduk.uploadfile(tambahproduk.java:226)
at com.user.katalog.lulu.user.tambahproduk$3.onClick(tambahproduk.java:102)
at android.view.View.performClick(View.java:5198)
at android.view.View$PerformClick.run(View.java:21147)
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)
According to your comment, I understand that you are getting that error because of the following line of code:
produk produk = new produk(id_produk,nama_produk,ket_produk,URL_JPG.toString(),URL_PDF.toString());
It is because you cannot create the URL_PDF varaible as a global variable and expect to work fine. You cannot use something now that hasn't been loaded yet. With other words, you cannot simply use the URL_PDF object outside the onComplete() method because it will always be null due the asynchronous behaviour of this method. This means that by the time you are trying to use that result outside that method, the data hasn't finished loading yet from the database and that's why is not accessible. A quick solve for this problem would be to use the URL_PDF varaible only inside the onComplete() method, otherwise I recommend you see the last part of my anwser from this post in which I have explained how it can be done using a custom callback. You can also take a look at this video for a better understanding.
Related
I am learning to write in java.
I registered a photo transfer method Using the Cropimage library for cropping photos. Preparing photos for transfer
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE && resultCode == RESULT_OK && data != null) {
CropImage.ActivityResult result = CropImage.getActivityResult(data);
imageUriPts = result.getUri();
} else {
Toast.makeText(this, "Произошла ошибка", Toast.LENGTH_SHORT).show();
}
}
The transfer method
private void loadImagePts() {
final ProgressDialog progressDialog = new ProgressDialog(this);
progressDialog.setTitle("Идет загрузка");
progressDialog.setMessage("Пожалуйста подождите");
progressDialog.show();
if (imageUriPts != null) {
final StorageReference fileRef = storageDeliveryPts.child(mAuth.getCurrentUser().getUid() + "jpg");
uploadTask = fileRef.putFile(imageUriPts);
uploadTask.continueWithTask(new Continuation() {
#Override
public Object then(#NonNull Task task) throws Exception {
if (!task.isSuccessful()) {
throw task.getException();
}
return fileRef.getDownloadUrl();
}
}).addOnCompleteListener(new OnCompleteListener<Uri>() {
#Override
public void onComplete(#NonNull Task<Uri> task) {
if (task.isSuccessful()) {
Uri downloadUri = task.getResult();
myUri = downloadUri.toString();
HashMap<String, Object> userMap = new HashMap<>();
userMap.put("uid", mAuth.getCurrentUser().getUid());
userMap.put("image", myUri);
PtsRef.child(mAuth.getCurrentUser().getUid()).updateChildren(userMap);
progressDialog.dismiss();
startActivity(new Intent(PTSActivity.this, HomeActivity.class));
}
}
});
}
}
There are two imageviews where photos are added and one upload button. which should launch the method of loading two photos at onсе.what does it look like visually
PtsRef is DatabaseReference MyUri is String MyUri=''
How to make it possible to post two photos with one activity?
Tried creating a second empty string but didn't work.
Here i read some input which i want to use for creating "Produs" object which i upload it to the firebase storage, then i want to retrieve it to display a list of objects, i have a problem when i want to update the path to the image storage, to retrieve it later.
public class Add extends AppCompatActivity {
DatabaseReference mDatabase;
EditText etNume, etCantitate, etPret;
Button btnSubmit, btnImage;
Uri mImage;
ImageView ivTest;
public static String path="";
StorageReference mStorageRef;
final int GALLERY_INTENT = 2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add);
mDatabase = FirebaseDatabase.getInstance().getReference();
etNume = findViewById(R.id.etNume);
etCantitate = findViewById(R.id.etCantitate);
etPret = findViewById(R.id.etPret);
btnSubmit = findViewById(R.id.btnSubmit);
btnImage = findViewById(R.id.btnImage);
ivTest =findViewById(R.id.ivTest);
mStorageRef = FirebaseStorage.getInstance().getReference();
btnImage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.setType("image/*");
startActivityForResult(i, GALLERY_INTENT);
}
});
btnSubmit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String nume, pret,cantitate;
nume = etNume.getText().toString().trim();
pret = etPret.getText().toString().trim();
cantitate = etCantitate.getText().toString().trim();
if(TextUtils.isEmpty(nume)){
etNume.setError("Email is required.");
return;
}
if(TextUtils.isEmpty(pret)){
etPret.setError("Email is required.");
return;
}
if(TextUtils.isEmpty(cantitate)){
etCantitate.setError("Email is required.");
return;
}
StorageReference file = mStorageRef.child("Produs").child(nume + ".jpg");
file.putFile(mImage).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
path += taskSnapshot.getMetadata().toString(); /// good path
Toast.makeText(Add.this, path, Toast.LENGTH_SHORT).show();
}
});
Toast.makeText(Add.this, path, Toast.LENGTH_SHORT).show();/// null path
Produs p=new Produs(nume,cantitate,pret,path);
Task task =mDatabase.child("Produs").child(nume).setValue(p);
task.addOnSuccessListener(new OnSuccessListener() {
#Override
public void onSuccess(Object o) {
Toast.makeText(Add.this, "Produsul a fost adaugat cu succes", Toast.LENGTH_SHORT).show();
startActivity(new Intent(getApplicationContext(),MainActivity.class));
}
});
task.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(Add.this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == GALLERY_INTENT && resultCode == RESULT_OK && data != null && data.getData() != null){
mImage = data.getData();
ivTest.setImageURI(mImage);
}
}
}
How to have path changed from the onSuccess method?
Basically i want to change the path after i upload an image to build " Produs " object
Also, this is the good path to the image storage? As taskSnapshot.getdownloadURL() doesn't work for me.
The problem is not where you set and read the path variable, the problem is when you do this. Since the getDownloadURL() method makes a call to the server, its onSuccess may run much later than you think.
If you're seeing the wrong value for path, it's very likely that the onSuccess that sets it hasn't run yet. The easiest way to verify that is by either setting breakpoints on the read and write and running in a debugger, or by adding some logging and checking the order of that in your logcat.
The solution for this type of problem is always the same: any code that needs the download URL, needs to either be inside onSuccess, be called from there, or be synchronized in some other way.
So in your case, move the `` into the onSuccess:
StorageReference file = mStorageRef.child("Produs").child(nume + ".jpg");
file.putFile(mImage).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
path += taskSnapshot.getMetadata().toString(); /// good path
Toast.makeText(Add.this, path, Toast.LENGTH_SHORT).show();
Toast.makeText(Add.this, path, Toast.LENGTH_SHORT).show();
Produs p=new Produs(nume,cantitate,pret,path);
Task task =mDatabase.child("Produs").child(nume).setValue(p);
task.addOnSuccessListener(new OnSuccessListener() {
...
});
task.addOnFailureListener(new OnFailureListener() {
...
});
}
});
For more on this, see:
How to store download image url in realtime database firebase android
How to store Url into ArrayList from Firebase Storage?
Can someone help me with logic of the firebase on success listener
getContactsFromFirebase() method return an empty list
Setting Singleton property value in Firebase Listener
Not all of these are directly about Cloud Storage for Firebase, but the explanation applies here as well.
To upload images to Firebase Storage I am attaching addOnSuccessListener on the instance of the StorageReference. While overriding onSuccess method I am calling getDownloadUrl() on the instance of taskSnapshot but it is giving me an error saying
Can't resolve method getDownloadUrl()
This app I had created 2 months ago, earlier this app was working fine and getDownloadUrl() was working fine as well. Also, in taskSnapshot instance when I press Ctrl+space, in the suggestions I don't find getDownloadUrl() method. Why is it happening?
Code to onActivityResult():
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == RC_SIGN_IN) {
if (resultCode == RESULT_OK) {
Toast.makeText(this, "Signed in!!!1", Toast.LENGTH_SHORT).show();
} else if (resultCode == RESULT_CANCELED) {
Toast.makeText(this, "Failed to sign in", Toast.LENGTH_SHORT).show();
finish();
}
}
else if(requestCode == RC_PHOTO_PICKER && resultCode == RESULT_OK){
Uri selectedPhoto = data.getData();
StorageReference localRefrence = storageReference.child(selectedPhoto.getLastPathSegment());
// Uploading the file on the storage
localRefrence.putFile(selectedPhoto).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
Uri downloadUrl = taskSnapshot.getDownloadUrl();
FriendlyMessage message = new FriendlyMessage(mUsername, null, downloadUrl.toString());
databaseReference.push().setValue(message);
}
});
}
}
The Firebase API has changed.
May 23, 2018
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().
UploadTask.TaskSnapshot has a method named getMetadata() which returns a StorageMetadata object.
This StorageMetadata object contains a method named getReference() which returns a StorageReference object.
That StorageReference object contains the getDownloadUrl() method, which now returns a Task object instead of an Uri object.
This Task must then be listened upon in order to obtain the Uri, which can be done asynchronously or in a blocking manner; see the Tasks API for that.
You wont get the download url of image now using
profileImageUrl = taskSnapshot.getDownloadUrl().toString();
this method is deprecated.
Instead you can use the below method
uniqueId = UUID.randomUUID().toString();
ur_firebase_reference = storageReference.child("user_photos/" + uniqueId);
Uri file = Uri.fromFile(new File(mphotofile.getAbsolutePath()));
UploadTask uploadTask = ur_firebase_reference.putFile(file);
Task<Uri> urlTask = uploadTask.continueWithTask(new Continuation<UploadTask.TaskSnapshot, Task<Uri>>() {
#Override
public Task<Uri> then(#NonNull Task<UploadTask.TaskSnapshot> task) throws Exception {
if (!task.isSuccessful()) {
throw task.getException();
}
// Continue with the task to get the download URL
return ur_firebase_reference.getDownloadUrl();
}
}).addOnCompleteListener(new OnCompleteListener<Uri>() {
#Override
public void onComplete(#NonNull Task<Uri> task) {
if (task.isSuccessful()) {
Uri downloadUri = task.getResult();
System.out.println("Upload " + downloadUri);
Toast.makeText(mActivity, "Successfully uploaded", Toast.LENGTH_SHORT).show();
if (downloadUri != null) {
String photoStringLink = downloadUri.toString(); //YOU WILL GET THE DOWNLOAD URL HERE !!!!
System.out.println("Upload " + photoStringLink);
}
} else {
// Handle failures
// ...
}
}
});
final StorageReference filePath = mImageStore.child("profile_images").child("full_image").child(userId + ".jpg");
filePath.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
//Bitmap hochladen
uploadBitMap(uri.toString());
}
});
The .getDownloadURL is no longer available and deprecated.
from the documentation Task<Uri> and getdownloadUrl();
Asynchronously retrieves a long lived download URL with a revokable token.
see documentation
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
Task<Uri> urlTask = taskSnapshot.getStorage().getDownloadUrl();
while (!urlTask.isSuccessful());
Uri downloadUrl = urlTask.getResult();
//continue with your code
The getDownloadUrl method has been depreceated. Instead use the following
taskSnapshot.getMetadata().getReference().getDownloadUrl().toString()
You should try this one. Understand it and try to implement in yours
buttonSetup.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String name = editText_name.getText().toString();
if (!TextUtils.isEmpty(name) && mainImageURI != null) {
final String user_id = firebaseAuth.getCurrentUser().getUid();
progressBar_setup.setVisibility(View.VISIBLE);
final StorageReference image_path = storageReference.child("profile_images").child(user_id + ".jpg");
UploadTask uploadTask = image_path.putFile(mainImageURI);
uploadTask.continueWithTask(new Continuation<UploadTask.TaskSnapshot, Task<Uri>>() {
#Override
public Task<Uri> then(#NonNull Task<UploadTask.TaskSnapshot> task) throws Exception {
if(!task.isSuccessful()){
throw task.getException();
}
return image_path.getDownloadUrl();
}
}).addOnCompleteListener(new OnCompleteListener<Uri>() {
#Override
public void onComplete(#NonNull Task<Uri> task) {
if (task.isSuccessful()){
Uri downloadUrl = task.getResult();
Log.i("The URL : ", downloadUrl.toString());
}
}
});
}
}
});
Try
{
firebase.storage()
.child()
.getDownloadURL().then()
}
I read different articles on how to go about it and i use a particularly easy one that i have no idea why i did not think of that in the first place, It was to loop the method that contains the function of uploading a "single image", looping it will then repeat the method according to the number of images to be uploaded, but i am finding something rather troubling here, maybe its my code or something but i have no idea why, during the loop, it loops according to the number of images alright, but when i check the firebase storage, i find just an image at the directory which is always the last image i selected, so i am thinking maybe my code deletes existing images in the directory and then save incoming images therefore deleting all previous images and leaving only the last one ( just a thought though) i am attaching my code now, i am so sorry, but i sometimes make mistakes in attaching codes, please bear with me.
The OnActivityResult method:
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == gallerypick && resultCode == RESULT_OK) {
if (data.getClipData() != null) {
Toast.makeText(this, "multiple images selected", Toast.LENGTH_SHORT).show();
count = data.getClipData().getItemCount();
for (i = 0; i < count; i++) {
imageuri = data.getClipData().getItemAt(i).getUri();
inputproductimg.setImageURI(data.getClipData().getItemAt(0).getUri());
}
} else {
if (data.getData() != null) {
Toast.makeText(this, "Single image selected", Toast.LENGTH_SHORT).show();
imageuri = data.getData();
inputproductimg.setImageURI(imageuri);
}
}
}
}
method that calls the upload image function
addproductbtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Validateproduct();
}
});
}
private void Validateproduct() {
Pname = inputproductname.getText().toString();
Pdescription = inputproductdesc.getText().toString();
Pprice = inputproductprice.getText().toString();
if (imageuri == null) {
Toast.makeText(this, "One image must be selected at least", Toast.LENGTH_SHORT).show();
} else {
if (TextUtils.isEmpty(Pname) || TextUtils.isEmpty(Pdescription) || TextUtils.isEmpty(Pprice)) {
Toast.makeText(this, "Please fill out all fields", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Images will take turns to save, Please wait...", Toast.LENGTH_SHORT).show();
for (i = 0; i < count; i++) {
storeproductinfo(imageuri, i);
}
}
}
}
and the upload image function itself
private void storeproductinfo(Uri imageuri, int i) {
Calendar calender = Calendar.getInstance();
SimpleDateFormat currentdate = new SimpleDateFormat("MMM dd, yyyy");
savecurrentdate = currentdate.format(calender.getTime());
SimpleDateFormat currenttime = new SimpleDateFormat("HH:mm:ss a");
savecurrenttime = currenttime.format(calender.getTime());
productkey = savecurrentdate + savecurrenttime;
final StorageReference filepath = Pimagesref.child(gendercategoryname).child(categoryname)
.child(Pname + productkey).child(this.imageuri.getLastPathSegment() + gendercategoryname + categoryname + productkey + ".jpg");
progressbar.setVisibility(View.VISIBLE);
final UploadTask uploadTask = filepath.putFile(this.imageuri);
filepath.putFile(this.imageuri).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
String message = e.toString();
progressbar.setVisibility(View.INVISIBLE);
Toast.makeText(newProduct.this, "Error: " + message, Toast.LENGTH_SHORT).show();
}
}).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
progressbar.setVisibility(View.INVISIBLE);
Toast.makeText(newProduct.this, "Image uploaded successfully", Toast.LENGTH_SHORT).show();
Task<Uri> urltask = uploadTask.continueWithTask(new Continuation<UploadTask.TaskSnapshot, Task<Uri>>() {
#Override
public Task<Uri> then(#NonNull Task<UploadTask.TaskSnapshot> task) throws Exception {
if (!task.isSuccessful()) {
progressbar.setVisibility(View.INVISIBLE);
throw task.getException();
}
downloadUrl = filepath.getDownloadUrl().toString();
return filepath.getDownloadUrl();
}
}).addOnCompleteListener(new OnCompleteListener() {
#Override
public void onComplete(#NonNull Task task) {
if (task.isSuccessful()) {
downloadUrl = task.getResult().toString();
progressbar.setVisibility(View.INVISIBLE);
Toast.makeText(newProduct.this, "Product Image URL has been created", Toast.LENGTH_SHORT).show();
Saveproductinfo();
}
}
});
}
});
}
maybe the upload method wasnt necessary but im only being thorough, please kindly help in pointing out my mistake(s)
Thank you.
I'm trying to upload some images to firestore storage and put the image URL to firebase database. The images are uploading successfully but the image URLs aren't being added to the database. The problem that I think might be causing this is that the image URL is being added to the Hashmap after uploading the image but the database upload process isn't waiting for the URL instead, adding all other HashMap keys to the database before the Upload task returns the URL. This way all other keys get added to the database but not the Image URLs. In the below code product id is being added successfully to the database, also if I leave any image unselected its url alse gets added as empty to the database which is working fine but if I select an image to upload, The hashmap to database upload finishes even before getting the uploaded image URL.
public class AddProductDataActivity extends AppCompatActivity {
String productId;
EditText productIdEditText;
ImageView addProductImage3;
Button addProductSubmit;
final int IMAGE3_REQUEST = 30;
Uri image3LocationPath;
StorageReference objectStorageReference;
FirebaseFirestore objectFireBaseFireStore;
Map<String, String> objectMap = new HashMap<>();
StorageReference img3Store;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_product_data);
brandNameEditText =(EditText)
addProductImage3 = (ImageView) findViewById(R.id.add_product_image3);
objectStorageReference =
FirebaseStorage.getInstance().getReference("images");
objectFireBaseFireStore = FirebaseFirestore.getInstance();
addProductImage3.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent objectIntent = new Intent();
objectIntent.setType("image/*");
objectIntent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(objectIntent, IMAGE3_REQUEST);
}
});
addProductSubmit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
productId = productIdEditText.getText().toString();
if(image3LocationPath != null)
{
final String image3Name = productId + "_image3." + getExtension(image3LocationPath);
img3Store = objectStorageReference.child(image3Name);
UploadTask imageUploadTask = img3Store.putFile(image3LocationPath);
imageUploadTask.continueWithTask(new Continuation<UploadTask.TaskSnapshot, Task<Uri>>() {
#Override
public Task<Uri> then(#NonNull Task<UploadTask.TaskSnapshot> task) throws Exception {
if(!task.isSuccessful())
{
Toast.makeText(AddProductDataActivity.this, "Task Unsuccessful", Toast.LENGTH_SHORT).show();
}
return img3Store.getDownloadUrl();
}
}).addOnCompleteListener(new OnCompleteListener<Uri>() {
#Override
public void onComplete(#NonNull Task<Uri> task) {
if(task.isSuccessful())
{
String image_3_url = task.getResult().toString();
objectMap.put("image3_url",image_3_url);
}
else
{
Toast.makeText(AddProductDataActivity.this, task.getException().toString(), Toast.LENGTH_SHORT).show();
}
}
});
}
else
{
objectMap.put("image3_url","");
}
objectFireBaseFireStore.collection("images").document(productId).set(objectMap).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Toast.makeText(AddProductDataActivity.this, "Product Added Successfully.", Toast.LENGTH_SHORT).show();
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(AddProductDataActivity.this, "Error in Adding Product. Please Try Again.\n"+e.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode){
case 30:
try
{
if(resultCode == RESULT_OK && data != null && data.getData() != null)
{
image3LocationPath = data.getData();
Bitmap objectBitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), image3LocationPath);
addProductImage3.setImageBitmap(objectBitmap);
}
}
catch (Exception e)
{
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
break;
default:
break;
}
private String getExtension(Uri uri){
try
{
ContentResolver objectContentResolver = getContentResolver();
MimeTypeMap objectMimeTypeMap = MimeTypeMap.getSingleton();
return objectMimeTypeMap.getExtensionFromMimeType(objectContentResolver.getType(uri));
}
catch (Exception e)
{
Toast.makeText(AddProductDataActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
return null;
}
}
}
Your code
objectFireBaseFireStore.collection("images").document(productId).set(objectMap)
executes before
objectMap.put("image3_url",image_3_url)
Which means when you are setting your url, your objectMap does not have the key image3_url
Try to set values to database inside onComplete() or use different workaround to set only the url.
You forgot to add your HashMap to Database Reference of Firebase.
This is reference from my current project code.
private void uploadVideo() {
StorageReference mStorageRef = FirebaseStorage.getInstance().getReference();
final StorageReference riversRef = mStorageRef.child(Constants.STORAGE_PATH + "/" + mFinalUploadUri.getLastPathSegment());
riversRef.putFile(mFinalUploadUri).continueWithTask(new Continuation<UploadTask.TaskSnapshot, Task<Uri>>() {
#Override
public Task<Uri> then(#NonNull Task<UploadTask.TaskSnapshot> task) throws Exception {
if (!task.isSuccessful()) {
throw Objects.requireNonNull(task.getException());
}
// Continue with the task to get the download URL
return riversRef.getDownloadUrl();
}
}).addOnCompleteListener(new OnCompleteListener<Uri>() {
#Override
public void onComplete(#NonNull Task<Uri> task) {
if (task.isSuccessful()) {
Uri downloadUri = task.getResult();
FirebaseFirestore database = FirebaseFirestore.getInstance();
String mSelectedCategory = binding.categorySpinner.getSelectedItem().toString();
DocumentReference newDocumentReference = database.collection(PENDING_PATH).document();
VideoModel videoModel = new VideoModel();
videoModel.setDocumentId(newDocumentReference.getId());
videoModel.setTitle(mTitle);
videoModel.setCategory(mSelectedCategory);
//videoModel.setTime(FieldValue.serverTimestamp());
videoModel.setUrl(downloadUri != null ? downloadUri.toString() : null);
newDocumentReference.set(videoModel).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
binding.progressBar.setVisibility(View.GONE);
binding.button.setVisibility(View.VISIBLE);
binding.videoView.setVisibility(View.GONE);
selectedUri = null;
Toast.makeText(AdminVideoUploadActivity.this, R.string.uploaded_successfully, Toast.LENGTH_SHORT).show();
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(AdminVideoUploadActivity.this, R.string.failed_to_upload, Toast.LENGTH_SHORT).show();
}
});
}
}
});
}
Now you can check code and find where you have done mistake. Just add lines of code of inserting in database.
Thank you.