30

I read much about issues with onActivityResult, but it seems that none of the described problems fit to mine, like putting a negative requestCode in startActivityForResult or something else.

I'm playing with the camera in my Activity, which streams its preview to a SurfaceView. After taking a picture, I close the cam releasing its resources, call setResult(RESULT_OK, DataIntent) and hoping that onActivityResult is triggered in my parent.

But it doesn't. If I set a result in onCreate of the child Activity and finish the child in onCreate the result is not passed to onActivityResult.

What possible reason could it be that onActivityResult is not getting triggered? I'll write some of my source down for understanding of what I'm doing...

public class MainActivity extends Activity {
    Button mButtonScan;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mButtonScan = (Button)findViewById(R.id.main_btn_scan);
    }

    /**
    * OnClick Event called from main.xml
    * @param v View that called that onClickEvent
    */
    public void btnCaptureClick(View v) {
        Intent intent = new Intent(this, CaptureActivity.class);
        startActivityForResult(intent, Constants.REQUEST_CODE_CAPTURE);
    }

    /**
    * callback for this Activity. Called when an Activity which was started by
    * this.startActivityForResult(intent, requestCode) sets its result and calls finish()
    */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        String foo = "foo";
        switch (requestCode) {
            case Constants.REQUEST_CODE_CAPTURE:
                switch (resultCode) {
                    case RESULT_FIRST_USER:
                        Toast.makeText(this, data.getStringExtra(Config.SCAN_RESULT_TEXT), Toast.LENGTH_LONG).show();
                        break;
                    case RESULT_CANCELED:
                        break;
                    default:
                        break;
                }
                break;

            default:
                super.onActivityResult(requestCode, resultCode, data);
                break;
        }
    }
}


public class CaptureActivity extends Activity implements ActivityCallback, SurfaceHolder.Callback, PreviewCallback {

    private Preview mPreview;
    private Camera mCam;
    private SurfaceHolder mHolder;
    private Size size;

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.capture);

        mPreview = (Preview)findViewById(R.id.capture_preview); 
    }

    @Override
    public void onValidDecodeResult(Result rawResult, Bitmap barcode) {
        Intent intent = new Intent();
        if (rawResult != null && barcode != null) {
            intent.putExtra(Config.SCAN_RESULT_TEXT, rawResult.getText());
            intent.putExtra(Config.SCAN_RESULT_FORMAT, rawResult.getBarcodeFormat().getName());
            intent.putExtra(Config.SCAN_RESULT_BMP, barcode);
        } else {
            intent.putExtra(Config.SCAN_RESULT_TEXT, "foo");
            intent.putExtra(Config.SCAN_RESULT_FORMAT, "bar");
            intent.putExtra(Config.SCAN_RESULT_BMP, "barcode");
        }
        mPreview = null;
        setResult(Activity.RESULT_FIRST_USER, intent);
        finish();   
    }

    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
        MultiFormatReader reader = new MultiFormatReader();     
        PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(data, size.width, size.height, 160, 60, 480, 360);
        GlobalHistogramBinarizer binarizer = new GlobalHistogramBinarizer(source);
        BinaryBitmap bb = new BinaryBitmap(binarizer);
        Result result = null;
        try {
            result = reader.decode(bb);
        } catch (NotFoundException e) {
            //do NOTHING cause e == null
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            reader.reset();
        }
        if (result != null) {
            mCam.stopPreview();
            releaseCameraResources();
            onValidDecodeResult(result, source.renderCroppedGreyscaleBitmap());
        } else {
            camera.setOneShotPreviewCallback(this);
        }       
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        try {
            mCam = Camera.open();
            mCam.setPreviewDisplay(mPreview.getHolder());
        } catch (IOException e) {
            releaseCameraResources();
            e.printStackTrace();
        }           
    }

    private void releaseCameraResources() {
        mCam.release();
        mCam = null;
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
        int height) {
        //begin Preview
        Camera.Parameters parameters = mCam.getParameters();

        List<Size> sizes = parameters.getSupportedPreviewSizes();

        size = getOptimalPreviewSize(sizes, width, height);
        parameters.setPreviewSize(size.width, size.height);

        mCam.setParameters(parameters);
        mCam.startPreview();
        mCam.setOneShotPreviewCallback(this);
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        if (mCam != null) {
            mCam.stopPreview();
            releaseCameraResources();
        }   
    }

    private Size getOptimalPreviewSize(List<Size> sizes, int width, int height) {
        final double ASPECT_TOLERANCE = 0.05;
        double targetRatio = (double) width / height;

        if (sizes == null) return null; 
            Size optimalSize = null;
            double minDiff = Double.MAX_VALUE;

            int targetHeight = height;

            for (Size size: sizes) {
                double ratio = (double) size.width / size.height;
                if(Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) {
                    continue;
                }

                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }               
            }

            if (optimalSize == null) {
                //cannot find matching aspect-ratio
                minDiff = Double.MAX_VALUE;
                for (Size size : sizes) {
                    if (Math.abs(size.height - targetHeight) < minDiff) {
                        optimalSize = size;
                        minDiff = Math.abs(size.height - targetHeight);
                }
            }
        }
        return optimalSize;
    }
}
Rafael T
  • 15,401
  • 15
  • 83
  • 144
  • outline the code and click the code button on the toolbar. – prolink007 Feb 16 '11 at 17:20
  • Did you tried to put breakpoint in onValidDecodeResult function? Maybe it is never entered and thus there is no result in parent activity? – dstefanox Feb 16 '11 at 17:56
  • Yes, I had put a breakpoint in onValidDecodeResult. It is triggered as soon the result in onPreviewFrame is NOT null. The data it gets is what I suspect. – Rafael T Feb 17 '11 at 12:21

