Introduction
Capturing an image from the camera and displaying it in an Android Activity involves launching the system camera app via an Intent, receiving the result, and loading the image into an ImageView. The modern approach uses the Activity Result API (registerForActivityResult) instead of the deprecated onActivityResult. For full-resolution images, you must provide a file URI via FileProvider. The thumbnail returned in the Intent extras is low resolution (around 160x120 pixels) and only suitable for previews.
Permissions
1<!-- AndroidManifest.xml -->
2<uses-feature android:name="android.hardware.camera" android:required="false" />
3<uses-permission android:name="android.permission.CAMERA" />
4
5<!-- Required for saving full-size photos -->
6<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
7 android:maxSdkVersion="28" />
8
9<!-- FileProvider for sharing file URIs with the camera app -->
10<provider
11 android:name="androidx.core.content.FileProvider"
12 android:authorities="${applicationId}.fileprovider"
13 android:exported="false"
14 android:grantUriPermissions="true">
15 <meta-data
16 android:name="android.support.FILE_PROVIDER_PATHS"
17 android:resource="@xml/file_paths" />
18</provider>
1<!-- res/xml/file_paths.xml -->
2<paths>
3 <external-files-path name="images" path="Pictures" />
4</paths>
FileProvider is required on Android 7+ (API 24) because direct file URIs (file://) throw FileUriExposedException. The provider shares files securely via content:// URIs.
Thumbnail Only (Quick Approach)
1import android.graphics.Bitmap
2import android.os.Bundle
3import android.widget.ImageView
4import androidx.activity.result.contract.ActivityResultContracts
5import androidx.appcompat.app.AppCompatActivity
6
7class MainActivity : AppCompatActivity() {
8 private lateinit var imageView: ImageView
9
10 private val takePicture = registerForActivityResult(
11 ActivityResultContracts.TakePicturePreview()
12 ) { bitmap: Bitmap? ->
13 bitmap?.let { imageView.setImageBitmap(it) }
14 }
15
16 override fun onCreate(savedInstanceState: Bundle?) {
17 super.onCreate(savedInstanceState)
18 setContentView(R.layout.activity_main)
19 imageView = findViewById(R.id.imageView)
20
21 findViewById<android.widget.Button>(R.id.captureButton).setOnClickListener {
22 takePicture.launch(null)
23 }
24 }
25}
TakePicturePreview() returns a small Bitmap thumbnail. No file URI or storage permissions are needed. Use this only when image quality does not matter.
Full-Resolution Image (Recommended)
1import android.net.Uri
2import android.os.Bundle
3import android.os.Environment
4import android.widget.ImageView
5import androidx.activity.result.contract.ActivityResultContracts
6import androidx.appcompat.app.AppCompatActivity
7import androidx.core.content.FileProvider
8import java.io.File
9import java.text.SimpleDateFormat
10import java.util.*
11
12class MainActivity : AppCompatActivity() {
13 private lateinit var imageView: ImageView
14 private lateinit var photoUri: Uri
15
16 private val takePicture = registerForActivityResult(
17 ActivityResultContracts.TakePicture()
18 ) { success: Boolean ->
19 if (success) {
20 imageView.setImageURI(photoUri)
21 }
22 }
23
24 override fun onCreate(savedInstanceState: Bundle?) {
25 super.onCreate(savedInstanceState)
26 setContentView(R.layout.activity_main)
27 imageView = findViewById(R.id.imageView)
28
29 findViewById<android.widget.Button>(R.id.captureButton).setOnClickListener {
30 photoUri = createImageUri()
31 takePicture.launch(photoUri)
32 }
33 }
34
35 private fun createImageUri(): Uri {
36 val timestamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(Date())
37 val imageFile = File(
38 getExternalFilesDir(Environment.DIRECTORY_PICTURES),
39 "IMG_${timestamp}.jpg"
40 )
41 return FileProvider.getUriForFile(
42 this,
43 "${packageName}.fileprovider",
44 imageFile
45 )
46 }
47}
TakePicture() saves the full-resolution photo to the URI you provide. The camera app writes directly to this file, and you load it afterward.
Java Version
1import android.net.Uri;
2import android.os.Bundle;
3import android.os.Environment;
4import android.widget.Button;
5import android.widget.ImageView;
6import androidx.activity.result.ActivityResultLauncher;
7import androidx.activity.result.contract.ActivityResultContracts;
8import androidx.appcompat.app.AppCompatActivity;
9import androidx.core.content.FileProvider;
10import java.io.File;
11import java.text.SimpleDateFormat;
12import java.util.Date;
13import java.util.Locale;
14
15public class MainActivity extends AppCompatActivity {
16 private ImageView imageView;
17 private Uri photoUri;
18
19 private final ActivityResultLauncher<Uri> takePicture =
20 registerForActivityResult(new ActivityResultContracts.TakePicture(), success -> {
21 if (success) {
22 imageView.setImageURI(photoUri);
23 }
24 });
25
26 @Override
27 protected void onCreate(Bundle savedInstanceState) {
28 super.onCreate(savedInstanceState);
29 setContentView(R.layout.activity_main);
30 imageView = findViewById(R.id.imageView);
31
32 Button captureBtn = findViewById(R.id.captureButton);
33 captureBtn.setOnClickListener(v -> {
34 photoUri = createImageUri();
35 takePicture.launch(photoUri);
36 });
37 }
38
39 private Uri createImageUri() {
40 String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date());
41 File imageFile = new File(
42 getExternalFilesDir(Environment.DIRECTORY_PICTURES),
43 "IMG_" + timestamp + ".jpg"
44 );
45 return FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", imageFile);
46 }
47}
Loading with Proper Orientation
1import android.graphics.BitmapFactory
2import android.graphics.Matrix
3import androidx.exifinterface.media.ExifInterface
4
5fun loadBitmapWithRotation(uri: Uri): Bitmap? {
6 val inputStream = contentResolver.openInputStream(uri) ?: return null
7 val bitmap = BitmapFactory.decodeStream(inputStream)
8 inputStream.close()
9
10 // Read EXIF orientation
11 val exifStream = contentResolver.openInputStream(uri) ?: return bitmap
12 val exif = ExifInterface(exifStream)
13 val orientation = exif.getAttributeInt(
14 ExifInterface.TAG_ORIENTATION,
15 ExifInterface.ORIENTATION_NORMAL
16 )
17 exifStream.close()
18
19 val rotation = when (orientation) {
20 ExifInterface.ORIENTATION_ROTATE_90 -> 90f
21 ExifInterface.ORIENTATION_ROTATE_180 -> 180f
22 ExifInterface.ORIENTATION_ROTATE_270 -> 270f
23 else -> 0f
24 }
25
26 if (rotation == 0f) return bitmap
27
28 val matrix = Matrix().apply { postRotate(rotation) }
29 return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
30}
Camera photos often have EXIF rotation metadata instead of actual pixel rotation. Without reading the EXIF data, images may appear rotated 90 degrees in the ImageView.
Using Glide for Efficient Loading
1import com.bumptech.glide.Glide
2
3// Glide handles EXIF rotation, memory management, and scaling automatically
4Glide.with(this)
5 .load(photoUri)
6 .into(imageView)
Glide (or Coil/Picasso) handles image loading, EXIF rotation, memory caching, and downsampling automatically. For production apps, always use an image loading library instead of setImageURI().
Common Pitfalls
Using the thumbnail bitmap for anything beyond previews: The data.getExtras().get("data") bitmap from the old Intent API is approximately 160x120 pixels. Always use TakePicture() with a file URI for usable-quality photos.
FileUriExposedException on Android 7+: Passing a file:// URI to the camera Intent crashes on API 24+. Always use FileProvider.getUriForFile() to create a content:// URI.
Image appears rotated: Many cameras save photos in landscape orientation with EXIF rotation metadata. Use ExifInterface to read the orientation and rotate the bitmap, or use Glide which handles this automatically.
OutOfMemoryError with large images: Loading a full-resolution camera photo (12MP+) directly into a Bitmap consumes 48MB+ of memory. Use BitmapFactory.Options.inSampleSize to downsample, or use Glide which manages memory automatically.
Deprecated onActivityResult: The old startActivityForResult / onActivityResult pattern is deprecated. Use registerForActivityResult with ActivityResultContracts.TakePicture() for the modern, lifecycle-safe approach.
Summary
Use ActivityResultContracts.TakePicture() with a FileProvider URI for full-resolution photos
Use TakePicturePreview() only for quick thumbnails that do not need to be saved
Configure FileProvider in the manifest to avoid FileUriExposedException on Android 7+
Handle EXIF rotation with ExifInterface or use Glide for automatic orientation correction
Use image loading libraries (Glide, Coil) in production to handle memory, caching, and rotation
The Activity Result API replaces the deprecated onActivityResult pattern