android 崩溃捕获_Android从相机和图库捕获图像

android 崩溃捕获

In this tutorial we’ll develop an application that picks an image from camera or gallery and display that in an ImageView.

在本教程中,我们将开发一个应用程序,该应用程序从相机或画廊中拾取图像并将其显示在ImageView中。

Android Capture图像概述 (Android Capture Image Overview)

With the commence of Android Marshmallow, runtime permissions need to be implemented forefront.

随着Android Marshmallow的开始,需要首先实现运行时权限。

Add the following permissions in the Android Manifest.xml file, above the application tag.

在Android Manifest.xml文件中的应用程序标签上方添加以下权限。

<uses-feature
        android:name="android.hardware.camera"
        android:required="false" />
    <uses-feature
        android:name="android.hardware.camera.autofocus"
        android:required="false" />
    <uses-feature
        android:name="android.hardware.camera.flash"
        android:required="false" />

    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="ANDROID.PERMISSION.READ_EXTERNAL_STORAGE"/>

By adding android.hardware.camera, Play Store detects and prevents installing the application on devices with no camera.

通过添加android.hardware.camera ,Play商店可以检测并阻止在没有相机的设备上安装该应用程序。

Intent is the standard way to delegate actions to another application.
To start the native camera the Intent requires android.provider.MediaStore.ACTION_IMAGE_CAPTURE.

意图是将动作委派给另一个应用程序的标准方法。
要启动本机相机,Intent需要android.provider.MediaStore.ACTION_IMAGE_CAPTURE

To choose an image from gallery, the Intent requires the following argument : Intent.ACTION_GET_CONTENT.

要从图库中选择图像,Intent需要以下参数: Intent.ACTION_GET_CONTENT

In this tutorial we’ll be invoking an image picker, that lets us select an image from camera or gallery and displays the image in a circular image view and a normal image view. Add the following dependency inside the build.gradle file.
compile 'de.hdodenhof:circleimageview:2.1.0'

在本教程中,我们将调用图像选择器,使我们可以从照相机或图库中选择图像,并以圆形图像视图和普通图像视图显示该图像。 在build.gradle文件中添加以下依赖项。
compile 'de.hdodenhof:circleimageview:2.1.0'

Android Image Capture项目结构 (Android Image Capture Project Structure)

Android Capture图像代码 (Android Capture Image Code)

The layout for the activity_main.xml stays the same barring the icon change for the FAB button to @android:drawable/ic_menu_camera.

activity_main.xml的布局保持不变,除非将FAB按钮的图标更改更改为@android:drawable/ic_menu_camera

The content_main.xml is given below:

content_main.xml如下所示:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    xmlns:tools="https://schemas.android.com/tools"
    android:id="@+id/content_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:background="#000000"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.journaldev.imagepicker.MainActivity"
    tools:showIn="@layout/activity_main">


    <RelativeLayout
        android:layout_width="250dp"
        android:layout_height="250dp"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:background="@drawable/image_border"
        android:clickable="true"
        android:orientation="vertical">


        <ImageView
            android:id="@+id/imageView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:adjustViewBounds="true"
            android:scaleType="centerCrop" />

    </RelativeLayout>

    <de.hdodenhof.circleimageview.CircleImageView
        android:id="@+id/img_profile"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_gravity="center_horizontal"
        android:src="@drawable/profile"
        app:civ_border_width="5dp"
        app:civ_border_color="#FFFFFF"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true" />

</RelativeLayout>

The code for the MainActivity.java is given below

MainActivity.java的代码如下

public class MainActivity extends AppCompatActivity {

    Bitmap myBitmap;
    Uri picUri;


    private ArrayList permissionsToRequest;
    private ArrayList permissionsRejected = new ArrayList();
    private ArrayList permissions = new ArrayList();

