Android开发:如何让类A等待类B的拍照执行结果?
Hey there, let's work through your problem! The main issue here is that startActivityForResult runs asynchronously—it doesn't pause your code to wait for the camera to finish taking a photo. Your attempt to use wait() is actually harmful here: it'll freeze your UI thread (leading to an ANR error) and there's no corresponding notify() to wake it up, so you'll just get stuck. Also, when you call camera.getImage() right after takePicture(), the photo hasn't been captured yet, so image will be null and you'll hit a NullPointerException when trying to compress it.
Let's fix this with two common, reliable approaches:
Option 1: Use a Callback Interface (Standard Android Practice)
Callbacks are the go-to way to handle async results in Android. We'll define an interface to let your camera class notify the caller when the photo is ready.
Step 1: Update Your Camera Class (Class B)
First, add a callback interface to your camera helper class, and remove that broken wait() call:
public class CameraHelper { // Assuming your class B is named CameraHelper static final int REQUEST_IMAGE_CAPTURE = 1; private Bitmap image = null; private OnPictureTakenListener resultListener; // Define the callback interface public interface OnPictureTakenListener { void onPictureSuccess(Bitmap capturedBitmap); void onPictureFailed(); // Handle cancellations or errors } // Set the listener from the calling class public void setOnPictureTakenListener(OnPictureTakenListener listener) { this.resultListener = listener; } public void takePicture(Context context, Activity activity) { Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (takePictureIntent.resolveActivity(context.getPackageManager()) != null) { activity.startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE); } else { // No camera app available? Notify failure if (resultListener != null) { resultListener.onPictureFailed(); } } // Remove the wait() call here—it's causing problems! } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); // Don't forget super! if (requestCode == REQUEST_IMAGE_CAPTURE) { if (resultCode == Activity.RESULT_OK && data != null) { Bundle extras = data.getExtras(); image = (Bitmap) extras.get("data"); // Send the result back to the caller via callback if (resultListener != null) { resultListener.onPictureSuccess(image); } } else { // Photo was cancelled or failed if (resultListener != null) { resultListener.onPictureFailed(); } } } } public Bitmap getImage(){ return image; } }
Step 2: Update the Calling Class (Class A)
Now, instead of trying to get the image immediately, we'll wait for the callback to fire:
public void openCamera() { CameraHelper camera = new CameraHelper(); // Set up the callback to handle the result camera.setOnPictureTakenListener(new CameraHelper.OnPictureTakenListener() { @Override public void onPictureSuccess(Bitmap capturedBitmap) { // Now we have the image—process it here ByteArrayOutputStream outStream = new ByteArrayOutputStream(); capturedBitmap.compress(Bitmap.CompressFormat.JPEG, 100, outStream); byte[] picture = outStream.toByteArray(); _addView.SetCameraPicture(picture); } @Override public void onPictureFailed() { // Let the user know something went wrong Toast.makeText(_addView, "拍照失败或已取消", Toast.LENGTH_SHORT).show(); } }); camera.takePicture((Context) _addView, (Activity) _addView); }
Option 2: Use LiveData (Modern Jetpack Approach)
If you're using Jetpack components, LiveData is a great choice—it handles lifecycle automatically so you don't have to worry about memory leaks.
Step 1: Update Camera Class with LiveData
public class CameraHelper { static final int REQUEST_IMAGE_CAPTURE = 1; private final MutableLiveData<Bitmap> imageLiveData = new MutableLiveData<>(); // Expose immutable LiveData to the caller public LiveData<Bitmap> getImageLiveData() { return imageLiveData; } public void takePicture(Context context, Activity activity) { Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (takePictureIntent.resolveActivity(context.getPackageManager()) != null) { activity.startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE); } else { imageLiveData.postValue(null); // Signal failure } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == Activity.RESULT_OK && data != null) { Bundle extras = data.getExtras(); Bitmap image = (Bitmap) extras.get("data"); imageLiveData.postValue(image); // Send result to observers } else { imageLiveData.postValue(null); // Signal failure/cancellation } } }
Step 2: Observe LiveData in the Calling Class
public void openCamera() { CameraHelper camera = new CameraHelper(); // Observe the LiveData for results camera.getImageLiveData().observe((AppCompatActivity) _addView, bitmap -> { if (bitmap != null) { ByteArrayOutputStream outStream = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outStream); byte[] picture = outStream.toByteArray(); _addView.SetCameraPicture(picture); } else { Toast.makeText(_addView, "拍照失败或已取消", Toast.LENGTH_SHORT).show(); } }); camera.takePicture((Context) _addView, (Activity) _addView); }
Quick Notes to Remember
- Never call
wait()on the UI thread—it'll make your app freeze and crash with an ANR. - Make sure your camera class correctly receives the
onActivityResultcallback. If your class B isn't an Activity/Fragment, you'll need to forward the callback from your host Activity to it. - If you're using AndroidX, consider using
registerForActivityResultinstead of the oldstartActivityForResult—it's more lifecycle-safe and avoids some edge cases.
内容的提问来源于stack exchange,提问作者Belved

