Android onActivityResult未被调用/触发

30

我读了很多关于 onActivityResult的问题,但似乎没有一个描述的问题适用于我的情况,比如在 startActivityForResult 中放置一个负的 requestCode 或其他问题。

我正在我的 Activity 中使用相机,并将其预览流传输到 SurfaceView。 拍照后,关闭相机释放其资源,调用 setResult(RESULT_OK, DataIntent),希望能够在父级中触发 onActivityResult

但是它没有触发。如果我在子 Activity 的 onCreate 中设置结果并在 onCreate 中完成子 Activity,则结果不会传递给 onActivityResult。

为什么可能会导致 onActivityResult 没有被触发呢? 下面是一些我正在做的事情的源代码以便理解...

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;
    }
}

将代码进行大纲化,并在工具栏上点击代码按钮。 - prolink007
你尝试在 onValidDecodeResult 函数中设置断点了吗?也许它从未被调用,因此父活动中没有结果? - dstefanox
是的,我在 onValidDecodeResult 中设置了一个断点。只要 onPreviewFrame 中的结果不为空,它就会被触发。我怀疑它得到的数据就是问题所在。 - Rafael T
8个回答

56

请确保传递给startActivityForResult(...)的数值参数(requestCode)大于等于0。


2
天啊!我甚至没有想到!但最好说:“确保传递的**requestCode**是……”。这样更清楚。 - Mir-Ismaili

42

我也遇到了同样的问题。请检查您的清单并确保您没有使用single instance:

android:launchMode="singleInstance"

14
我删除的是android:noHistory="true" - Poutrathor
+1 但是,如果您正在使用SearchView并且必须将launchmode设置为SingleInstante,则有没有办法停止为searchView打开新活动? - mohammad jannesary
奇怪的行为。感谢提示。自从在活动中添加了该项后,对我有用,因为onActivityResult不再被调用。 - Edison Spencer
2
在调用者活动上,使用SingleInstance或SingleTask。 - oli.G

30

删除我遇到问题的活动中的 android:noHistory="true" 代码解决了我的问题。


你太棒了!发现得真好。谢谢。 - ralphgabb
1
@ralphgabb 当然没问题! - Joseph Lam
这个救了我的一天。 - leegor

22

我现在自己解决了这个问题。

在放弃获取onActivityResult触发后,我决定通过从MainActivity传递静态引用到CaptureActivity来“hack” Android的封装,即使我知道这不是一个好主意。

finish()调用之后,神奇地onActivityResult被触发,并且结果为Context.RESULT_CANCELLED...这是预期的,因为我不再调用setResult了。

触发onActivityResult后,我调查了一下为什么现在它能工作。我发现这与位图有关,该位图被传递到一个Intent中。如果我将一个Parcellable位图放入我的resultIntent中,onActivityResult就永远不会被触发。

因此,删除上面代码中的以下行将起作用:

intent.putExtra(Config.SCAN_RESULT_BMP, barcode);

对我来说这没关系,因为在这个其他的Activity中我并不需要真正的位图。这更像是一个“特色”而不是一种需求。

如果你们中有人想要将大数据(如位图)传递到Intent中,请考虑将其存储在SD卡上,将路径传递给Intent,在ParentActivity中从SD卡中读取此Bitmap如何通过Intent拍照)。

此处所述,Parcelable的限制为1MB,因此传递给Intent的任何大于此值的内容都会导致一个内部TransactionTooLargeException并且将默默失败。


2
另一种可能难以发现原因的情况是:当使用这样的嵌入式方案TabActivity -> ActivityGroup -> Activity,并且通过使用Window.getDecorView()方法显示最后嵌入的实体(Activity)时,不要从最后一个嵌入的实体中调用startActivityForResult(),而是从更高一级的ActivityGroup中调用。同时,在同一个ActivityGroup实例中等待结果。 - kellogs
它解决了我的问题。但是,您能否解释一下为什么在使用putExtra()时它不起作用? - unorsk
@AndrewDashin 不,我确实做不到。我只能猜测,我的位图太大了,无法进行分包处理。 - Rafael T
2
遇到了同样的问题...谁能想到尝试返回可包含的位图会导致onActivityResult()永远不会被调用???-__-顺便说一下,非常感谢您的帖子..节省了我很多时间! - BlackSoil

7
在我的情况下,我在创建 startActivityForResult 的意图时加入了标志 Intent.FLAG_ACTIVITY_NEW_TASK,因此它没有被触发。移除它可以解决我的问题。

5

这是另一种方法。从DialogFragment中,您可以使用startActivityForResult。但如果您的意图是从关联的Activity启动的,则必须在startActivityForResult之前包含getActivity()。请参见下面的示例(最后一行):

Activity activeOne=FileDialogWindow.this.getActivity();
Intent intent = new Intent(activeOne,FolderSelectionActivity.class);
String message = "foobar";
intent.putExtra(EXTRA_MESSAGE, message);
getActivity().startActivityForResult(intent,1);

请在文本中使用标记(反引号)来格式化 代码词 - buhtz
1
非常感谢您的回答 - 拯救了我的白天/黑夜! - Dominikus K.
我从另一个线程开始了活动以获取结果。因此,我必须实现 runOnUIThread() - Pierre

1

有可能是您之前的活动没有完成?尝试使用Log.d进行调试,并查看logcat以查看呼叫堆栈是否实际到达CaptureActivity类中的finish()语句。


2
如果我在CaptureActivity中调用this.finish(),为什么CaptureActivity没有被finish掉呢?如果我在finish()调用处设置断点,它会从Android的Activity.class中触发。我在onDestroy中放置了一个Log来查看是否被调用,而且它确实被调用了。还有其他的想法吗? - Rafael T

0
在我的情况下,扫描请求代码必须是IntentIntegrator.REQUEST_CODE
也就是说 startActivityForResult(intent, IntentIntegrator.REQUEST_CODE)
希望能对你有所帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接