본문 바로가기
안드로이드

[Android] 내장 메모리 파일 가져오기 (2)

by Banlim 2020. 8. 10.

안드로이드 디바이스의 내장 메모리에 있는 파일을 가져오는 방법 두 번째를 소개한다.

-> 안드로이드가 제공하는 MediaStore 이용하기 + Picasso Library

 

Picasso Library를 사용하기 위해 app/build.gradle 파일에 dependency를 추가한다.

 

app/build.gradle

implementation 'com.squareup.picasso:picasso:2.5.2'

 

다음으로 내장 메모리를 접근하기 위해서 메모리 읽기, 쓰기 권한 코드를 삽입한다.

 

AndroidManifest.xml

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

 

내장 메모리에 있는 이미지 파일을 예로 들어서, 이미지 파일을 가져오기 위한 cardview와 recyclerview를 미리 정의하고 recyclerview에 cardview를 올려 동작하기 위해 recyclerviewAdapter를 작성한다. 생성자로 cardview에 보여질 data를 정의한 ModelData와 context를 파라미터로 가져오도록 정의한다. onCreateViewHolder 함수에서 layoutInflater를 정의하고 layoutInflater.inflate 함수를 통해 사전에 정의한 cardview.xml 파일을 가져와 View 형태로 리턴한다. 리턴된 view를 ViewHolder의 인자로 넣어 새로운 ViewHolder를 생성하여 리턴한다.

 

PhotoRecyclerViewAdapter.java

public class PhotoRecyclerViewAdapter extends RecyclerView.Adapter<SendPhotoRecyclerViewAdapter.ViewHolder> {
    private ArrayList<ModelData> sendPhotos;
    private Context context;
    public PhotoRecyclerViewAdapter(ArrayList<ModelData> sendPhotos, Context context) {
        this.sendPhotos = sendPhotos;
        this.context = context;
    }
    
    @NonNull
    @Override
    public SendPhotoRecyclerViewAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view;
        LayoutInflater layoutInflater = LayoutInflater.from(context);
        view = layoutInflater.inflate(R.layout.send_photo_cardview, parent, false);
        return new ViewHolder(view);
    }

 

onBindViewHolder에서 position에 있는 ModelData를 get 함수로 불러와 item 변수에 임시 저장하고, 이를 holder.setItem() 함수에 item 변수를 인자로 넣어 ViewHodler에 bind 되도록 한다. 

 

PhotoRecyclerViewAdapter.java

@Override
    public void onBindViewHolder(@NonNull SendPhotoRecyclerViewAdapter.ViewHolder holder, int position) {
    	ModelData item = sendPhotos.get(position);
        holder.setItem(item);
    }

    public void addItem(ModelData item){
        sendPhotos.add(item);
    }

    public void setItems(ArrayList<ModelData> item){
        this.sendPhotos = item;
    }

    public ModelData getItem(int position){
        return sendPhotos.get(position);
    }

    public void setItem(int position, ModelData item){
        sendPhotos.set(position, item);
    }
	@Override
    public int getItemCount() {
        return sendPhotos.size();
    }

 

ViewHolder class를 PhotoRecyclerViewAdapter class의 내부 클래스로 정의하였고, onBindViewHolder() 함수에서 각 data를 binding하기 위해 ViewHolder class에서 setItem() 함수를 만든다. setItem() 함수에서는 Picasso 라이브러리를 사용하여 이미지를 로드하여 imageView에 적용하는 동작을 수행한다.

 

PhotoRecyclerViewAdapter.java

public class ViewHolder extends RecyclerView.ViewHolder{

        private CheckBox checkBox;
        private ImageView imageView;
        private CardView cardView;
        private TextView selectCntTextView;
        private Button selectSendButton;
        private View views;

        private BitmapFactory.Options options = new BitmapFactory.Options();

        public ViewHolder(@NonNull View itemView) {
            super(itemView);

            options.inSampleSize = 12;

            cardView = (CardView)itemView.findViewById(R.id.send_photo_cardview);
            imageView = (ImageView)itemView.findViewById(R.id.send_photo_cardview_image);
            views = itemView;
        }

        public void setItem(SendPhoto item){

            Picasso.with(context)
                    .load(Uri.parse("file://"+item.getImagePath()))
                    .into(imageView);

        }
    }

 

