Monday, September 7, 2015

Intent.ACTION_OPEN_DOCUMENT to load images in RecyclerView + CardView

Last exercise show how to "Open multi files using Intent.ACTION_OPEN_DOCUMENT, with EXTRA_ALLOW_MULTIPLE and getClipData()". Here modify to load returned images in RecyclerView + CardView.



To use RecyclerView + CardView, we have to "Add Support Libraries of RecyclerView, CardView to Android Studio Project".

layout/layout_cardview.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="10dp"
    card_view:cardCornerRadius="20sp"
    card_view:cardElevation="5sp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <ImageView
            android:id="@+id/item_image"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
        <TextView
            android:id="@+id/item_uri"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="18dp"/>

    </LinearLayout>

</android.support.v7.widget.CardView>


com.blogspot.android_er.android_action_open_document.MyRecyclerViewAdapter.java
package com.blogspot.android_er.android_action_open_document;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;

public class MyRecyclerViewAdapter extends
        RecyclerView.Adapter<MyRecyclerViewAdapter.ItemHolder>{

    private List<Uri> itemsUri;
    private LayoutInflater layoutInflater;
    private Context context;

    public MyRecyclerViewAdapter(Context context){
        this.context = context;
        layoutInflater = LayoutInflater.from(context);
        itemsUri = new ArrayList<Uri>();
    }

    @Override
    public ItemHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        CardView itemCardView = (CardView)layoutInflater.inflate(R.layout.layout_cardview, viewGroup, false);
        return new ItemHolder(itemCardView, this);
    }

    @Override
    public void onBindViewHolder(ItemHolder itemHolder, int i) {

        Uri targetUri = itemsUri.get(i);
        itemHolder.setItemUri(targetUri.getPath());

        if (targetUri != null){

            try {
                //! CAUTION !
                //I'm not sure is it properly to load bitmap here!
                itemHolder.setImageView(loadScaledBitmap(targetUri));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

    /*
    reference:
    Load scaled bitmap
    http://android-er.blogspot.com/2013/08/load-scaled-bitmap.html
     */
    private Bitmap loadScaledBitmap(Uri src) throws FileNotFoundException {

        // required max width/height
        final int REQ_WIDTH = 400;
        final int REQ_HEIGHT = 400;

        Bitmap bm = null;

        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(context.getContentResolver().openInputStream(src),
                null, options);

        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, REQ_WIDTH,
                REQ_HEIGHT);

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        bm = BitmapFactory.decodeStream(
                context.getContentResolver().openInputStream(src), null, options);

        return bm;
    }

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

        return inSampleSize;
    }

    @Override
    public int getItemCount() {
        return itemsUri.size();
    }

    public void add(int location, Uri iUri){
        itemsUri.add(location, iUri);
        notifyItemInserted(location);
    }

    public void clearAll(){
        int itemCount = itemsUri.size();

        if(itemCount>0){
            itemsUri.clear();
            notifyItemRangeRemoved(0, itemCount);
        }
    }

    public static class ItemHolder extends RecyclerView.ViewHolder{

        private MyRecyclerViewAdapter parent;
        private CardView cardView;
        TextView textItemUri;
        ImageView imageView;

        public ItemHolder(CardView cView, MyRecyclerViewAdapter parent) {
            super(cView);
            cardView = cView;
            this.parent = parent;
            textItemUri = (TextView) cardView.findViewById(R.id.item_uri);
            imageView = (ImageView) cardView.findViewById(R.id.item_image);
        }

        public void setItemUri(CharSequence name){
            textItemUri.setText(name);
        }

        public void setImageView(Bitmap bitmap){
            imageView.setImageBitmap(bitmap);
        }

    }
}


layout/activity_main.xml
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="10dp"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <Button
        android:id="@+id/opendocument"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Open Document of Image/Video" />

    <android.support.v7.widget.RecyclerView
        android:id="@+id/myrecyclerview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>


com.blogspot.android_er.android_action_open_document.MainActivity.java
package com.blogspot.android_er.android_action_open_document;

import android.content.ClipData;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private static final int RQS_OPEN = 1;

    Button buttonOpen;

    private RecyclerView myRecyclerView;
    private StaggeredGridLayoutManager staggeredGridLayoutManagerVertical;
    private MyRecyclerViewAdapter myRecyclerViewAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        buttonOpen = (Button) findViewById(R.id.opendocument);
        buttonOpen.setOnClickListener(buttonOpenOnClickListener);

        myRecyclerView = (RecyclerView)findViewById(R.id.myrecyclerview);
        staggeredGridLayoutManagerVertical =
                new StaggeredGridLayoutManager(
                        2, //The number of Columns in the grid
                        LinearLayoutManager.VERTICAL);
        myRecyclerViewAdapter = new MyRecyclerViewAdapter(this);
        myRecyclerView.setAdapter(myRecyclerViewAdapter);
        myRecyclerView.setLayoutManager(staggeredGridLayoutManagerVertical);
    }

    View.OnClickListener buttonOpenOnClickListener =
            new View.OnClickListener() {
                @Override
                public void onClick(View v) {

                    //Open multi-type using Intent.ACTION_OPEN_DOCUMENT
                    //Open multi-file
                    Intent intent = new Intent();
                    intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
                    intent.addCategory(Intent.CATEGORY_OPENABLE);
                    intent.setType("image/*");
                    intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
                    startActivityForResult(intent, RQS_OPEN);

                    Toast.makeText(MainActivity.this,
                            "Single-selection: Tap on any file.\n" +
                                    "Multi-selection: Tap & Hold on the first file, " +
                                    "tap for more, tap on OPEN to finish.",
                            Toast.LENGTH_LONG).show();
                }
            };

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

        myRecyclerViewAdapter.clearAll();

        if (resultCode == RESULT_OK) {
            if (requestCode == RQS_OPEN) {
                ClipData clipData = data.getClipData();
                if(clipData == null){
                    myRecyclerViewAdapter.add(
                            myRecyclerViewAdapter.getItemCount(),
                            data.getData());
                }else{
                    for(int i=0; i<clipData.getItemCount(); i++){
                        ClipData.Item item = clipData.getItemAt(i);
                        Uri uri = item.getUri();
                        //s += uri.toString() + "\n";
                        myRecyclerViewAdapter.add(
                                myRecyclerViewAdapter.getItemCount(),
                                uri);
                    }
                }

            }
        }
    }
}



download filesDownload the files (Android Studio Format) .


How it run on Bluestacks App Player, refer: "Install Bluestacks App Player on Windows 10, and test your app".



More example:
- for Intent.ACTION_OPEN_DOCUMENT 
- for RecyclerView + CardView

No comments: