How to store multiple images in one document(Firestore) Android - android

User should be able to upload multiple images in one post.
I tried to add all urls to a ArrayList and then to store them to firestore.
All I get are errors.
"imageList" returns always null
Here is my code:
fun uploadPost(images:ArrayList<Uri>, imageCount: Int, description:String){
images.forEach { image->
val imageRef = storageReferenence.child(System.currentTimeMillis().toString()
+"."+ image.lastPathSegment)
val uploadTask = imageRef.putFile((image))
uploadTask.addOnSuccessListener {
val downloadUrl = imageRef.downloadUrl
downloadUrl.addOnSuccessListener {uri->
Log.d("IMAGES", uri.toString())
imageList!!.add(uri.toString())
count++
}
}
}
//firebaseRepository.firestoreDB.collection("post").document(firebaseRepository.userid.toString()).update(post)
}
You can see that the Log has the url but when I try to add it to the imageList
it fails to do so.
THIS CAUSES THE ERROR: imageList!!.add(uri.toString())
ERROR MSG: AddViewModel$uploadPost$$inlined$forEach$lambda$1$1.onSuccess
I don`t really know what is better to store the images as an array or to store each image like this: image1:url... , image2: url..
I need them to be part of the same document.

Related

Firebase Storage. Is it possible to parallelize queries when upload an image?

I want to upload user avatar into Firebase Storage. When I do this, I remove all previous avatars.
Also I need to keep user updated with my local storage and Realtime Database.
Is it possible to do it in faster way?
override suspend fun uploadImage(uri: Uri) = withContext(dispatchers.io) {
val user = remoteRepository.getUser() // I do several parallel queries when save edited user info
clearPreviousImages(user.id) // so, I guess, I need remote user below
val fileName = "${user.id}/${uri.lastPathSegment}"
val uploadReference = referencesRepository.getImagesStorageReference().child(fileName)
uploadReference.putFile(uri).await()
val link = uploadReference.downloadUrl.await().toString()
val updatedUser = user.copy(avatar = link) // save image url in Realtime Database
remoteRepository.updateUser(updatedUser) // and return updated user
}
private suspend fun clearPreviousImages(userId: String) {
referencesRepository.getImagesStorageReference().child(userId).listAll().await()
.items
.forEach { it.delete().await() }
}
If I try to put clearPreviousImages in async block and remove await() inside forEach, I get the following error
Task is not yet complete
Can I speed up the upload?

why is my image not showing in recyclerview?

I followed a tutorial on youtube on how to retrieve images and text from Firestore and display them in the RecyclerView. I'm using the Glide library to display captured images. I bind my image using this code:
override fun onBindViewHolder(holder: itemViewHolder, position: Int) {
val produk=listOfItem[position]
holder.kategori.text=produk.productCategory
holder.berat.text=produk.productWeight.toString()
//img
Glide.with(context)
.load(produk.productIcon)
.into(holder.gambarBarang)
}
I try to use FirebaseStorage references:
val storage = FirebaseStorage.getInstance()
val gsReference = storage.getReferenceFromUrl(produk.productIcon.toString())
Glide.with(context)
.load(produk.productIcon)
.into(holder.gambarBarang)
but that seems to make the situation even worse, i get this error:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.b1, PID: 8300
java.lang.IllegalArgumentException: The storage Uri could not be
parsed.
I also noticed that some of the images that I put in the imageView are not visible. Is this a result of the inserted image being too large? Anyone know how to solve it?
Edit: I try to log the produk.productIcon.toString() inside the onBindViewHolder, and get this:
D/TAG: com.google.firebase.storage.UploadTask$TaskSnapshot#7e89f3c
gggg
D/TAG: com.google.firebase.storage.UploadTask$TaskSnapshot#213e98e
gggg
D/TAG: com.google.firebase.storage.UploadTask$TaskSnapshot#df9e78f
I think the UploadTask come from the code that i use for adding the image to Firebase Storage:
val filePathAndName="product_images/"+""+timeStamp
val storageReference=FirebaseStorage.getInstance().
getReference(filePathAndName)
val uploadTask= storageReference.putFile(image_Uri!!)
.addOnCompleteListener { task ->
if (task.isSuccessful) {
val downloadUri = task.result
val item = Item(
""+firebaseAuth.uid,
timeStamp,
kategori,
berat_sampah.toDouble(),
deskripsi,
""+downloadUri,
)
FirestoreClass().addItem(this#AddProductActivity, FirestoreClass().getCurrentUserID(),item)
ClearData()
Is this code the cause of the error?
produk.productIcon is not an URL, in fact, it is a UploadTask.TaskSnapshot which is why it can neither be parsed as a storage reference nor as an image URL. While I don't yet understand where you are getting the UploadTask from(it's best if you make the changes there), I'd suggest you use getDownloadUrl to get a Task which will give you the URL you need to pass to Glide.
This is how it should look:
val storage = FirebaseStorage.getInstance()
storage.getReference(YOUR_STORAGE_PATH).getDownloadUrl()
.addOnSuccessListener(OnSuccessListener() {
// onSuccess method call
Glide.with(context)
.load(URL FROM LISTENER)
.into(holder.gambarBarang)
}
)
So based on #Abdullah Z Khan answer, i notice that the problem is with my image uri. I use task.getResult to get the uri, but it give me taskSnapShot instead.

Reading custom metadata from Firebase storage using Kotlin (Android)

I'm newish to Kotlin, and new to StackOverflow. This is my first question.
I'm trying to retrieve and parse metadata stored in Google Firebase storage, using Kotlin. I have successfully retrieved the file and displayed it, and am able to get a reference to the metadata using val valName = referenceName.metadata. At this point I would like to retrieve the custom metadata that is stored in that val and parse it to a string. Printing the contents of the metadata using toString() returns com.google.android.gms.tasks.taskId to the console.
I've visited the docs and used them for a lot of my project so far, they are located at:
https://firebase.google.com/docs/storage/android/file-metadata, but am stuck on what to do next.
Thanks for your help!
My code:
// create an instance of the firebase storage
val storage = FirebaseStorage.getInstance()
// create a reference to storage
val storageRef = storage.reference
// create a reference to the featured content image
val filmRef = storageRef.child("featured/film.jpg")
// place the image metadata in a val - this appears to be working
val filmMeta = filmRef.metadata
// parse metadata to a string
// ****** what to do next? ********
val filmId = filmMeta.customMetadata("id") // <--- this does not work
You should add your customMetedata in storage ref
val metadata = storageMetadata {
setCustomMetadata("id", "filmId")
}
filmRef.updateMetadata(metadata).addOnSuccessListener {
// Updated metadata is in storageMetadata
val filmId = it.getCustomMetadata("id")
}.addOnFailureListener {
}
Then you can use like this:
filmRef.metadata.addOnSuccessListener {
val filmId = it.getCustomMetadata("id")
}.addOnFailureListener {
}

Can we use firebase console to upload images manually?

In my app , I have to display images in RecyclerView from Firebase database but the problem is I don't want to upload images using my app but I want them to be manually added using console of Firebase storage and later use their location to be added in Firebase database. I tried doing this way but glide is not loading the images. So is there any way to upload images manually and load images in app ?
Edited :
enter image description here
Look at my image, I have simply added the storage location of image in my database table. After then I am using those functions to get the image location and loading them with the help of glide library.
Here is my code of retrieving categories from Firebase database.
fun getCategories() : List<Categories>{
val categoriesList = mutableListOf<Categories>()
CoroutineScope(IO).launch {
databaseReference.child("categories")
.addValueEventListener(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
for (postSnapshot in dataSnapshot.children) {
val categories = postSnapshot.getValue(Categories::class.java)
categoriesList.add(categories!!)
}
}
override fun onCancelled(p0: DatabaseError) {
}
})
}
return categoriesList
}
And after retrieving categories list ,I am loading my Images in Adapter class. Here is my Adapter class code
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val model = modelList[position]
holder.nameOfFruit?.text = model.name
holder.nameOfFruit?.setOnClickListener {
it.findNavController().navigate(R.id.action_mainFragment_to_choiceSelectedFragmentModel)
}
Glide.with(myContext!!).load(model.url).into(holder.imageOfFruit)
}
Edited : It is my image URL stored in my database.
enter image description here
You've stored a "gs://" URL in your database. This is a special Cloud Storage URL that only works with Google infrastructure. It will not work in browsers or applications.
You will have to instead store a download URL in the database. If you've done it correctly, it will start with "https://".

Android Kotlin - Firestore image upload and display

At the moment as a sample I'm recreating instagram-like post, where user can post a description and image (along with username since I'm still not configuring authentication). So far as follows I can only post username and description. Along side of that I can load new image as a source into the imageview on the screen.
My data class is:
data class Post(val username: String,
val timestamp: Date,
val postTxt: String,
val numLikes: Int,
val numComments: Int,
val documentId: String)
I put data in a hashmap as follows:
val data = hashMapOf(
NUM_LIKES to 0,
NUM_COMMENTS to 0,
POST_TXT to addPostTxt.text.toString().trim(),
TIMESTAMP to FieldValue.serverTimestamp(),
USERNAME to addUsernameTxt.text.toString().trim()
)
and then pass it to upload to firestore:
FirebaseFirestore.getInstance().collection(POST_REF)
.add(data)
.addOnSuccessListener { finish() }
.addOnFailureListener {
Log.e("Exception", "Could not add post: $it")
toast("Could not add post")
}
And to get the data I created a function which takes snapshot of type QuerySnapshot like so:
// Clear all the posts before relaod
posts.clear()
snapshot.documents.forEach { document ->
val data = document.data
val name = data?.get(USERNAME) as String
val timestamp = data[TIMESTAMP] as Date
val postTxt = data[POST_TXT] as String
val numLikes = data[NUM_LIKES] as Long
val numComments = data[NUM_COMMENTS] as Long
val documentId = document.id
val newPost = Post(name, timestamp, postTxt, numLikes.toInt(), numComments.toInt(), documentId)
posts.add(newPost)
}
postsAdapter.notifyDataSetChanged()
So far uploading text, current time of upload works fine for both upload and reading it from the database; however my question here is:
- What is the best way (following current codebase) to upload image to firestore and storage and display it accordingly in the main window (preferably using Glide or picasso)?
It's generally not a good idea to store binary data like images in Firestore. You could very easily exceed the limit for how much data you can store in a document, which is 1MB. Large documents also take more time to load on the client, which is even worse if you don't even need to use the image at the time of the read.
Instead, consider uploading the image to Cloud Storage and saving a path to that location in a field in your document. Then, when it's time to display the image, load it from there.

Categories

Resources