안드로이드에서 제공하는 MediaStore를 사용하여 이미지 파일을 가져오는 함수이다. MediaStore.Images.Media.EXTERNAL_CONTENT_URI를 URI 형태로 받아온 후, cursor를 query형태로 받아온다. cursor.moveToNext() 함수로 다음 데이터가 나오지 않을 때까지 반복하여 데이터베이스에 projection 조건에 맞는 데이터를 가져와 ModelData에 데이터를 넣는 작업을 수행한다.

 

PhotoFragment.java

private ArrayList<ModelData> queryAllPhoto(){
        ArrayList<ModelData> result = new ArrayList<>();
        Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
        String[] projection = { MediaStore.MediaColumns.DATA, MediaStore.MediaColumns.DISPLAY_NAME, MediaStore.MediaColumns.DATE_ADDED};

        Cursor cursor = getActivity().getContentResolver().query(uri, projection, null, null, MediaStore.MediaColumns.DATE_ADDED);

        int colDataIndex = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
        int colNameIndex = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME);
        int colDateIndex = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATE_ADDED);

        pictureCount = 0;
        while(cursor.moveToNext())
        {
            String path = cursor.getString(colDataIndex);
            String displayName = cursor.getString(colNameIndex);
            String outDate = cursor.getString(colDateIndex);
            String addedDate = dateFormat.format(new Date(new Long(outDate).longValue()*1000L));

            if(!TextUtils.isEmpty(path)){
                ModelData sendPhoto = new ModelData(path);
                result.add(sendPhoto);
            }
            pictureCount++;
        }
        return result;
    }

 

추가로 이미지 말고 일반 파일을 가져오고 싶을 때의 함수이다. MediaStord의 MIME_TYPE으로 데이터를 접근하여 파일을 가져올 수 있다. String 배열의 selectionArgs를 통해 원하는 확장자의 파일만을 정의하고, cursor에서 query함수의 selectionArgs를 인자로 넣어 사전에 정의한 확장자만을 조회하도록 한다. 이후의 과정은 위의 PhotoFragment.java와 동일하다.

 

FileFragment.java

private ArrayList<ModelData> queryAllFiles(){
        ArrayList<ModelData> result = new ArrayList<>();
        Uri uri = MediaStore.Files.getContentUri("external");
        String[] projection = {
                MediaStore.Files.FileColumns.DATA,
                MediaStore.Files.FileColumns.DISPLAY_NAME,
                MediaStore.Files.FileColumns.DATE_ADDED,
                MediaStore.Files.FileColumns.MIME_TYPE
        };
        String selection = MediaStore.Files.FileColumns.MIME_TYPE + "=?" + ""
                + "OR "
                + MediaStore.Files.FileColumns.MIME_TYPE + "=?" + ""
                +"OR "
                + MediaStore.Files.FileColumns.MIME_TYPE + "=?" + ""
                +"OR "
                + MediaStore.Files.FileColumns.MIME_TYPE + "=?" + ""
                +"OR "
                + MediaStore.Files.FileColumns.MIME_TYPE + "=?" + "";
        
        String[] selectionArgs = new String[]{
                MimeTypeMap.getSingleton().getMimeTypeFromExtension("hwp"),
                MimeTypeMap.getSingleton().getMimeTypeFromExtension("doc"),
                MimeTypeMap.getSingleton().getMimeTypeFromExtension("xlsx"),
                MimeTypeMap.getSingleton().getMimeTypeFromExtension("pptx"),
                MimeTypeMap.getSingleton().getMimeTypeFromExtension("pdf")
        };

        Cursor cursor = getActivity().getContentResolver().query(uri, projection, selection, selectionArgs, MediaStore.Files.FileColumns.DATE_ADDED +" DESC");

        int colDataIndex = cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DATA);
        int colNameIndex = cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DISPLAY_NAME);
        int colDateIndex = cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.DATE_ADDED);
        int colMimeIndex = cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns.MIME_TYPE);

        pictureCount = 0;
        while(cursor.moveToNext())
        {
            String path = cursor.getString(colDataIndex);
            String displayName = cursor.getString(colNameIndex);
            String outDate = cursor.getString(colDateIndex);
            String ext = MimeTypeMap.getSingleton().getExtensionFromMimeType(cursor.getString(colMimeIndex));
            String addedDate = dateFormat.format(new Date(new Long(outDate).longValue()*1000L));

            if(ext == null){
                ext="not";
            }
            if(!TextUtils.isEmpty(path)){
                ModelData sendFile = new ModelData(path, ext, displayName, addedDate);
                result.add(sendFile);
            }
            pictureCount++;
        }

        return result;
    }