sabato 7 novembre 2015

Selezionare una foto dalla Galleria

Vediamo come selezionare un'immagine dalla Galleria usando gli intent.

Innanzitutto, occorre creare l'Intent.

public class MyFragment extends Fragment
    private static final int REQUEST_GALLERY = 100;
    ...
    private void openGallery() {    
        Intent galleryIntent = new Intent(Intent.ACTION_GET_CONTENT);
        galleryIntent.setType("image/*");
        startActivityForResult(galleryIntent, REQUEST_GALLERY);
    }

N.B. Alcuni usano Intent.ACTION_PICK ma è bene utilizzare ACTION_GET_CONTENT che è più universale (Fonte: link)
Dopodichè occorre fare l'override dell' OnActivityResult() in modo da gestire il risultato restituito dalla Galleria, cioè l'immagine.

private String mCurrentPhotoPath;
...
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    switch (requestCode) {
        case REQUEST_GALLERY:
            if (resultCode == Activity.RESULT_OK) {
                Uri selectedImageUri = data.getData();
                mCurrentPhotoPath = getPathFromUri(selectedImageUri);

                if (mCurrentPhotoPath != null) {
                    setPicInImageView();      /* Show the pic in the ImageView */
                    mCurrentPhotoPath = null;
                }
            }
            break;

    }
}

In pratica, in questo metodo si verifica se la Galleria ha ritornato l'immagine, in caso positivo si estrae l'uri della stessa in modo da poter poi ricavare il path completo (absolute path) della risorsa attraverso il metodo getPathFromUri(). Questo metodo è molto importante in quanto si basa su una classe custom che dovremo implementare, all'interno della quale dovremo specificare come ottenere il path in base alla versione di Android sulla quale sta girando l'applicazione.

Vediamo prima il codice sorgente del metodo getPathFromUri():

private String getPathFromUri(Uri uri) {
    if (Build.VERSION.SDK_INT < 11)
        return RealPathUtil.getRealPathFromURI_BelowAPI11(getContext(), uri);
    else if (Build.VERSION.SDK_INT < 19)
        return RealPathUtil.getRealPathFromURI_API11to18(getContext(), uri);
    else
        return RealPathUtil.getRealPathFromURI_API19(getContext(), uri);
}

Vediamo ora, invece, il codice sorgente della classe Util menzionata in precedenza, denominata RealPathUtil.

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.CursorLoader;
import android.database.Cursor;
import android.net.Uri;
import android.provider.DocumentsContract;
import android.provider.MediaStore;

public class RealPathUtil {

    @SuppressLint("NewApi")
    public static String getRealPathFromURI_API19(Context context, Uri uri) {
        String filePath = "";
        String wholeID = DocumentsContract.getDocumentId(uri);

        // Split at colon, use second item in the array
        String id = wholeID.split(":")[1];
        String[] column = { MediaStore.Images.Media.DATA };

        // where id is equal to
        String sel = MediaStore.Images.Media._ID + "=?";

        Cursor cursor = context.getContentResolver().query(
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI, column, sel, new String[]{ id }, null);

        assert cursor != null;
        int columnIndex = cursor.getColumnIndex(column[0]);

        if (cursor.moveToFirst()) {
            filePath = cursor.getString(columnIndex);
        }
        cursor.close();
        return filePath;
    }

    @SuppressLint("NewApi")
    public static String getRealPathFromURI_API11to18(Context context, Uri contentUri) {
        String[] proj = { MediaStore.Images.Media.DATA };
        String result = null;

        CursorLoader cursorLoader = new CursorLoader(context, contentUri, proj, null, null, null);
        Cursor cursor = cursorLoader.loadInBackground();

        if (cursor != null) {
            int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            cursor.moveToFirst();
            result = cursor.getString(column_index);
        }
        return result;
    }

    public static String getRealPathFromURI_BelowAPI11(Context context, Uri contentUri) {
        Cursor cursor = null;

        try {
            String[] proj = { MediaStore.Images.Media.DATA };
            cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
            assert cursor != null;
            int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            cursor.moveToFirst();
            return cursor.getString(column_index);
        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
    }

}

Infine, è giusto osservare il metodo setPicInImageView() che consente di visualizzare l'immagine all'interno della ImageView desiderata. E' bene sottolineare. però, che viene effettuato uno scaling dell'immagine in modo da evitare che l'app crashi producendo l'errore:

java.lang.OutofMemoryError: bitmap size exceeds VM budget

Il codice sorgente del metodo è il seguente:

private void setPicInImageView() {
    // Get the dimensions of the ImageView
    int targetW = mPicImageView.getWidth();
    int targetH = mPicImageView.getHeight();

    // Get the dimensions of the bitmap
    BitmapFactory.Options bmOptions = new BitmapFactory.Options();
    bmOptions.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(mCurrentPhotoPath, 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(mCurrentPhotoPath, bmOptions);
    mPicImageView.setImageBitmap(bitmap);
}

Per saperne di più: link (sezione: Loading Large Bitmaps Efficiently)

Nessun commento:

Posta un commento