    private final static int ALL_PERMISSIONS_RESULT = 107;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startActivityForResult(getPickImageChooserIntent(), 200);
            }
        });


        permissions.add(CAMERA);
        permissionsToRequest = findUnAskedPermissions(permissions);
        //get the permissions we have asked for before but are not granted..
        //we will store this in a global list to access later.


        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {


            if (permissionsToRequest.size() > 0)
                requestPermissions(permissionsToRequest.toArray(new String[permissionsToRequest.size()]), ALL_PERMISSIONS_RESULT);
        }

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }


    /**
     * Create a chooser intent to select the source to get image from.<br />
     * The source can be camera's (ACTION_IMAGE_CAPTURE) or gallery's (ACTION_GET_CONTENT).<br />
     * All possible sources are added to the intent chooser.
     */
    public Intent getPickImageChooserIntent() {

        // Determine Uri of camera image to save.
        Uri outputFileUri = getCaptureImageOutputUri();

        List allIntents = new ArrayList();
        PackageManager packageManager = getPackageManager();

        // collect all camera intents
        Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
        List listCam = packageManager.queryIntentActivities(captureIntent, 0);
        for (ResolveInfo res : listCam) {
            Intent intent = new Intent(captureIntent);
            intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
            intent.setPackage(res.activityInfo.packageName);
            if (outputFileUri != null) {
                intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
            }
            allIntents.add(intent);
        }

        // collect all gallery intents
        Intent galleryIntent = new Intent(Intent.ACTION_GET_CONTENT);
        galleryIntent.setType("image/*");
        List listGallery = packageManager.queryIntentActivities(galleryIntent, 0);
        for (ResolveInfo res : listGallery) {
            Intent intent = new Intent(galleryIntent);
            intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
            intent.setPackage(res.activityInfo.packageName);
            allIntents.add(intent);
        }

        // the main intent is the last in the list (fucking android) so pickup the useless one
        Intent mainIntent = allIntents.get(allIntents.size() - 1);
        for (Intent intent : allIntents) {
            if (intent.getComponent().getClassName().equals("com.android.documentsui.DocumentsActivity")) {
                mainIntent = intent;
                break;
            }
        }
        allIntents.remove(mainIntent);

        // Create a chooser from the main intent
        Intent chooserIntent = Intent.createChooser(mainIntent, "Select source");

        // Add all other intents
        chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, allIntents.toArray(new Parcelable[allIntents.size()]));

        return chooserIntent;
    }


    /**
     * Get URI to image received from capture by camera.
     */
    private Uri getCaptureImageOutputUri() {
        Uri outputFileUri = null;
        File getImage = getExternalCacheDir();
        if (getImage != null) {
            outputFileUri = Uri.fromFile(new File(getImage.getPath(), "profile.png"));
        }
        return outputFileUri;
    }

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

        Bitmap bitmap;
        if (resultCode == Activity.RESULT_OK) {

            ImageView imageView = (ImageView) findViewById(R.id.imageView);

            if (getPickImageResultUri(data) != null) {
                picUri = getPickImageResultUri(data);

                try {
                    myBitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), picUri);
                    myBitmap = rotateImageIfRequired(myBitmap, picUri);
                    myBitmap = getResizedBitmap(myBitmap, 500);

                    CircleImageView croppedImageView = (CircleImageView) findViewById(R.id.img_profile);
                    croppedImageView.setImageBitmap(myBitmap);
                    imageView.setImageBitmap(myBitmap);

                } catch (IOException e) {
                    e.printStackTrace();
                }


            } else {


                bitmap = (Bitmap) data.getExtras().get("data");

                myBitmap = bitmap;
                CircleImageView croppedImageView = (CircleImageView) findViewById(R.id.img_profile);
                if (croppedImageView != null) {
                    croppedImageView.setImageBitmap(myBitmap);
                }

                imageView.setImageBitmap(myBitmap);

            }

        }

    }

    private static Bitmap rotateImageIfRequired(Bitmap img, Uri selectedImage) throws IOException {

        ExifInterface ei = new ExifInterface(selectedImage.getPath());
        int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);

        switch (orientation) {
            case ExifInterface.ORIENTATION_ROTATE_90:
                return rotateImage(img, 90);
            case ExifInterface.ORIENTATION_ROTATE_180:
                return rotateImage(img, 180);
            case ExifInterface.ORIENTATION_ROTATE_270:
                return rotateImage(img, 270);
            default:
                return img;
        }
    }

    private static Bitmap rotateImage(Bitmap img, int degree) {
        Matrix matrix = new Matrix();
        matrix.postRotate(degree);
        Bitmap rotatedImg = Bitmap.createBitmap(img, 0, 0, img.getWidth(), img.getHeight(), matrix, true);
        img.recycle();
        return rotatedImg;
    }

    public Bitmap getResizedBitmap(Bitmap image, int maxSize) {
        int width = image.getWidth();
        int height = image.getHeight();

        float bitmapRatio = (float) width / (float) height;
        if (bitmapRatio > 0) {
            width = maxSize;
            height = (int) (width / bitmapRatio);
        } else {
            height = maxSize;
            width = (int) (height * bitmapRatio);
        }
        return Bitmap.createScaledBitmap(image, width, height, true);
    }


    /**
     * Get the URI of the selected image from {@link #getPickImageChooserIntent()}.<br />
     * Will return the correct URI for camera and gallery image.
     *
     * @param data the returned data of the activity result
     */
    public Uri getPickImageResultUri(Intent data) {
        boolean isCamera = true;
        if (data != null) {
            String action = data.getAction();
            isCamera = action != null && action.equals(MediaStore.ACTION_IMAGE_CAPTURE);
        }


        return isCamera ? getCaptureImageOutputUri() : data.getData();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);

        // save file url in bundle as it will be null on scren orientation
        // changes
        outState.putParcelable("pic_uri", picUri);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);

        // get the file url
        picUri = savedInstanceState.getParcelable("pic_uri");
    }

    private ArrayList findUnAskedPermissions(ArrayList wanted) {
        ArrayList result = new ArrayList();

        for (String perm : wanted) {
            if (!hasPermission(perm)) {
                result.add(perm);
            }
        }

        return result;
    }

    private boolean hasPermission(String permission) {
        if (canMakeSmores()) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                return (checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED);
            }
        }
        return true;
    }

    private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
        new AlertDialog.Builder(this)
                .setMessage(message)
                .setPositiveButton("OK", okListener)
                .setNegativeButton("Cancel", null)
                .create()
                .show();
    }

    private boolean canMakeSmores() {
        return (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1);
    }

    @TargetApi(Build.VERSION_CODES.M)
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {

        switch (requestCode) {

            case ALL_PERMISSIONS_RESULT:
                for (String perms : permissionsToRequest) {
                    if (hasPermission(perms)) {

                    } else {

                        permissionsRejected.add(perms);
                    }
                }

                if (permissionsRejected.size() > 0) {


                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                        if (shouldShowRequestPermissionRationale(permissionsRejected.get(0))) {
                            showMessageOKCancel("These permissions are mandatory for the application. Please allow access.",
                                    new DialogInterface.OnClickListener() {
                                        @Override
                                        public void onClick(DialogInterface dialog, int which) {
                                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

                                                //Log.d("API123", "permisionrejected " + permissionsRejected.size());

                                                requestPermissions(permissionsRejected.toArray(new String[permissionsRejected.size()]), ALL_PERMISSIONS_RESULT);
                                            }
                                        }
                                    });
                            return;
                        }
                    }

                }

                break;
        }

    }
}

