布局/活动更改后保留上传的图片

时间:2016-07-19 17:55:03

标签: java android imageview onactivityresult android-savedstate

我仍然是Java和Android编程方面的新手,我相信我在过去的几周里走得很远,但现在我有点卡住了,我真的很感谢你的帮助。

我正在尝试开发一个可以创建用户个人资料布局的应用。到目前为止,我准备好了,从Web服务中提取用户的数据。但现在我必须为用户添加一种方式从图库或相机上传他的照片。到目前为止,我已经使用下一个代码实现了这一目标:

public void loadimage (View view)
{
    Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    startActivityForResult(intent, 0);
}

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

    if (resultCode ==  RESULT_OK)
    {
        Uri targetUri = data.getData();
        picture_location = targetUri.toString();
        textTargetUri.setText(picture_location);
        Bitmap bitmap;
        try
        {
            bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(targetUri));
            targetImage.setImageBitmap(bitmap);
        }
        catch (FileNotFoundException e)
        {
            e.printStackTrace();
        }
    }
}

这真的适用于从厨房绘制图像并在屏幕上显示路径文件(好吧,这不会成为我的最终版本)但是,当我输入另一个布局/活动时,加载的图像会消失,而我必须再次上传。我正在尝试下一个保存方法:

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState)
{
    image = savedInstanceState.getParcelable("BitmapImage");
    targetImage.setImageBitmap(image);
    textTargetUri.setText(savedInstanceState.getString("path_to_picture"));
}

@Override
public void onSaveInstanceState (Bundle savedInstanceState)
{
    super.onSaveInstanceState(savedInstanceState);
    savedInstanceState.putParcelable("BitmapImage", bitmap);
    savedInstanceState.putString("path_to_picture", picture_location);
}

但是,这仅适用于sreen orientarion更改,而不适用于布局/活动更改。即使活动发生变化,有没有办法让上传的图像保持不变?我的服务器内存非常小,所以上传到它不是一个好选择,我必须保持本地。请帮忙:(

1 个答案:

答案 0 :(得分:1)

尝试以下两种方法:

首先,向他们展示一个选择选项的对话框:

private void selectImage() {
    final CharSequence[] items = { getString(R.string.take_photo), getString(R.string.choose_from_gallery),
            getString(R.string.cancel) };

    AlertDialog.Builder builder = new AlertDialog.Builder(MyAccountActivity.this);
    builder.setTitle(getString(R.string.upload_photo));
    builder.setItems(items, new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int item) {
            if (items[item].equals(getString(R.string.take_photo))) {
                Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                startActivityForResult(intent, REQUEST_CAMERA);
            } else if (items[item].equals(getString(R.string.choose_from_gallery))) {
                Intent intent = new Intent(
                        Intent.ACTION_PICK,
                        android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                intent.setType("image/*");
                startActivityForResult(
                        Intent.createChooser(intent, getString(R.string.select_file)),
                        SELECT_FILE);
            } else if (items[item].equals(getString(R.string.choose_from_gallery))) {
                dialog.dismiss();
            }
        }
    });
    builder.show();
}

当用户拍摄照片或从照片库中选择时接收实际图像:

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

    if (resultCode == Activity.RESULT_OK) {
        if (requestCode == SELECT_FILE)
            onSelectFromGalleryResult(data);
        else if (requestCode == REQUEST_CAMERA)
            onCaptureImageResult(data);
        else if (requestCode == Crop.REQUEST_CROP) {
            handleCrop(resultCode, data);
        }
    }
}

接下来是在需要时处理裁剪 - 这个代码不是必须的,但你可以使用它;

private void onCaptureImageResult(Intent data) {

    beginCrop(data.getData());
}

@SuppressWarnings("deprecation")
private void onSelectFromGalleryResult(Intent data) {
    Uri selectedImageUri = data.getData();

    beginCrop(selectedImageUri);
}