8 Answers8

56

Make sure the number parameter (requestCode) passed to startActivityForResult(...) is >=0

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Abolfoooud
  • 2,663
  • 2
  • 27
  • 27
  • 2
    Oh my God! I don't even think about it! But was better to say: "Make sure the passed **`requestCode`** is ...". It is more clear. – Mir-Ismaili Feb 07 '17 at 10:16
42

Had the same problem. check your manifest and make sure you are NOT using single instance:

android:launchMode="singleInstance"
Jérôme Verstrynge
  • 57,710
  • 92
  • 283
  • 453
JayW
  • 421
  • 1
  • 5
  • 2
30

Deleting android:noHistory="true" from the activity I was having problem with solved the issue for me.

Rohit Arya
  • 6,751
  • 1
  • 26
  • 40
Joseph Lam
  • 5,289
  • 3
  • 14
  • 13
22

I solved the problem myself now.

After giving up to get onActivityResult triggering, I decided to 'hack' Androids encapsulating by passing a static reference from MainActivity to CaptureActivity, even if I know that this isn't a good idea.

After the finish() call, MAGICALLY onActivityResult gets triggered with Context.RESULT_CANCELLED... as expected because I don't call setResult anymore.

Getting onActivityResult triggered I investigated why it is working now. I found out, that it has something to do with the bitmap, passed to an Intent. If I put a Parcellable Bitmap into my resultIntent onActivityResult never gets fired.

So removing following line in the code above will work:

intent.putExtra(Config.SCAN_RESULT_BMP, barcode);

Thats ok for me, because I don't needed the BitMap really in this other Activity. It was more a 'feature' than a need.

If some of you guys want to pass big Data into an Intent like a Bitmap, think about storing it somewhere on SD, passing the path in the Intent, while reading this Bitmap from SD in ParentActivity (How to take a photo by Intent).

As stated here, the Limit of a Parcelable is 1MB, thus everything bigger passed to an Intent will cause an internal TransactionTooLargeException and will silently fail

Rafael T
  • 15,401
  • 15
  • 83
  • 144
  • 2
    another case where the cause might be hard to spot: When having such embed scheme TabActivity -> ActivityGroup ->Activity and the last embedded entities (Activity) get shown by making use of the Window.getDecorView() method - do not call startActivityForResult() from within the last embedded entity, but from one step higher, so from ActivityGroup. Also wait for the result in that same ActivityGroup instance. – kellogs Nov 08 '11 at 23:34
  • It solved my problem. But, could you please make an explanation why it doesn't work when you do putExtra()? – unorsk Nov 20 '11 at 16:13
  • @AndrewDashin No, i could not really. I can only assume, that my bitmap was too large to be parceled. – Rafael T Dec 03 '11 at 12:01
  • 2
    Ran into the same problem... Who would have known that trying to return parcelable bitmap would make onActivityResult() to never get called??? -__- Btw, thanks a lot for this post.. Save me lots of time! – BlackSoil Oct 08 '12 at 02:18
7

In my case, it was not triggered since I had added flag Intent.FLAG_ACTIVITY_NEW_TASK while creating intent for startActivityForResult. Removing it solved my issue.

NightFury
  • 13,436
  • 6
  • 71
  • 120
5

Another variant on this one. From a DialogFragment, you can startActivityForResult. But if your Intent is started from the associated Activity, you must include getActivity() before startActivityForResult. See below (last line):

Activity activeOne=FileDialogWindow.this.getActivity();
Intent intent = new Intent(activeOne,FolderSelectionActivity.class);
String message = "foobar";
intent.putExtra(EXTRA_MESSAGE, message);
getActivity().startActivityForResult(intent,1);
Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
DavidLeRay
  • 51
  • 1
  • 3
1

It might just be the case that your previous activity doesn't finish? Trying debugging using Log.d and view logcat to see whether the call stack actually reaches the finish() statement in your CaptureActivity class.

Manish Burman
  • 3,069
  • 2
  • 30
  • 35
  • 2
    how can the CaptureActivity NOT be finish if I call this.finish() in CaptureActivity. If I put a breakpoint to the finish() call it is triggered in Activity.class from Android. I put a Log to onDestroy to see if it gets called and it gets called. any other ideas? – Rafael T Feb 17 '11 at 12:25
0

in my case, the scan request code must be IntentIntegrator.REQUEST_CODE,

that is

startActivityForResult(intent, IntentIntegrator.REQUEST_CODE).

Hope can help you.

hoot
  • 1,215
  • 14
  • 15