Android从相机获取URI [英] Android getting URI from Camera

查看:79
本文介绍了Android从相机获取URI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Nexus 5上使用相机拍摄照片时遇到问题.我可以从图库中毫无问题地拍摄照片并将其保存到后端.但是,当我尝试使用相机拍照时,在拍照并选择勾号后,应用程序崩溃了... 我可以看到传递给onActivityResult()的意图是空的,但是我不知道如何解决这个问题.有人可以帮忙吗?谢谢.

I am having an issue when taking a photo with the camera on my Nexus 5. I can take photos from the gallery no problem and save them to the back end. However when I try to take a picture using the camera, after I take the picture and select the tick, then the app crashes... I can see that the intent passed to the onActivityResult() is empty but I don't know how to fix this. Can anyone help? thanks.

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Toast;

import com.khackett.runmate.R;
import com.khackett.runmate.utils.FileHelper;
import com.khackett.runmate.utils.ParseConstants;
import com.parse.ParseException;
import com.parse.ParseFile;
import com.parse.ParseUser;
import com.parse.SaveCallback;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;


public class MyProfileFragment extends Fragment implements View.OnClickListener {

    public static final String TAG = MyProfileFragment.class.getSimpleName();

    protected Button mTakePicture;
    protected Button mChoosePicture;

    /**
     * Default constructor
     */
    public MyProfileFragment() {
    }

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

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View rootView = inflater.inflate(R.layout.fragment_my_profile, container, false);

        mTakePicture = (Button) rootView.findViewById(R.id.takePictureButton);
        mChoosePicture = (Button) rootView.findViewById(R.id.choosePictureButton);

        mTakePicture.setOnClickListener(this);
        mChoosePicture.setOnClickListener(this);

        return rootView;

    }

    /**
     * Called when a view has been clicked.
     *
     * @param v The view that was clicked.
     */
    @Override
    public void onClick(View v) {
        // Switch statement to select which action to take depending on button/text pressed
        switch (v.getId()) {
            case R.id.takePictureButton:
                takeCameraPicture();
                break;
            case R.id.choosePictureButton:
                chooseGalleryPicture();
                break;
            default:
                System.out.println("Problem with input");
        }
    }

    public static final int TAKE_PHOTO_REQUEST = 1888;
    public static final int PICK_PHOTO_REQUEST = 1888;
    private static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 1888;

    // member variable to store the media type as a URI, that can be stored in multiple places
    // Uri = uniform resource identifier
    protected Uri mMediaUri;

    public void takeCameraPicture() {
        // Take picture
        // use an existing camera app on the phone by starting an intent
        // declare intent to capture a photo using whatever camera app is available
        Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        // after invoking the camera,
        mMediaUri = getOutputMediaFileUri();

        // check that a null value is not returned
        if (mMediaUri == null) {
            // display an error
            Toast.makeText(getActivity(), R.string.error_external_storage, Toast.LENGTH_LONG).show();
        } else {
            // to add extra data to an intent, use the putExtra() method
            takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT, mMediaUri);
            // start an activity for a result so that the activity exits and returns a result back for us
            // ie, the main activity will wait for the result
            startActivityForResult(takePhotoIntent, TAKE_PHOTO_REQUEST);
        }
    }

    public void chooseGalleryPicture() {
        // Choose picture
        Intent choosePhotoIntent = new Intent(Intent.ACTION_GET_CONTENT);
        // need to specify which type of action we want to get - an image in this case
        choosePhotoIntent.setType("image/*");
        startActivityForResult(choosePhotoIntent, PICK_PHOTO_REQUEST);
    }

    private Uri getOutputMediaFileUri() {
        // To be safe, you should check that the SD card / external storage is mounted
        // using Environment.getExternalStorageState() before doing this.
        // see method below...
        if (isExternalStorageAvailable()) {
            String appName = MyProfileFragment.this.getString(R.string.app_name);
            // get the Uri

            // Get the external storage directory - we want to return a file object
            File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), appName);

            // Create our subdirectory
            if (!mediaStorageDir.exists()) {
                if (!mediaStorageDir.mkdir()) {
                    Log.e(TAG, "Failed to create directory");
                    return null;
                }
            }

            // Create a file to hold the image
            File mediaFile;
            // get the current date and time
            Date now = new Date();
            // convert the date and time into a String datetimestamp
            // see http://developer.android.com/guide/topics/media/camera.html#saving-media for the methods used
            // need to append a timestamp to make it unique - otherwise it will overwrite the previous photo
            String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ENGLISH).format(now);

            String path = mediaStorageDir.getPath() + File.separator;

            // create a new file using the constructor that takes a name

            mediaFile = new File(path + "IMG_" + timestamp + ".jpg");

            Log.d(TAG, "File: " + Uri.fromFile(mediaFile));

            // Return the files URI
            Log.d(TAG, "Returning the files URI");
            return Uri.fromFile(mediaFile);
        } else {
            return null;
        }
    }

    /**
     * check if external storage is available on the users device
     *
     * @return
     */
    private boolean isExternalStorageAvailable() {
        // find out what state external storage is in
        String state = Environment.getExternalStorageState();
        // if external storage is available, return true,
        if (state.equals(Environment.MEDIA_MOUNTED)) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (resultCode == Activity.RESULT_OK) {
            if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) {
                if (data == null) {
                    Log.d(TAG, "Data is null");
                    Toast.makeText(getActivity(), getString(R.string.general_error), Toast.LENGTH_LONG).show();
                } else {
                    Log.d(TAG, "Data: " + data);
                    // the intent has data, so set the media uri
                    Log.d(TAG, "adding the data using the getData() method");
                    mMediaUri = data.getData();
                    Log.d(TAG, "Media Uri: " + mMediaUri);
                }


                // ParseUser.getCurrentUser().put("profilePic", mMediaUri);

                saveImageToParse();

            }
        } else if (resultCode != Activity.RESULT_CANCELED) {
            Log.d(TAG, "Problem getting the picture from gallery");
            // Toast.makeText(getActivity(), R.string.general_error, Toast.LENGTH_LONG).show();
        }
    }

    public void saveImageToParse() {
        Log.d(TAG, "entering saveImageToParse() method");
        byte[] fileBytes = FileHelper.getByteArrayFromFile(getActivity(), mMediaUri);

        fileBytes = FileHelper.reduceImageForUpload(fileBytes);

        String fileName = FileHelper.getFileName(getActivity(), mMediaUri, "file");
        ParseFile file = new ParseFile(fileName, fileBytes);
        ParseUser.getCurrentUser().put("profilePic", file);

        ParseUser.getCurrentUser().saveInBackground(new SaveCallback() {
            public void done(ParseException e) {
                if (e == null) {
                    Log.d(TAG, "Image saved successfully");
                    // myObjectSavedSuccessfully();
                } else {
                    Log.d(TAG, "Image not saved");
                    // myObjectSaveDidNotSucceed();
                }
            }
        });

    }

