编辑
Android上传图片
本文访问次数:0
  1. 1. 介绍
  2. 2. 获取图片
    1. 2.1. 通过选取图片的方式
      1. 2.1.1. 获取选区的图片
    2. 2.2. 通过照相的方式
      1. 2.2.1. 获取图片
  3. 3. 上传图片
  4. 4. 剪切图片
  5. 5. 获取指定大小的Bitmap
  6. 6. 将照片加入图库

介绍

这篇文章主要讲了如何通过选择图片或者拍照的方式获取图片并上传到服务器上,上传图片用到了nohttp框架,其他网络框架下略有不同,不再赘述。以下代码基于Android Studio。

获取图片

要想上传图片,首先要获取图片的路径,获取的方法主要分为选择已经存在的图片和通过各种照相机应用保存一张图片。

通过选取图片的方式

选择图片比较简单,请参考以下代码,首先是创建Intent

Intent getIntent = new Intent(Intent.ACTION_GET_CONTENT);
getIntent.setType("image/*");
Intent chooserIntent = Intent.createChooser(getIntent, getString(R.string.pickImage));
startActivityForResult(chooserIntent, RequestCode.PICK_PHOTO.getValue());

也可以使用以下代码直接打开图库应用

Intent pickIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(pickIntent, RequestCode.PICK_PHOTO.getValue());

获取选区的图片

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (RequestCode.valueOf(requestCode)) {
        case PICK_PHOTO:
            if (resultCode == Activity.RESULT_OK && data != null && data.getData() != null) {
                fullSizeImageUri = data.getData();
                File imageFile = new File(fullSizeImageUri.getPath());
                uploadFile(imageFile);
            }
            break;
    }
}

通过照相的方式

通过照相机应用获取图片稍微麻烦一点,首先需要创建Provider并声明读取外部存储的权限,在AndroidManifest.xml中写入以下代码

<manifest>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <application>
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.domain.appname.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths"/>
        </provider>
        ...
    </application>
</manifest>

注意将com.domain.appname替换为对应的包名。
res目录下创建xml文件夹,然后在xml目录下创建file_paths.xml文件,并写入以下内容

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path
        name="images"
        path="Android/data/com.domain.appname/files/Pictures"/>
</paths>

接下来就是创建Intent

Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getActivity().getPackageManager()) != null) {
    // Create the File where the photo should go
    File photoFile = null;
    try {
        photoFile = createImageFile("photo");
        //保存这个图片的绝对地址,在onActivityResult中使用
        mCurrentImagePath = photoFile.getAbsolutePath();
    } catch (IOException ex) {
        // Error occurred while creating the File
        Log.e(TAG,"Fail to create image file,error is "+ex.getMessage());
    }
    // Continue only if the File was successfully created
    if (photoFile != null) {
        Uri photoURI = FileProvider.getUriForFile(getContext(),
                "com.domain.appname.fileprovider",
                photoFile);
        takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);

        //如果不加入以下代码,4.X的机器会崩溃(未严格测试)
        List<ResolveInfo> resolveInfoList = getContext().getPackageManager().queryIntentActivities(takePictureIntent, PackageManager.MATCH_DEFAULT_ONLY);
        for (ResolveInfo resolveInfo : resolveInfoList) {
            String packageName = resolveInfo.activityInfo.packageName;
            getContext().grantUriPermission(packageName, photoURI, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
        }

        startActivityForResult(takePictureIntent, RequestCode.TAKE_PHOTO.getValue());
    }
}
else{
    Toast.makeText(getContext(),R.string.deviceNotSupportCamera,Toast.LENGTH_SHORT).show();
}

以下为createImageFile函数的代码,创建一个文件供相机应用写入

private File createImageFile(String prefix) throws IOException {
    File storageDir = getActivity().getExternalFilesDir(Environment.DIRECTORY_PICTURES);
    return File.createTempFile(
            prefix,
            ".jpg",
            storageDir
    );
}