There are a lot of inferences to be drawn from the code above.

从上面的代码中可以得出很多推断。

  • We need to ask for the Camera runtime permissions when the user starts the activity.

    当用户启动活动时,我们需要请求Camera运行时权限。
  • As we are starting the intent to get some result back, we need to call startActivityForResult with the relevant arguments

    在开始获取一些结果的意图时,我们需要使用相关参数调用startActivityForResult
  • Instead of using a dialog to separately call the Intents for Camera and Gallery, we’ve used a method getPickImageChooserIntent() that creates a single chooser intent for all the camera and gallery intents(note the documents intent). Intent.EXTRA_INITIAL_INTENTS is used to add the multiple application intents at one place

    我们没有使用对话框来单独调用“相机和画廊的意图”,而是使用了getPickImageChooserIntent()方法,该方法为所有相机和画廊的意图创建一个选择器意图(请注意文档的意图)。 Intent.EXTRA_INITIAL_INTENTS用于在一个位置添加多个应用程序意图
  • For the camera intent, MediaStore.EXTRA_OUTPUT is passed as an extra to specify the image storage path. Without this you’ll be returned only a small resolution image.

    对于摄像机意图,将传递MediaStore.EXTRA_OUTPUT作为额外内容以指定图像存储路径。 没有这个,您将只得到一个小分辨率的图像。
  • The URI path for the image returned by camera is fetched inside the method getCaptureImageOutputUri().

    相机返回的图像的URI路径在方法getCaptureImageOutputUri()
  • The onActivityResult essentially returns a URI to the image. Some devices do return the bitmap as data.getExtras().get("data");.

    onActivityResult本质上返回图像的URI。 某些设备确实将位图作为data.getExtras().get("data");
  • When an image is clicked, the camera screen while returning restarts the activity thereby causing the URI stored from the method getCaptureImageOutputUri() to become null.
    Hence it’s essential that we store and restore that URI using onSaveInstanceState() and onRestoreInstanceState().

    单击图像后,返回时的相机屏幕将重新启动活动,从而使从方法getCaptureImageOutputUri()存储的URI变为空。
    因此,必须使用onSaveInstanceState()onRestoreInstanceState()存储和还原该URI。
  • The bitmap is retrieved from the URI in the following line of code.
    myBitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), picUri);

    在下面的代码行中,从URI中检索位图。
    myBitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), picUri);
  • Devices like Samsung galaxy are known to capture the image in landscape orientation. Retrieving the image and displaying as it is can cause it to be displayed in the wrong orientation. Hence we’ve called the method rotateImageIfRequired(myBitmap, picUri);

    众所周知,三星银河等设备可以横向捕获图像。 检索图像并按原样显示可能会导致其显示方向错误。 因此,我们将方法称为rotateImageIfRequired(myBitmap, picUri);
  • ExifInterface is a class for reading and writing Exif tags in a JPEG file or a RAW image file.

    ExifInterface是用于在JPEG文件或RAW图像文件中读写Exif标签的类。
  • In the end we call the method getResizedBitmap() to scale the bitmap by width or height(whichever is larger) and set the image to the image view using setImageBitmap.

    最后,我们调用方法getResizedBitmap()以按宽度或高度(以较大者为准缩放位图,并使用setImageBitmap将图像设置为图像视图。

The output of the application in action is given below. Note: To capture and display an image from camera you’ll need to run the application on a smartphone for obvious reasons.

实际应用程序的输出如下。 注意:要从相机捕获并显示图像,出于明显的原因,您需要在智能手机上运行该应用程序。

This brings an end to this tutorial. You can download the Android project for Image Capture from the link below.

本教程到此结束。 您可以从下面的链接下载用于Image Capture的Android项目。

翻译自: https://www.journaldev.com/13270/android-capture-image-camera-gallery

android 崩溃捕获

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值