Android 默认相机崩溃

Posted

技术标签:

【中文标题】Android 默认相机崩溃【英文标题】:Android default camera crashes 【发布时间】:2016-03-20 11:30:05 【问题描述】:

我正在使用系统默认相机拍照并将图像保存到 SD 卡。

该应用在装有 android 6.0 的 Nexus 5 上运行良好。 但是在带有 Android 5.0.1 的三星 Galaxy S4 上,当我按下“保存”时,应用程序崩溃了:

java.lang.RuntimeException:无法启动活动 组件信息com.jublikon.example/com.jublikon.example.ReviewMaschine.ReviewActivity: java.lang.NullPointerException:尝试调用虚拟方法'int 空对象引用上的 java.lang.Integer.intValue()'

为什么相机 Activity 会尝试启动另一个 Activity? 它应该只保存图像并完成()本身。

我的抓图方法是这样的:

 private void captureImage() 
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

        fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);

        intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);

        // start the image capture Intent
        startActivityForResult(intent, CAMERA_CAPTURE_IMAGE_REQUEST_CODE);
    

代码生成的fileUri:

file:///storage/emulated/0/Pictures/ImageDokumentation/IMG_20151214_214131.jpg

我注意到该应用程序将图像保存在本地三星 Galaxy S4 上,而不是 SD 卡上。也许这是我正在做的错误? 我意识到有时图片会被保存,有时不会。该应用程序在每种情况下都会停止。

应用程序在没有遇到 onActivityResult 的情况下崩溃。

我真的不明白我做错了什么。该应用程序在物理 Nexus 设备上运行没有任何问题。

编辑:因为这似乎是一个更复杂的问题,这里片段的缩短代码:

public class FragmentReview extends Fragment 

    // some initialization (...)

    private static final int CAMERA_CAPTURE_IMAGE_REQUEST_CODE = 100;
    public static final int MEDIA_TYPE_IMAGE = 1;

    private static final String IMAGE_DIRECTORY_NAME = "ImageDokumentation";

    private Uri fileUri; // file url to store image/video

    // Permission Strings
    private  static final String PERMISSION_HARDWARE_CAMERA = "android.permission.CAMERA";
    private  static final String PERMISSION_WRITE_EXTERNAL_STORAGE = "android.permission.WRITE_EXTERNAL_STORAGE";

    private static final String IMAGE_URI_BUNDLE = "fileUri";

    public FragmentReview() 

    

    @Override
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);

        //Adding some data

        setRetainInstance(true);

    

    @Override
    public void onSaveInstanceState(Bundle outState) 
        super.onSaveInstanceState(outState);
        outState.putParcelable(IMAGE_URI_BUNDLE, fileUri);
    

    @Override
    public boolean onOptionsItemSelected(MenuItem item) 

        List<ReviewItem> currentData = mAdapter.getCurrentData();

        DatabaseHandler db = new DatabaseHandler(getActivity());
        Maschine updateMaschine = new Maschine();
        updateMaschine = db.getMaschineForKeyMaschineAndAnlage(getIdForSelectedAnlage(), getIdForSelectedMaschine());

        switch (item.getItemId()) 
            case R.id.action_save:

               //saving some data 

                return true;
            case R.id.action_photo:

                if (isDeviceSupportCamera()) 

                    boolean checkcamera = hasPermission(PERMISSION_HARDWARE_CAMERA);
                    boolean checkstorage = hasPermission(PERMISSION_WRITE_EXTERNAL_STORAGE);

                    if(hasPermission(PERMISSION_HARDWARE_CAMERA) == true && hasPermission(PERMISSION_WRITE_EXTERNAL_STORAGE))

                        try 
                            captureImage();
                         catch (Exception e) 
                            new MaterialDialog.Builder(getActivity())
                                    .title("Berechtigungen nicht aktiviert")
                                    .content("Bitte lassen Sie in den Einstellungen die notwendigen Berechtigungen zu")
                                    .positiveText("OK")
                                    .show();
                        

                     else 
                        new MaterialDialog.Builder(getActivity())
                                .title("Berechtigungen nicht aktiviert")
                                .content("Bitte lassen Sie in den Einstellungen die notwendigen Berechtigungen zu")
                                .positiveText("OK")
                                .show();
                    

                 else 
                    new MaterialDialog.Builder(getActivity())
                            .title("Fehler")
                            .content("Kamera konnte nicht geöffnet werden")
                            .positiveText("OK")
                            .show();
                

                return false;

            case R.id.action_gallery:

               // starting gallery activity

                return true;
            default:
                break;
        
        return false;
    

    private boolean isDeviceSupportCamera() 
        if (getActivity().getPackageManager().hasSystemFeature(
                PackageManager.FEATURE_CAMERA)) 
            // this device has a camera
            return true;
         else 
            // no camera on this device
            return false;
        

    

    private void captureImage() 
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

        fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);

        intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);

        // start the image capture Intent
        startActivityForResult(intent, CAMERA_CAPTURE_IMAGE_REQUEST_CODE);
    

    public Uri getOutputMediaFileUri(int type) 
        return Uri.fromFile(getOutputMediaFile(type));
    

    private static File getOutputMediaFile(int type) 
        File mediaStorageDir = new File(       Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + File.separator + IMAGE_DIRECTORY_NAME);

        // Create the storage directory if it does not exist
        if (!mediaStorageDir.exists()) 
            mediaStorageDir.mkdirs();

            if (!mediaStorageDir.mkdirs()) 
                Log.d(IMAGE_DIRECTORY_NAME, "Fehler beim Erstellen der Datei: "
                        + IMAGE_DIRECTORY_NAME + " directory");
                return null;
            
        

        // Create a media file name
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss",
                Locale.getDefault()).format(new Date());
        File mediaFile;

        if (type == MEDIA_TYPE_IMAGE) 
            mediaFile = new File(mediaStorageDir.getPath() + File.separator
                    + "IMG_" + timeStamp + ".jpg");
         else 
            return null;
        

        return mediaFile;
    

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) 

        try

            // if the result is capturing Image
            if (requestCode == CAMERA_CAPTURE_IMAGE_REQUEST_CODE) 
                if (resultCode == Activity.RESULT_OK) 


                    DatabaseHandler db = new DatabaseHandler(getActivity());


                    db.addImage(getIdForSelectedAnlage(), getIdForSelectedMaschine(), fileUri.toString());

                    Toast.makeText(getActivity(),
                            "Bild wurde gespeichert" + fileUri.toString(), Toast.LENGTH_SHORT)
                            .show();

                    //previewCapturedImage();
                 else if (resultCode == Activity.RESULT_CANCELED) 
                    // user cancelled Image capture
                /* Toast.makeText(getActivity(),
                        "User cancelled image capture", Toast.LENGTH_SHORT)
                        .show(); */
                 else 
                    // failed to capture image
                /* Toast.makeText(getActivity(),
                        "Sorry! Failed to capture image", Toast.LENGTH_SHORT)
                        .show(); */
                
            

         catch (Exception e) 
            e.printStackTrace();

            Toast.makeText(getActivity(),
                    "Datei konnte nicht in Datenbank gespeichert werden", Toast.LENGTH_SHORT)
                    .show();
        


    

    public boolean hasPermission(String permission)
    
        try 
            PackageInfo info = getActivity().getPackageManager().getPackageInfo(getActivity().getPackageName(), PackageManager.GET_PERMISSIONS);
            if (info.requestedPermissions != null) 
                for (String p : info.requestedPermissions) 
                    if (p.equals(permission)) 
                        return true;
                    
                
            
         catch (Exception e) 
            e.printStackTrace();
        
        return false;
    