获取图片

相机应用会把图片存到指定的位置,然后在onActivityResult中使用mCurrentImagePath获取图片文件

public void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (RequestCode.valueOf(requestCode)) {
        case PICK_PHOTO:
            //因为相机应用不会返回数据,所以data=null
            if (resultCode == Activity.RESULT_OK) {
                File imageFile = new File(mCurrentImagePath);
                uploadFile(imageFile);
            }
            break;
    }
}

上传图片

以下为uploadFile函数的代码,使用nohttp框架上传图片文件

private void uploadFile(File imageFile) {
    Request<String> request = new StringRequest(Constant.API_USER_PROFILE_UPLOAD,RequestMethod.POST);
    BasicBinary binary = new FileBinary(imageFile);
    binary.setUploadListener(UPLOAD_IMAGE, mUploadListener);
    request.add("load_img", binary);
    addRequest(request);
}
private OnUploadListener mUploadListener = new OnUploadListener() {
    @Override
    public void onStart(int what) {
        mProgressDialog.setMessage(getString(R.string.uploadStart));
        mProgressDialog.show();
    }

    @Override
    public void onCancel(int what) {
        mProgressDialog.setMessage(getString(R.string.uploadCanceled));
        mProgressDialog.hide();
    }

    @Override
    public void onProgress(int what, int progress) {// 这个文件的上传进度发生边耍
        mProgressDialog.setProgress(progress);
    }

    @Override
    public void onFinish(int what) {
        mProgressDialog.setMessage(getString(R.string.uploadFinish));
        mProgressDialog.hide();
    }

    @Override
    public void onError(int what, Exception exception) {
        mProgressDialog.setMessage(String.format(getString(R.string.uploadError),exception.getMessage()));
        mProgressDialog.hide();
    }
};

剪切图片

通过Android-Image-Cropper剪切图片,具体使用方法请参考该项目的github主页

private void cropImage(Uri imageUri, Uri outputUri) {
    CropImage.activity(imageUri)
        .setOutputUri(outputUri)
        .setFixAspectRatio(true)
        .setAspectRatio(1, 1)
        .setMaxCropResultSize(1000, 1000)
        .setGuidelines(CropImageView.Guidelines.ON)
        .start(getActivity(), this);
}

获取指定大小的Bitmap

如果直接使用完整尺寸的照片显示在屏幕上,图片稍微多一点就会发生内存泄漏事件,最好的办法是根据ImageView的大小获取缩小版Bitmap,代码如下

private void setImage(ImageView imageView, String imagePath) {
    // Get the dimensions of the View
    int targetW = imageView.getWidth();
    int targetH = imageView.getHeight();

    // Get the dimensions of the bitmap
    BitmapFactory.Options bmOptions = new BitmapFactory.Options();
    bmOptions.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(imagePath, bmOptions);
    int photoW = bmOptions.outWidth;
    int photoH = bmOptions.outHeight;

    // Determine how much to scale down the image
    int scaleFactor = Math.min(photoW / targetW, photoH / targetH);

    // Decode the image file into a Bitmap sized to fill the View
    bmOptions.inJustDecodeBounds = false;
    bmOptions.inSampleSize = scaleFactor;
    bmOptions.inPurgeable = true;

    Bitmap bitmap = BitmapFactory.decodeFile(imagePath, bmOptions);
    imageView.setImageBitmap(bitmap);
}

将照片加入图库

通过你的应用拍摄的照片是不会自动加入到图库中的,需要使用以下代码调用系统媒体扫描器,将图片加入到媒体提供数据库(Media Provider’s database)

private void galleryAddImage(String imagePath) {
    Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
    File imageFile = new File(imagePath);
    Uri contentUri = Uri.fromFile(imageFile);
    mediaScanIntent.setData(contentUri);
    getActivity().sendBroadcast(mediaScanIntent);
}
没有任何评论