I am trying to get image file from external storage using new activity result Api.
My contract always return null from else branch (inside when). Why?
class GetImageContract : ActivityResultContract<Unit, Bitmap>() {
override fun createIntent(context: Context, input: Unit?): Intent {
val intent = Intent(ACTION_GET_CONTENT)
intent.type = "image/*"
return intent
}
override fun parseResult(resultCode: Int, intent: Intent?): Bitmap? {
return when {
resultCode != Activity.RESULT_OK -> null
else -> intent?.extras?.get("data") as? Bitmap
}
}
}
Related
I am currently trying to learn from a step-by-step tutorial to upload an Image or File to my server while using Volley. This tutorial is a little bit outdated and I really don't understand how I can fix these issues.
the tutorial
onActivityResult(Int, Int, Intent?): Unit' is deprecated. Deprecated in Java
Fragment is attempting to registerForActivityResult after being created. Fragments must call registerForActivityResult() before they are created (i.e. initialization, onAttach(), or onCreate()).
My code
//Uploading Photos
private fun launchGallery() {
val intent = Intent(Intent.ACTION_PICK)
intent.type = "image/*"
var resultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
// There are no request codes
val data: Intent? = result.data
}
}
}
private fun uploadImage() {
imageData?: return
val request = object : VolleyFileUploadRequest(
Request.Method.POST,
postURL,
{
println("response is: $it")
},
{
println("error is: $it")
}
) {
override fun getByteData(): MutableMap<String, FileDataPart> {
var params = HashMap<String, FileDataPart>()
params["imageFile"] = FileDataPart("image", imageData!!, "jpeg")
return params
}
}
Volley.newRequestQueue(requireContext()).add(request)
}
#Throws(IOException::class)
private fun createImageData(uri: Uri) {
val inputStream = requireContext().contentResolver.openInputStream(uri)
inputStream?.buffered()?.use {
imageData = it.readBytes()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (resultCode == Activity.RESULT_OK && requestCode == IMAGE_PICK_CODE) {
val uri = data?.data
if (uri != null) {
imageView.setImageURI(uri)
createImageData(uri)
}
}
super.onActivityResult(requestCode, resultCode, data)
}
}
you are trying to registerForActivityResult from a method "launchGallery()" which is not the way it should be done, "registerForActivityResult" should be initialized in the Activity/Fragment onCreate function and then you can use the "resultLauncher" variable to open the gallery/camera etc...
also when you are using the "registerForActivityResult" you don't need to override "onActivityResult" (which is now deprecated).
check the Activity Result Api to get a better understanding of how the new api works.
and here is a good tutorial that shows you how to use the Android Activity Result API for selecting and taking images
Is there any default way to get the request code in ActivityResultContract?
I know about StartActivityForResult contract, which returns ActivityResult, but there is no requestCode, only resultCode.
I can do something like this, but maybe there is a better solution:
class StartActivityForResult : ActivityResultContract<ActivityInput, ActivityOutput?>() {
override fun createIntent(
context: Context,
input: ActivityInput
): Intent {
return input.data.apply { putExtra(requestCodeKey, input.requestCode) }
}
override fun parseResult(resultCode: Int, intent: Intent?): ActivityOutput? {
return if (intent == null || resultCode != Activity.RESULT_OK) null
else ActivityOutput(
// should never return default value
requestCode = intent.getIntExtra(requestCodeKey, -1),
resultCode = resultCode,
data = intent
)
}
override fun getSynchronousResult(
context: Context,
input: ActivityInput?
): SynchronousResult<ActivityOutput?>? {
return if (input == null) SynchronousResult(null) else null
}
companion object {
const val requestCodeKey = "requestCodeKey";
}
}
data class ActivityInput(val requestCode: Int, val data: Intent)
data class ActivityOutput(val requestCode: Int,
val resultCode: Int,
val data: Intent
)
My application checks whether the new selected image is the same as the previous one so that I don't need to update the cloud data, but newBitmap.sameAs(oldBitmap) always return false even though I pick the same photo.
Piece of my code:
private lateinit var oldBitmap: Bitmap
private lateinit var newBitmap: Bitmap
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_my_profile)
myProfilePictureUrl = intent.getStringExtra("myProfilePictureUrl")!!
if (myProfilePictureUrl.isNotEmpty()) {
Picasso.get().load(myProfilePictureUrl).into(my_profile_imageView)
}
oldBitmap = (my_profile_imageView.drawable as BitmapDrawable).bitmap //for later comparison
my_profile_imageView.setOnClickListener {
val intent = Intent(Intent.ACTION_PICK)
intent.type = "image/*"
startActivityForResult(intent, RESULT_CODE_PICK_IMAGE)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == RESULT_CODE_PICK_IMAGE && resultCode == Activity.RESULT_OK) {
val inputStream = contentResolver.openInputStream(data!!.data!!)
val bitmap = BitmapFactory.decodeStream(inputStream)
newBitmap = bitmap //for comparison
my_profile_imageView.setImageBitmap(bitmap)
}
}
And when the user click on the "save" button on the action bar will it first check whether they are the same photo:
private fun updateProfile(nickname: String) {
if (this::newBitmap.isInitialized && !newBitmap.sameAs(oldBitmap)) { //here
//upload task code
}
}
THE PROBLEM IS:
!newBitmap.sameAs(oldBitmap) always return false even they are the same photo, may be the problem of PICASSO? Or the way I used to compare is not right. Any help would be appreciated.
In my android application, I am trying to let the user select a gallery image and show a high-quality image in another activity. is there a way to get an absolute path from URI? or is there an efficient way to do this?
This function opens the gallery and lets the user select an image:
private fun getGalleryImage() {
val galleryImageIntent =
Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
if (galleryImageIntent.resolveActivity(requireActivity().packageManager) != null) {
startActivityForResult(galleryImageIntent, REQUEST_GALLERY_IMAGE)
}
}
And the following gets the result, but I am not sure how to get the image path
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == REQUEST_GALLERY_IMAGE && resultCode == RESULT_OK) {
startActivity(
Intent(context, ImageViewActivity::class.java).putExtra(
"imagePath",
data?.data?.toString()
)
)
} else
super.onActivityResult(requestCode, resultCode, data)
}
Here is my ImageViewActivity:
class ImageViewActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_image_view)
backBtn.setOnClickListener {
finish()
}
val imagePath = intent?.extras?.get("imagePath")
BitmapFactory.decodeFile(imagePath?.toString())?.also { bitmap ->
imageHolder.setImageBitmap(bitmap)
}
}
}
I tried sending the bitmap itself to my ImageViewActivity but it keeps crashing, and from what I read online, it is not possible to send large amount of data to an Activity.
How to pass Image selected in ImageView to another Activity in Android using Kotlin ?
This is the way to select the Image inside the ImageView using internal Storage and I need to pass the image to another activity
fun Loadimage()
{
var intent = Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
startActivityForResult(intent,ImageCode)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode==ImageCode && data!=null && resultCode== Activity.RESULT_OK)
{
val selectedImage = data.data
val filepath = arrayOf(MediaStore.Images.Media.DATA)
val cursor = contentResolver.query(selectedImage,filepath,null,null,null)
cursor.moveToFirst()
val Index = cursor.getColumnIndex(filepath[0])
val Picture = cursor.getString(Index)
cursor.close()
imageView.setImageBitmap(BitmapFactory.decodeFile(Picture))
}
}
You can pass Picture variable to next activity using Intents like below
val intent = Intent(this, NextActivity::class.java)
intent.putExtra("picture", Picture)
startActivity(intent)
Then in NextActivity, in onCreate method, you can get picture using
val Picture = getIntent().getStringExtra("picture")
In the NextActivity:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val postImage = findViewById<ImageView>(R.id.post_image)
myPic = postImage
}
companion object {
lateinit var myPic: ImageView()
}
And in the first Activity:
NextActivity.myPic = Picture