【问题讨论】:

【参考方案1】:

我遇到过这个问题。 os 5.0.1 的三星 Galaxy S4 存在特定问题,当相机流打开时,屏幕方向改变了几次,我们的活动正在重新创建,这是根本原因。

尝试保存并恢复imageUri:

@Override
public void onCreate(@Nullable Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    if (savedInstanceState != null) 
        imageUri = savedInstanceState.getParcelable(IMAGE_URI_BUNDLE);
    

@Override
public void onSaveInstanceState(Bundle outState) 
    super.onSaveInstanceState(outState);
    outState.putParcelable(IMAGE_URI_BUNDLE, imageUri);

您应该在启动相机意图之前初始化 imageUri

private void captureImage() 
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

    imageUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);

    intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri );

    // start the image capture Intent
    startActivityForResult(intent, CAMERA_CAPTURE_IMAGE_REQUEST_CODE);

小心在片段中从相机捕获图像,在这种情况下,您还应该在片段中保存和恢复 imageUri 并添加活动:

fragment.setRetainInstance(true);

【讨论】:

我已将您的建议添加到我的代码中。但它仍然给出了同样的问题。也许由于某种原因我做错了......为了展示我所做的事情,我已将 frament 的代码添加到我以前的帖子中 您是否添加了将 imageUri 恢复到 onCreate 的代码?看看我在 onCreate() 和你的 onCreate 中的例子,这是不同的@jublikon 根本原因:多次重新创建活动,您的 imageUri 为空。您需要保存在 Bundle 中。您也可以在 AndroidManifest.xml 文件中为您的活动添加可选属性:android:configChanges="orientation|screenSize"【参考方案2】:

这是你的活动吗?包和活动名称:

com.jublikon.example.ReviewMaschine.ReviewActivity

NPE 来自于它

在此设备上,您的活动似乎在相机应用程序完成之前就被破坏了。您的活动可能会因各种原因被破坏 - 即。相机应用程序仅适用于横向,或需要大量内存并破坏您的活动。

现在,返回后 - 在 onActivityResult 之前,android 将对您的活动调用 onCreate 和 onStart。因此,您应该在此处放置断点以查找从 null 对象读取一些数据的位置。

【讨论】:

【参考方案3】:

看看您的代码,似乎 Activity 在它真正开始之前就被杀死了。

检查相机是否在横向模式下工作或尝试运行 adb 日志并查看应用程序是否由于大量内存使用或一些奇怪的编码内容而崩溃。你可以用

adb logcat -s com.jublikon.example.ReviewMaschine.ReviewActivity

之后 - 如果您不是自己发现崩溃,请在此处发布,我会尽力帮助您! :) 并检查您的应用程序从哪里开始。

编辑: 尝试在 Eclispe 中使用断点并调试你的东西! :)

【讨论】:

我在应用程序中禁用了横向模式。关键是,相机启动并工作。当我按下保存按钮时,活动在拍照后崩溃。根据您的建议,我有一个问题:手机不应该能够保存完整质量的图像吗?大量的内存使用应该从哪里来?

以上是关于Android 默认相机崩溃的主要内容,如果未能解决你的问题,请参考以下文章

Android - 相机意图导致应用程序崩溃

Android Cordova 5.0+ 相机崩溃

Android:使用相机意图时应用程序在 onActivityResult 上崩溃

世博会相机在 Android 设备上崩溃

Android SDK 相机 API 演示崩溃

Ionic 2 Android 相机/画廊崩溃