.

package com.khackett.runmate.utils;

import android.content.Context;
import android.graphics.Bitmap;
import android.net.Uri;
import android.util.Log;

import org.apache.commons.io.IOUtils;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

// https://github.com/treehouse/treehouse_android_utilities
public class FileHelper {

    public static final String TAG = FileHelper.class.getSimpleName();

    public static final int SHORT_SIDE_TARGET = 1280;

    public static byte[] getByteArrayFromFile(Context context, Uri uri) {
        byte[] fileBytes = null;
        InputStream inStream = null;
        ByteArrayOutputStream outStream = null;
        Log.d(TAG, "in the getByteArrayFromFile() method");

        if (uri.getScheme() != null && uri.getScheme().equals("content")) {
            try {
                Log.d(TAG, "entering try to set inputstream");
                inStream = context.getContentResolver().openInputStream(uri);
                outStream = new ByteArrayOutputStream();

                byte[] bytesFromFile = new byte[1024 * 1024]; // buffer size (1 MB)
                int bytesRead = inStream.read(bytesFromFile);
                while (bytesRead != -1) {
                    outStream.write(bytesFromFile, 0, bytesRead);
                    bytesRead = inStream.read(bytesFromFile);
                }

                fileBytes = outStream.toByteArray();
            } catch (IOException e) {
                Log.e(TAG, e.getMessage());
            } finally {
                try {
                    inStream.close();
                    outStream.close();
                } catch (IOException e) { /*( Intentionally blank */ }
            }
        } else {
            try {
                File file = new File(uri.getPath());
                FileInputStream fileInput = new FileInputStream(file);
                fileBytes = IOUtils.toByteArray(fileInput);
            } catch (IOException e) {
                Log.e(TAG, e.getMessage());
            }
        }

        return fileBytes;
    }

    public static byte[] reduceImageForUpload(byte[] imageData) {
        Bitmap bitmap = ImageResizer.resizeImageMaintainAspectRatio(imageData, SHORT_SIDE_TARGET);

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
        byte[] reducedData = outputStream.toByteArray();
        try {
            outputStream.close();
        } catch (IOException e) {
            // Intentionally blank
        }

        return reducedData;
    }

