使用Activity Result Contracts结合UCrop时无法获取裁剪结果到应用中
Hey there! Let's figure out why your cropped image isn't showing up in the ImageView—I've spotted a few key issues in your code that are causing this problem, and fixing them should get things working smoothly.
1. You're Using the Wrong Intent to Get the Cropped Result
The biggest mistake is in your cropImage activity result callback:
private val cropImage = registerForActivityResult(uCropContract){ val uri = intent.data // ❌ This is the NewPostActivity's intent, not UCrop's result! imageUri = uri newPostImageSelector.setImageURI(imageUri) }
UCrop already returns the cropped image's Uri directly through the callback parameter (it). You don't need to access intent.data here—that's pointing to the intent that launched your activity, not the result from UCrop.
2. Unsafe Parsing of UCrop Result
Your custom uCropContract doesn't handle error cases properly, which could lead to crashes or null results. If the user cancels the crop, intent might be null, and using !! will throw an exception.
3. Invalid Output File Name
You added a space in your output file name (" .jpg"), which can cause file path issues. Always avoid spaces in file names for Android storage operations.
Corrected Code
Here's the fixed version of your code with explanations:
Step 1: Fix the UCrop Contract
Update the contract to safely handle result codes and null intents:
private val uCropContract = object : ActivityResultContract<Pair<Uri, Uri>, Uri?>() { override fun createIntent(context: Context, input: Pair<Uri, Uri>): Intent { val (inputUri, outputUri) = input return UCrop.of(inputUri, outputUri) .withAspectRatio(2F, 1F) .withMaxResultSize(1720, 860) .getIntent(context) } override fun parseResult(resultCode: Int, intent: Intent?): Uri? { // Only return the result if the crop was successful return if (resultCode == RESULT_OK && intent != null) { UCrop.getOutput(intent) } else { null } } }
I changed the input type to a Pair<Uri, Uri> instead of a List—it's cleaner for passing exactly two URIs.
Step 2: Fix the Crop Result Callback
Now use the callback parameter to get the cropped Uri:
private val cropImage = registerForActivityResult(uCropContract) { croppedUri -> croppedUri?.let { imageUri = it newPostImageSelector.setImageURI(imageUri) // ✅ This will load the cropped image! } }
We use let to safely handle the case where the user cancels the crop (croppedUri is null).
Step 3: Fix the Output Uri and Launch Logic
Update the getContent callback to pass a Pair instead of a list, and fix the file name:
private val getContent = registerForActivityResult(ActivityResultContracts.GetContent()) { uri -> uri?.let { inputUri -> // Remove the space in the file name val outputFile = File(filesDir, "${System.currentTimeMillis()}_post.jpg") val outputUri = outputFile.toUri() // Pass input and output URIs as a Pair cropImage.launch(Pair(inputUri, outputUri)) } }
Full Corrected Activity Code
class NewPostActivity : AppCompatActivity() { private var myUrl: String? = null private var imageUri: Uri? = null private var storagePostPicRef: StorageReference? = null private lateinit var publishPostButton: ImageView private lateinit var closePostPageButton: ImageView private lateinit var newPostImageSelector: ImageView private val uCropContract = object : ActivityResultContract<Pair<Uri, Uri>, Uri?>() { override fun createIntent(context: Context, input: Pair<Uri, Uri>): Intent { val (inputUri, outputUri) = input return UCrop.of(inputUri, outputUri) .withAspectRatio(2F, 1F) .withMaxResultSize(1720, 860) .getIntent(context) } override fun parseResult(resultCode: Int, intent: Intent?): Uri? { return if (resultCode == RESULT_OK && intent != null) { UCrop.getOutput(intent) } else { null } } } private val getContent = registerForActivityResult(ActivityResultContracts.GetContent()) { uri -> uri?.let { inputUri -> val outputFile = File(filesDir, "${System.currentTimeMillis()}_post.jpg") val outputUri = outputFile.toUri() cropImage.launch(Pair(inputUri, outputUri)) } } private val cropImage = registerForActivityResult(uCropContract) { croppedUri -> croppedUri?.let { imageUri = it newPostImageSelector.setImageURI(imageUri) } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_new_post) storagePostPicRef = FirebaseStorage.getInstance().reference.child("Post Pictures") publishPostButton = findViewById(R.id.publishNewPost) closePostPageButton = findViewById(R.id.closeAddPost) newPostImageSelector = findViewById(R.id.newPostImage) publishPostButton.setOnClickListener { uploadImage() } closePostPageButton.setOnClickListener { val closeIntent = Intent(this, MainActivity::class.java) startActivity(closeIntent) finish() } newPostImageSelector.setOnClickListener { getContent.launch("image/*") } } // Don't forget to implement your uploadImage() method! private fun uploadImage() { // Add your Firebase upload logic here using imageUri } }
Key Takeaways
- Always use the callback parameter provided by
registerForActivityResultto get the result from child activities. - Handle null cases and result codes safely to avoid crashes.
- Avoid spaces or special characters in file names when creating local files for image processing.
After making these changes, your cropped image should load correctly into the ImageView for preview. Good luck with your app development!
内容的提问来源于stack exchange,提问作者Adrian Njagi