private void beginCrop(Uri source) {
    Uri destination = Uri.fromFile(new File(getCacheDir(), "cropped"));
    Crop.of(source, destination).asSquare().start(this);
}

private void handleCrop(int resultCode, Intent result) {
    if (resultCode == RESULT_OK) {

        try {
            Bitmap bitmap = handleSamplingAndRotationBitmap(this, Crop.getOutput(result));

            saveToInternalStorage(bitmap);

            mUserProfilePhoto.setImageBitmap(readFromInternalStorage("profile.png"));
        }catch (IOException e){ /* do nothing here */}
    } else if (resultCode == Crop.RESULT_ERROR) {
        Toast.makeText(this, Crop.getError(result).getMessage(), Toast.LENGTH_SHORT).show();
    }
}

有时,如果图像不直立,您可能想要旋转图像:

private static Bitmap handleSamplingAndRotationBitmap(Context context, Uri selectedImage) throws IOException {
    int MAX_HEIGHT = 1024;
    int MAX_WIDTH = 1024;

    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    InputStream imageStream = context.getContentResolver().openInputStream(selectedImage);
    BitmapFactory.decodeStream(imageStream, null, options);
    imageStream.close();

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, MAX_WIDTH, MAX_HEIGHT);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    imageStream = context.getContentResolver().openInputStream(selectedImage);
    Bitmap img = BitmapFactory.decodeStream(imageStream, null, options);

    img = rotateImageIfRequired(img, selectedImage);
    return img;
}

private static int calculateInSampleSize(BitmapFactory.Options options,
                                         int reqWidth, int reqHeight) {
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {

        // Calculate ratios of height and width to requested height and width
        final int heightRatio = Math.round((float) height / (float) reqHeight);
        final int widthRatio = Math.round((float) width / (float) reqWidth);

        // Choose the smallest ratio as inSampleSize value, this will guarantee a final image
        // with both dimensions larger than or equal to the requested height and width.
        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;

        // This offers some additional logic in case the image has a strange
        // aspect ratio. For example, a panorama may have a much larger
        // width than height. In these cases the total pixels might still
        // end up being too large to fit comfortably in memory, so we should
        // be more aggressive with sample down the image (=larger inSampleSize).

        final float totalPixels = width * height;

        // Anything more than 2x the requested pixels we'll sample down further
        final float totalReqPixelsCap = reqWidth * reqHeight * 2;

        while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
            inSampleSize++;
        }
    }
    return inSampleSize;
}

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

用于在用户从图库中选择或从相机中选择时进行存储:

private boolean saveToInternalStorage(Bitmap image) {

    try {
        FileOutputStream fos = this.openFileOutput("profile.png", Context.MODE_PRIVATE);

        image.compress(Bitmap.CompressFormat.PNG, 100, fos);
        fos.close();

        return true;
    } catch (Exception e) {
        return false;
    }
}

现在从存储中读取:

private Bitmap readFromInternalStorage(String filename){
    try {
        File filePath = this.getFileStreamPath(filename);
        FileInputStream fi = new FileInputStream(filePath);
        return BitmapFactory.decodeStream(fi);
    } catch (Exception ex) { /* do nothing here */}

    return null;
}

在onResume中,我有这个代码将图像设置为imageview:

@Override
public void onResume(){
    super.onResume();

    Bitmap savedProfilePhoto = readFromInternalStorage("profile.png");

    if (savedProfilePhoto != null){
        mUserProfilePhoto.setImageBitmap(savedProfilePhoto);
    }
}

几乎在这里完成:

将此添加到您的依赖项(build.gradle)

dependencies{
     compile 'com.soundcloud.android:android-crop:1.0.1@aar'
 }

最后,在您的Android清单文件中,要使裁剪库工作,请添加:

<activity android:name="com.soundcloud.android.crop.CropImageActivity"/>

这就是您在应用程序内使用相机从图库中选择图像或拍照时所需的一切!

我希望这可以帮助你和其他有需要的人,祝你好运!