I am currently using firebase storage to allow users to upload images.
I copied my old working java code and is trying to convert it to Kotlin but I have a mismatch issue. The error message is:
Type mismatch
Required: Uri
Found: Uri?
Here is my code.
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK && requestCode == 1046) {
try {
val imageUri : Uri? = data?.data
val imageStream: InputStream? = this.contentResolver.openInputStream(imageUri) //this is the line that errors imageUri has a mismatch error
val selectedImage = BitmapFactory.decodeStream(imageStream)
CloudStorage().upload(imageUri,
{ s ->
uploadedImageURL = s
}) { e ->
Toast.makeText(this#CreatePostActivity, e.message, Toast.LENGTH_SHORT).show()
e.printStackTrace()
}
} catch (e: FileNotFoundException) {
e.printStackTrace()
Toast.makeText(this, "file not found", Toast.LENGTH_SHORT).show()
}
}
}
Thanks!
imageUri cannot be null since openInputStream does not accept nullable values. You can fix it by only executing the code if the value is not nullable, for example:
data?.data?.let { imageUri ->
try {
val imageStream: InputStream? = this.contentResolver.openInputStream(imageUri)
val selectedImage = BitmapFactory.decodeStream(imageStream)
CloudStorage().upload(imageUri,
{ s ->
uploadedImageURL = s
}) { e ->
Toast.makeText(this#CreatePostActivity, e.message, Toast.LENGTH_SHORT).show()
e.printStackTrace()
}
} catch (e: FileNotFoundException) {
e.printStackTrace()
Toast.makeText(this, "file not found", Toast.LENGTH_SHORT).show()
}
} ?: notifyUserImageUriIsNull()
Note that you're calling super.onActivityResult() twice.
"Android Studio" shows the answers.
Related
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 :)
I am new to kotlin. I wrote this code that will get image from image picker.
But I am getting error on line:val filePath: Uri = attr.data.getData()
error: Unresolved reference. Is there any change in kotlin because this code was working properly in java (Means I migrated to kotlin)
And another error on imageStore(bitmap) error: smart cast to bitmap is impossible.
I've searched for documentation but couldn't solve this 2 problems .
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK && requestCode == 1) {
val filePath: Uri = attr.data.getData()
try {
val inputStream: InputStream? = contentResolver.openInputStream(filePath)
bitmap = BitmapFactory.decodeStream(inputStream)
imageStore(bitmap)
} catch (e: FileNotFoundException) {
e.printStackTrace()
}
}
}
But I am getting error on line:val filePath: Uri = attr.data.getData() error: Unresolved reference
Well, this means the compiler can't understand what you're referring to. Is it correct to say this ?
Well, considering you don't have any object named attr it would seem that the compiler is correct.
this means you should remove the attr part, something like:
val filePath: Uri = data?.getData() ?: return
The return here will stop executing the rest of the method if the data from the intent is null
To resolve your second problem, you'll need something like this :
bitmap?.let { bitmapInstance ->
imageStore(bitmapInstance)
}
What does this do ?
Well, it gives you thread safe access to your bitmap object and also ensures that the instance isn't null.
As #a_local_nobody said "the migration tool isn't perfect", I learned the basics of kotlin and found that the following code works fine for me.
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == 1 && resultCode == Activity.RESULT_OK && data != null) {
val filePath = data.data
try {
val inputStream = contentResolver.openInputStream(filePath!!)
bitmap = BitmapFactory.decodeStream(inputStream)
imageView!!.setImageBitmap(bitmap)
imageStore(bitmap)
} catch (e: FileNotFoundException) {
e.printStackTrace()
}
}
super.onActivityResult(requestCode, resultCode, data)
}
Replace this line val filePath: Uri = attr.data.getData() with
val filePath: Uri = data!!.getData()!!
Updated code
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK && requestCode == 1) {
val filePath: Uri = data!!.getData()!!
try {
val inputStream: InputStream? = contentResolver.openInputStream(filePath)
var bitmap = BitmapFactory.decodeStream(inputStream)
imageStore(bitmap)
} catch (e: FileNotFoundException) {
e.printStackTrace()
}
}
}
I am currently trying to save a text file inside a fragment, but I can't get it to work:
Here is the method called when the user clicks the save button
private fun saveText(){
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "*/*"
putExtra(Intent.EXTRA_TITLE, "text.txt")
}
startActivityForResult(intent, 1)
}
Here is the onActivityResult method:
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
if (requestCode == 1 && resultCode == Activity.RESULT_OK) {
try {
val path = resultData?.data?.path
Log.wtf("Path", filePath)
val writer: Writer = BufferedWriter(FileWriter(path))
writer.write("Example Text")
writer.close()
} catch (e: Exception){
e.printStackTrace()
}
}
}
I also have the permissions set in the manifest and the file itself is created, but nothing is written. Perhaps I'm writing to the file wrong?
The error thrown is FileNotFoundException, because its trying to use a file from /document when I'm selecting one from /downloads
Suggested solution which unfortunately doesn't work:
resultData?.data?.let {
requireActivity().contentResolver.openOutputStream(it).use { stream ->
stream!!.bufferedWriter().write("Example Text")
}
}
A Uri is not a file.
Replace:
val path = resultData?.data?.path
Log.wtf("Path", filePath)
val writer: Writer = BufferedWriter(FileWriter(path))
writer.write("Example Text")
writer.close()
with:
resultData?.data?.let { contentResolver.openOutputStream(it).use { stream ->
stream.writer().write("Example Text")
}
}
I am creating a simple Android app where when a user clicks on a button, a file picker appears in which a user selects a file, and the app reads the contents of the file. However, in my code below, I get a FileNotFound following error after selecting a file (at the line where the File object is instantiated):
EXCEPTION: java.io.FileNotFoundException: /document/6471 (No such file
or directory)
Below is my code:
// File picker implementation
private fun chooseFile(view:View) {
println("chooseFile activated!");
var selectFile = Intent(Intent.ACTION_GET_CONTENT)
selectFile.type = "*/*"
selectFile = Intent.createChooser(selectFile, "Choose a file")
startActivityForResult(selectFile, READ_IN_FILE)
}
/* After startActivityForResult is executed, when the selectFile Intent is completed, onActivityResult is executed with
the result code READ_IN_FILE.*/
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == READ_IN_FILE) { // Step 1: When a result has been received, check if it is the result for READ_IN_FILE
if (resultCode == Activity.RESULT_OK) { // Step 2: Check if the operation to retrieve thea ctivity's result is successful
// Attempt to retrieve the file
try {
// Retrieve the true file path of the file
var uri: Uri? = data?.getData();
// Instantiate a File object from the file name
var file:File = File(uri?.getPath());
// Read the file, line by line
file.forEachLine { println(it) }
} catch (e: Exception) { // If the app failed to attempt to retrieve the error file, throw an error alert
println("EXCEPTION: " + e.toString());
Toast.makeText(this, "Sorry, but there was an error reading in the file", Toast.LENGTH_SHORT).show()
}
}
}
}
#RequiresApi(Build.VERSION_CODES.LOLLIPOP)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var file1:Button = findViewById(R.id.file1);
file1.setOnClickListener(::chooseFile)
}
Below is my XML code (activity_main.xml):
<Button
android:id="#+id/file1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif"
android:text="File 1"
android:textAllCaps="false"
android:textSize="16sp" />
// File picker implementation
private fun chooseFile(view:View) {
//only the below specified mime type is allowed in the picker
val mimeTypes = arrayOf(
"application/msword",
"application/vnd.ms-powerpoint",
"application/vnd.ms-excel",
"text/plain",
"application/pdf"
)
println("chooseFile activated!");
var selectFile = Intent(Intent.ACTION_GET_CONTENT)
selectFile.type = if (mimeTypes.size == 1) mimeTypes[0] else "*/*"
if (mimeTypes.isNotEmpty()) {
selectFile.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes)
}
selectFile = Intent.createChooser(selectFile, "Choose a file")
startActivityForResult(selectFile, READ_IN_FILE)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 200) { // Step 1: When a result has been received, check if it is the result for READ_IN_FILE
if (resultCode == Activity.RESULT_OK) { // Step 2: Check if the operation to retrieve thea ctivity's result is successful
// Attempt to retrieve the file
try {
data?.data?.let {
contentResolver.openInputStream(it)
}?.let {
val r = BufferedReader(InputStreamReader(it))
while (true) {
val line: String? = r.readLine() ?: break
println(line)
}
}
} catch (e: Exception) { // If the app failed to attempt to retrieve the error file, throw an error alert
Toast.makeText(
this,
"Sorry, but there was an error reading in the file",
Toast.LENGTH_SHORT
).show()
}
}
}
}
I've just been coding in kotlin for a while. I've got some problems.
It always return null data in after I click item in second activity.
first activity
btnClick.setOnClickListener { v ->
val intent = Intent(applicationContext, NumberPickerActivity::class.java)
startActivityForResult(intent, 777)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
try {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 777 && resultCode == Activity.RESULT_OK) {
val result = data?.getStringExtra("picked_product").toString()
Toast.makeText(applicationContext, result, Toast.LENGTH_SHORT).show()
}
} catch (e: Exception) {
Toast.makeText(applicationContext, e.message, Toast.LENGTH_LONG).show()
}
}
second activity
override fun onItemClick(item: Product) {
val intent = Intent()
intent.putExtra("picked_product", item.price)
setResult(Activity.RESULT_OK, intent)
finish()
}
Because you are expecting an Int, do this instead:
val result = data?.getIntExtra("picked_product", 0) //0 will be used in case no value in data and result is now Integer.
The extra you put in your intent is an Integer (item.price). But you are trying to retrive a String data?.getStringExtra("picked_product").
Sinc the intent does not contain a String at the key "picked_product", it returns null.
You should try to get an Int extra :
val result = data?.getIntExtra("picked_product")
Nothing to do with your problem but it's useless to do
data?.getStringExtra("picked_product").toString()
Since it return you a String the use of toString() is useless