    public static String getFileName(Context context, Uri uri, String fileType) {
        String fileName = "uploaded_file.";

        if (fileType.equals(ParseConstants.TYPE_IMAGE)) {
            fileName += "png";
        } else {
            // For video, we want to get the actual file extension
            if (uri.getScheme().equals("content")) {
                // do it using the mime type
                String mimeType = context.getContentResolver().getType(uri);
                int slashIndex = mimeType.indexOf("/");
                String fileExtension = mimeType.substring(slashIndex + 1);
                fileName += fileExtension;
            } else {
                fileName = uri.getLastPathSegment();
            }
        }

        return fileName;
    }
}

.

09-01 20:15:49.322  23271-23271/com.khackett.runmate E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.khackett.runmate, PID: 23271
    java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=67424, result=-1, data=Intent {  }} to activity {com.khackett.runmate/com.khackett.runmate.ui.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.net.Uri.getScheme()' on a null object reference
            at android.app.ActivityThread.deliverResults(ActivityThread.java:3574)
            at android.app.ActivityThread.handleSendResult(ActivityThread.java:3617)
            at android.app.ActivityThread.access$1300(ActivityThread.java:151)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1352)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5254)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.net.Uri.getScheme()' on a null object reference
            at com.khackett.runmate.utils.FileHelper.getByteArrayFromFile(FileHelper.java:29)
            at com.khackett.runmate.ui.MyProfileFragment.saveImageToParse(MyProfileFragment.java:233)
            at com.khackett.runmate.ui.MyProfileFragment.onActivityResult(MyProfileFragment.java:210)
            at android.support.v4.app.FragmentActivity.onActivityResult(FragmentActivity.java:165)
            at android.app.Activity.dispatchActivityResult(Activity.java:6192)
            at android.app.ActivityThread.deliverResults(ActivityThread.java:3570)
            at android.app.ActivityThread.handleSendResult(ActivityThread.java:3617)
            at android.app.ActivityThread.access$1300(ActivityThread.java:151)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1352)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5254)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)

推荐答案

从日志和您的代码中,您可以跟踪到mMediaUri为空.

From the log, and your code, you can track that it is mMediaUri being null.

这应该是由于屏幕旋转而导致的活动重新创建引起的,例如,如果您的应用程序通常以纵向运行,而相机强制为横向运行,或者您在使用相机时旋转了.

This should be caused by activity recreate because of screen rotation, for example, if your app usually run in Portrait, while the camera force to Landscape or you rotated when you use camera.

无论如何要解决此问题,您都必须保存mMediaUrl并将其还原到onCreate中,像这样修改您的片段:

Anyway to solve this, you have to save the mMediaUrl and restore it in onCreate, modify your Fragment like this:

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    // Save the user's current state
    savedInstanceState.putString("media_url", mMediaUrl.toString());

    // Always call the superclass so it can save the view hierarchy state
    super.onSaveInstanceState(savedInstanceState);
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (savedInstanceState != null) {
        mMediaUrl = Uri.parse(savedInstanceState.getString("media_url"));
    }
}

注意到另一个问题,请更改以下内容:

noticed another problem, change the followings:

public static final int TAKE_PHOTO_REQUEST = 1889;
public static final int PICK_PHOTO_REQUEST = 1888;

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (resultCode == Activity.RESULT_OK) {
        if (requestCode == PICK_PHOTO_REQUEST) {
            if (data == null) {
                Log.d(TAG, "Data is null");
                Toast.makeText(getActivity(), getString(R.string.general_error), Toast.LENGTH_LONG).show();
            } else {
                Log.d(TAG, "Data: " + data);
                // the intent has data, so set the media uri
                Log.d(TAG, "adding the data using the getData() method");
                mMediaUri = data.getData();
                Log.d(TAG, "Media Uri: " + mMediaUri);
            }


            // ParseUser.getCurrentUser().put("profilePic", mMediaUri);

            saveImageToParse();

        } else if(requestCode  == TAKE_PHOTO_REQUEST) {
            saveImageToParse();
        }
    } else if (resultCode != Activity.RESULT_CANCELED) {
        Log.d(TAG, "Problem getting the picture from gallery");
        // Toast.makeText(getActivity(), R.string.general_error, Toast.LENGTH_LONG).show();
    }
}

这篇关于Android从相机获取URI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