I try to make an storage where i can save my image in firebase storage but everytime i upload a new image it will replace the old one,i want evertime a new image will be save on storage,i am on android studio using kotlin,Is my code is wrong?here is my code
class Activity2 : AppCompatActivity() {
var curFile: Uri? = null
val imageRef = Firebase.storage.reference
private val userCollection = Firebase.firestore.collection("persons")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity2)
//here where a button to get an image from gallery
tvpilihfoto.setOnClickListener {
Intent(Intent.ACTION_GET_CONTENT).also {
it.type = "image/*"
val REQUEST_CODE_IMAGE_PICK = 0
startActivityForResult(it, REQUEST_CODE_IMAGE_PICK)
}
//this button for an upload activity to send the image to database firebase
btnupload.setOnClickListener {
uploadImageToStorage("my image")
}
}
private fun uploadImageToStorage(filename : String) = CoroutineScope(Dispatchers.IO).launch {
try {
curFile?.let {
imageRef.child("images/$filename").putFile(it).await()
withContext(Dispatchers.Main) {
Toast.makeText(this#Activity2,"Foto anda telah dipilih",
Toast.LENGTH_LONG).show()
}
}
} catch (e : Exception) {
withContext(Dispatchers.Main) {
Toast.makeText(this#Activity2,e.message,Toast.LENGTH_LONG).show()
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
val REQUEST_CODE_IMAGE_PICK = 0
if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_CODE_IMAGE_PICK) {
data?.data?.let {
curFile = it
ivfoto.setImageURI(it)
//this where my image get or display in app
}
}
}
}
Since you're always calling uploadImageToStorage("my image"), the image will alway be called my image. So each time you make that call, it will overwrite the previous my image in storage.
To always add a new image, generate a unique filename in your code. For example:
uploadImageToStorage(UUID.randomUUID().toString())
Related
I'm new to android development and I've been building an app for studies purposes that is supposed to display one of the images selected from the gallery previously in a recyclerview.
private fun configDocImageDialog(pathGallery: Int, pathCamera: Int) {
MaterialAlertDialogBuilder(requireContext())
.setTitle(getString(R.string.camera_or_gallery))
.setMessage(getString(R.string.image_path))
.setPositiveButton(getString(R.string.gallery)) { _, _ ->
val intent = Intent()
intent.type = "image/*"
intent.action = Intent.ACTION_GET_CONTENT
startActivityForResult(Intent.createChooser(intent, "Select: "), pathGallery)
}.setNegativeButton(getString(R.string.camera)) { _, _ ->
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
startActivityForResult(Intent.createChooser(intent, "Take: "), pathCamera)
}.setNeutralButton(getString(R.string.cancel)) { dialog, _ ->
dialog.dismiss()
}.show()
}
Not I'm not worried about the camera result.
Then receiving the result as:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if(resultCode == RESULT_OK) {
val selectedImage = data!!.data
val pathImage = selectedImage.toString()
try {
when (requestCode) {
GALLERY_1 -> {
binding.imageDoc1.setImageURI(selectedImage)
}
CAMERA_1 -> {
binding.imageDoc1.setImageURI(selectedImage)
}
GALLERY_2 -> {
binding.imageDoc2.setImageURI(selectedImage)
}
CAMERA_2 -> {
binding.imageDoc2.setImageURI(selectedImage)
}
GALLERY_3 -> {
binding.imageDoc3.setImageURI(selectedImage)
}
CAMERA_3 -> {
binding.imageDoc3.setImageURI(selectedImage)
}
}
imageList.add(pathImage)
} catch (e: Exception){
e.printStackTrace()
}
}
}
I received as a result from the intent a list with this kind of content:
content://com.android.providers.media.documents/document/image%3A20
And those are saved into the database, the list of paths. /
Is it possible to use this path to my exhibit the image in my adapter? I've been trying different treatments but it always blank.
I've trying to use Picasso as:
override fun onBindViewHolder(holder: DocViewHolder, position: Int) {
val doc = docs[position]
holder.binding.apply {
Picasso.get()
.load(doc.docImageList[0])
.into(imageDoc)
textDocName.text = doc.title
textValidity.text = doc.validity
}
holder.itemView.setOnClickListener {
onItemClickListener?.let {
it(doc)
}
}
}
I want to display an image from internal storage in a recyclerview but the image is always blank.
Any ideas how to do it properly? Thanks
I try to make an Export Function for my App, that can export(and later Import) data to a txt-file in the shared storage. I use the ACTION_OPEN_DOCUMENT_TREE to choose a Folder and get "resultdata: Intent?" back.
For explanation in the Downloads-folder/Documents-Folder there is a "myApp"-folder. The user gave permission for that folder. So i get an Intent? with the path to this place back
How can i use that to create a "Spells.txt" in said folder without ACTION_CREATE_DOCUMENT
Edit: Thanks to blackapps, I've found DocumentFile, which helped create and fill the File. Here are the relevant parts of my Code so far:
lateinit var permissedFolder: Intent
in onCreate
permissiontest_btn_Choose_Permission.setOnClickListener(){chooseFolder()}
permissiontest_btn_createFile.setOnClickListener(){createFile()}
fun chooseFolder(){
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply {
}
startActivityForResult(intent, 100)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
super.onActivityResult(requestCode, resultCode, resultData)
if(requestCode==100 && resultCode== RESULT_OK){
if (resultData != null) {
permissedFolder = resultData
}
fun createFile() {
if(permissedFolder.data != null) {
val folderUri:Uri = permissedFolder.data!!
val enabledDirectory:DocumentFile= DocumentFile.fromTreeUri(this, folderUri)!!
val spellsExportDF =enabledDirectory.createFile(".txt","Spells.txt")
val spellsExportURI = spellsExportDF?.uri
if(spellsExportURI != null) {
val fileOutputStream = getContentResolver().openOutputStream(spellsExportURI)
//FileOutputStream(spellsExportURI, true)
fileOutputStream.use { fileout ->
fileout?.writer(Charsets.UTF_8)?.use {
it.write(test)
it.flush()
it.close()
}
}
val readfile = spellsExportDF.canRead()
val writefile =spellsExportDF.canWrite()
Toast.makeText(this, "can Read: $readfile", Toast.LENGTH_SHORT).show()
Toast.makeText(this, "can Write: $writefile", Toast.LENGTH_SHORT).show()
}
I am trying to learn Kotlin and I'm building a simple example as I go. I have 3 image buttons that open the camera and take a photo. The thumbnail is then set into an ImageView. I've used the examples from https://developer.android.com/training/camera/photobasics?hl=en to get the basics working (figuring if I can make it work for one, it'll work for all. It does indeed work for one, but I can't figure out how to make it one function that drops the thumbnail into the correct ImageView.
Inside my onCreate I have the listener for each of the buttons that will invoke the camera:
camRead1.setOnClickListener {dispatchTakePictureIntent() }
camRead2.setOnClickListener {dispatchTakePictureIntent() }
camRead3.setOnClickListener {dispatchTakePictureIntent() }
And I took the sample from the url above:
val REQUEST_IMAGE_CAPTURE = 1
private fun dispatchTakePictureIntent() {
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
try {
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)
} catch (e: ActivityNotFoundException) {
// display error state to the user
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
val thumb: ImageView = findViewById(R.id.thumbRead1)
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
val imageBitmap = data.extras.get("data") as Bitmap
thumb.setImageBitmap(imageBitmap)
}
}
and pasted it into my class MainActivity, and after I replaced imageView in the override function with a variable (thumb) and added the super, it worked perfectly for the first one.
However, I am trying to get 3 photos, read1, read2, and read3 which each need to display the thumb in thumbRead1, thumbRead2 and thumbRead3. I can't figure out how the onActivityResult is executed since the call inside dispatchTakePictureIntent is calling startActivityForResult (especially as Android Studio says that startActivityForResult is deprecated).
Obviously, once onActivityResult executes, I can see that thumb defines R.id.thumbRead1 and receives imageBitmap but I don't understand how I can make it aware of the button that was clicked.
Without understanding how onActivityResult is called, I'm thinking that if I can do something like:
findViewById(R.id("thumbRead" + imgID))
to define the specific ImageView that I want the photo pasted into. Am I on the right track here? If not, what is the recommended way of doing this?
Note they've recently added what's supposed to be a cleaner way of starting other activities for results and getting the results, explained here. But since you're already doing it the traditional way, I'll explain how to get that working.
I think the easiest thing to do in this situation is just make more request codes, so you can check which request it was.
val REQUEST_IMAGE_CAPTURE_SOURCE_1 = 1
val REQUEST_IMAGE_CAPTURE_SOURCE_2 = 2
val REQUEST_IMAGE_CAPTURE_SOURCE_3 = 3
//...
camRead1.setOnClickListener { dispatchTakePictureIntent(REQUEST_IMAGE_CAPTURE_SOURCE_1) }
camRead2.setOnClickListener { dispatchTakePictureIntent(REQUEST_IMAGE_CAPTURE_SOURCE_2) }
camRead3.setOnClickListener { dispatchTakePictureIntent(REQUEST_IMAGE_CAPTURE_SOURCE_3) }
//...
private fun dispatchTakePictureIntent(requestCode: Int) {
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
try {
startActivityForResult(takePictureIntent, requestCode)
} catch (e: ActivityNotFoundException) {
// display error state to the user
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode != RESULT_OK) {
// possibly show message to user
return
}
val imageViewId = when (requestCode) {
REQUEST_IMAGE_CAPTURE_SOURCE_1 -> R.id.thumbRead1
REQUEST_IMAGE_CAPTURE_SOURCE_2 -> R.id.thumbRead2
REQUEST_IMAGE_CAPTURE_SOURCE_3 -> R.id.thumbRead3
}
val imageView = findViewById<ImageView>(imageViewId)
imageView.imageBitmap = data.extras.get("data") as Bitmap
}
By the way, if you want to get an ID for a view using the String like you were showing you were trying, you would do it like this:
val viewId = resources.getIdentifier("thumbRead$imgId", "id", packageName)
val imageView = findViewById<ImageView>(viewId)
You need to pass different request code for each call and pass it to the dispatchTakePictureIntent function. You do not need to get id by findviewbyid. You simply can add the image on the basis of the request code.
val REQUEST_IMAGE_CAPTURE_ONE = 1
val REQUEST_IMAGE_CAPTURE_TWO = 2
val REQUEST_IMAGE_CAPTURE_THREE = 3
private fun dispatchTakePictureIntent(requestCode: Int) {
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
try {
startActivityForResult(takePictureIntent, requestCode)
} catch (e: ActivityNotFoundException) {
// display error state to the user
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK) {
val imageBitmap = data.extras.get("data") as Bitmap
if (requestCode == REQUEST_IMAGE_CAPTURE_ONE ) {
thumbRead1.setImageBitmap(imageBitmap)
}else if (requestCode == REQUEST_IMAGE_CAPTURE_TWO ) {
thumbRead2.setImageBitmap(imageBitmap)
}else if (requestCode == REQUEST_IMAGE_CAPTURE_THREE ) {
thumbRead3.setImageBitmap(imageBitmap)
}
}
}
can you help me., ?
I am new in develop Android use kotlin, and still learning.,
this my code on Fragment.,
......
private fun takePhotoFromCamera() {
Dexter.withActivity(requireActivity())
.withPermissions(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.CAMERA
)
.withListener(object : MultiplePermissionsListener {
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
// Here after all the permission are granted launch the CAMERA to capture an image.
if (report!!.areAllPermissionsGranted()) {
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
intent.putExtra("Document", 2)
startActivityForResult(intent, CAMERA)
}
}
override fun onPermissionRationaleShouldBeShown(
permissions: MutableList<PermissionRequest>?,
token: PermissionToken?,
) {
showRationalDialogForPermissions()
}
}).onSameThread()
.check()
}
private fun choosePhotoFromGallery() {
Dexter.withActivity(activity)
.withPermissions(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
.withListener(object : MultiplePermissionsListener {
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
// Here after all the permission are granted launch the gallery to select and image.
if (report!!.areAllPermissionsGranted()) {
val galleryIntent = Intent(
Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
)
galleryIntent.putExtra("Document", 2)
startActivityForResult(galleryIntent, GALLERY)
}
}
override fun onPermissionRationaleShouldBeShown(
permissions: MutableList<PermissionRequest>?,
token: PermissionToken?,
) {
showRationalDialogForPermissions()
}
}).onSameThread()
.check()
}
and this onActivityResult from parent Activity for Fragment
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
for (fragment in supportFragmentManager.fragments) {
fragment.onActivityResult(requestCode, resultCode, data)
}
}
And this OnActivityResult from Fragment
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK) {
if (requestCode == GALLERY) {
if (data != null) {
val contentURI = data.data
try {
// Here this is used to get an bitmap from URI
#Suppress("DEPRECATION")
val selectedImageBitmap =
MediaStore.Images.Media.getBitmap(requireActivity().contentResolver,
contentURI)
// TODO (Step 3 : Saving an image which is selected from GALLERY. And printed the path in logcat.)
// START
val saveImageToInternalStorage =
saveImageToInternalStorage(selectedImageBitmap)
Log.i("Saved Image : ", "Path :: $saveImageToInternalStorage")
// END
binding.btnNpwpCaptureAgain.visibility=View.VISIBLE
binding.ivPvNpwp.foreground.clearColorFilter()
binding.cvNpwp.visibility=View.GONE
binding.btnCaptureNpwp.visibility=View.GONE
binding.ivNpwpPreview.setImageBitmap(selectedImageBitmap) // Set the selected image from GALLERY to imageView.
} catch (e: IOException) {
e.printStackTrace()
Toast.makeText(requireActivity(), "Failed!", Toast.LENGTH_SHORT).show()
}
}
} else if (requestCode == CAMERA) {
val thumbnail: Bitmap = data!!.extras!!.get("data") as Bitmap // Bitmap from camera
// TODO (Step 4 : Saving an image which is selected from CAMERA. And printed the path in logcat.)
// START
val saveImageToInternalStorage =
saveImageToInternalStorage(thumbnail)
Log.i("Saved Image : ", "Path :: $saveImageToInternalStorage")
//binding.btnCaptureKtp.text = getString(R.string.regist_step_2_KTP_retake).toString()
// END
binding.btnNpwpCaptureAgain.visibility=View.VISIBLE
binding.ivPvNpwp.foreground.clearColorFilter()
binding.btnCaptureNpwp.visibility=View.GONE
binding.cvNpwp.visibility=View.GONE
binding.ivNpwpPreview.setImageBitmap(thumbnail) // Set to the imageView.
}
} else if (resultCode == Activity.RESULT_CANCELED) {
Log.e("Cancelled", "Cancelled")
}
//
}
My Problem is why this block is executed, but nothing happend ??
....
binding.btnNpwpCaptureAgain.visibility=View.VISIBLE
binding.ivPvNpwp.foreground.clearColorFilter()
binding.btnCaptureNpwp.visibility=View.GONE
binding.cvNpwp.visibility=View.GONE
binding.ivNpwpPreview.setImageBitmap(thumbnail)
......
Thank you for respond my question.,
Try with putting another null check for "contentURI". Like :-
if(contentURI != null){
try {
// Here this is used to get an bitmap from URI
#Suppress("DEPRECATION")
val selectedImageBitmap =
MediaStore.Images.Media.getBitmap(requireActivity().contentResolver,
contentURI)
// TODO (Step 3 : Saving an image which is selected from GALLERY. And printed the path in logcat.)
// START
val saveImageToInternalStorage =
saveImageToInternalStorage(selectedImageBitmap)
Log.i("Saved Image : ", "Path :: $saveImageToInternalStorage")
// END
binding.btnNpwpCaptureAgain.visibility=View.VISIBLE
binding.ivPvNpwp.foreground.clearColorFilter()
binding.cvNpwp.visibility=View.GONE
binding.btnCaptureNpwp.visibility=View.GONE
binding.ivNpwpPreview.setImageBitmap(selectedImageBitmap) // Set the selected image from GALLERY to imageView.
} catch (e: IOException) {
e.printStackTrace()
Toast.makeText(requireActivity(), "Failed!", Toast.LENGTH_SHORT).show()
}
}
As onActivityResult() method is deprecated, its better to use registerForActivityResult(). Like below :
private val startForResultToLoadImage = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult ->
if (result.resultCode == Activity.RESULT_OK) {
try {
val selectedImage: Uri? = result.data?.data
if (selectedImage != null){
// From Gallery
// Use uri to get the image
}else{
// From Camera code goes here.
// Get the bitmap directly from camera
val bitmap: Bitmap = result.data?.extras?.get("data") Bitmap
}
} catch (error: Exception) {
Log.d("log==>>", "Error : ${error.localizedMessage}")
}
}
}
For gallery call it like:
val intent = Intent (Intent.ACTION_PICK,MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
startForResultToLoadImage.launch(intent)
For camera call it like:
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
intent.putExtra(MediaStore.EXTRA_OUTPUT, it)
startForResultToLoadImage.launch(intent)
I believe you should:
Print log at the start of the function with all of the parameters printed to always know how the code will branch. Something like Log.i("onActivityResult: ", "requestCode=" + requestCode + “, resultCode=” + resultCode + “, data=” + data);
Check your request code before you check result code since different requests may have different results.
You’re assuming the result would be either Activity.RESULT_CANCELED or Activity.RESULT_OK but the result code might be a custom result, so please add another else branch after you check Activity.RESULT_CANCELED to be sure you’re covering all results.
Don’t call Fragment.onActivityResult from Activity.onActivityResult if your activity inherits from AppCompatActivity. Activity automatically forward the result to fragments (it even allows request code duplication across fragments without mixing the fragments).
The structure of onActivityResult should be mainly:
if (requestCode == REQUEST_1) {
if (resultCode == RESULT_1) {
// Do your thing
} else if (resultCode == RESULT_2) {
// Do your thing
} else if (resultCode == RESULT_LAST) {
// Do your thing
} else {
// Important!! Expect the unexpected
}
} else if (requestCode == REQUEST_2) {
...
} else if (requestCode == REQUEST_LAST) {
...
}
I would use switch-case instead if-else but it’s you code style so I won’t judge :)
This question already has answers here:
Android Kotlin: Getting a FileNotFoundException with filename chosen from file picker?
(5 answers)
Create a file from a photo URI on Android
(1 answer)
Closed 2 years ago.
I want to upload a logo picked in gallery to our api via multipart.
I am using multipartFile method from the networking library witch take a File in parameter: uploading a file to server
The File object can take an Uri as constructor.
With the uri received from the gallery return, i can display the image in a ImageView, but the uri or uri.path cause FileNotFoundException when passed in FileConstructor. (internet, read, write permissions are declared in manifest)
there is all code concerning this feature:
//selected image uri
private var imageUri: Uri? = null
set(value) {
field = value
field?.let { //value after picking image is : content://com.android.providers.media.documents/document/image%3A25
uploadImageFile(imageUri= it,
route = "uploadImageRoute/",
onProgression = { progress ->
Log.d("upload", "progress= $progress")
},
onSuccess = {
Log.d("upload", "upload success !")
},
onError = { errorMessage ->
Log.d("upload", "error= $errorMessage")
})
}
}
//select image button clicked, go to image gallery to pick an image
override fun onClick(v: View?) {
val intent = Intent()
intent.type = "image/*"
intent.action = Intent.ACTION_GET_CONTENT
startActivityForResult(Intent.createChooser(intent, "Select Picture"), 0)
}
//comeback from image gallery
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 0 && resultCode == Activity.RESULT_OK && data != null) {
val selectedPhotoUri = data.data!!
imageUri = selectedPhotoUri
}
}
//prepare request headers
private fun configureHeaders(): MutableMap<String,Any> {
var headerMap = mutableMapOf<String, Any>()
headerMap["Content-Type"] = "multipart/form-data"
headerMap["Accept"] = "application/json, text/plain"
return headerMap
}
private fun uploadImageFile(imageUri: Uri, route: String, onProgression: (Double) -> Unit, onSuccess: () -> Unit, onError: (String?) -> Unit) {
val headers = configureHeaders()
var file = File(imageUri.path)
AndroidNetworking.upload("https://api.ourDomain.com/$route")
.addMultipartFile("file", file)
.addHeaders(headers)
.build()
.setUploadProgressListener { uploaded, total ->
val percentage = 100 * uploaded / total as Double
onProgression(percentage)
}
.getAsJSONObject(object : JSONObjectRequestListener {
override fun onResponse(response: JSONObject?) {
onSuccess()
}
override fun onError(anError: ANError?) {
onError(anError.toString())
}
})
}
How to get the real path to the file to put in parameter of File constructor ?