삽질도사

[안드로이드] firestorage 코드로 파일삭제하기(firebase) 본문

안드로이드

[안드로이드] firestorage 코드로 파일삭제하기(firebase)

전성진블로그 2021. 11. 10. 10:07

이런 식으로 되어있음.
글 쓸때에 사진/gif/영상을 첨부하면 스토리지로 글내용/info는 스토어로!

 

스토리지에 올라간 모습이고, 동그라미 친 부분이 스토리지의 경로(이후에 사용됨) 
삭제하면 스토리지+스토어 데이터 같이 삭제
스토리지 파일이 삭제되는게 핵심

아래 함수로 글쓰기에서 파일이 있는 경우와 없는 경우로 나누었는데요.

파일이 있다면 스토리지에 올릴 것이고, 그 경로와 내용은 스토어에 올릴 것이기 때문입니다.

파일이 없는 경우라면 당연히 스토어에만 올라갑니다.

 

제가 만들 당시에 스토리지에 파일 삭제하는 함수가 없었기 때문에 파일 하나하나 고유의 경로를 알아야만 했습니다.

따라서 파일이 있는 경우 Upload_Post라는 함수를 사용해서 일단 스토리지에 파일을 업로드하고 스토리지에 생성되는

고유의 경로를 다시 읽어와서 저장할 것이고 그것은 이후에 삭제할 때 사용할 것입니다.

 public void UploadStorage(String uid, String nickname, String title, String content) {
        loaderView.setVisibility(View.VISIBLE);

        DocumentReference locationDoc = db.collection("USER").document(uid);

        locationDoc.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
            @Override
            public void onComplete(@NonNull Task<DocumentSnapshot> task) {
                if (task.isSuccessful()) {
                    DocumentSnapshot document = task.getResult();

                    if (document.exists()) { //USER에서 location을 찾는 것은 비동기적이기떄문에 함수화 못했꼬, 그래서 우선적으로 지역을 찾고 찾았다면, 포스트를 올리기로.

                        location = document.getString("location"); //USER안에서 location을 찾아오는 쿼리(?)
                        Log.d("지역탐색",location);

                        final DocumentReference documentReference
                                = postInfo == null ? db.collection(location).document() : db.collection(location).document(postInfo.getDocid());
                        final Date date = postInfo == null ? new Date() : postInfo.getCreatedAt();
                        final ArrayList<String> formatList = new ArrayList<>();
                        final ArrayList<String> storagePath = new ArrayList<>();
                        UriFormats = Postmodel.get().getValue(); //업로드할 파일의 uri 목록
                        postInfo = new PostInfo(uid, nickname, title, content,date,documentReference.getId(),location);

                        if(UriFormats != null) { //업로드할 파일이 있다면 스토리지에 업로드
                            Log.d("imageList"," 갯수: "+UriFormats.size());
                            Upload_Post(UriFormats,documentReference,formatList,storagePath,postInfo);

                        }else{ //파일없이 글만 올리는 경우
                            postControler.Upload_Post_Store(documentReference, postInfo, new PostControler.Listener_UpLoadPost() {
                                @Override
                                public void onComplete() {
                                    Toast("성공적으로 게시되었습니다.");
                                    loaderView.setVisibility(View.GONE);
                                    toMain(WRITE_RESULT);
                                }
                                @Override
                                public void onFail() {
                                    Toast("업로드에 실패하였습니다.");
                                    loaderView.setVisibility(View.GONE);
                                }
                            });
                        }
                    }
                }
            }
        });
    }

 

public String getPathFromUri(Uri uri){ //파일의 경로 찾아오는 함수

        Cursor cursor = getContentResolver().query(uri, null, null, null, null );
        cursor.moveToNext();
        String path = cursor.getString( cursor.getColumnIndex( "_data" ) );
        cursor.close();

        return path;
    }

아래 함수를 통해서 파일 경로를 뽑아서 일단 스토리지에 올리고 스토리지에 올리면서 생긴 파일의 새로운 스토리지 경로를 얻어와서 데이터에 저장하는 모습입니다. 

 

파일이 여러개인 경우가 난감했었는데, 재귀함수를 통해서 하나하나 처리하고 모두 완료했을 때에 스토어에 글을 올리는 방식을 사용함으로써 문제를 해결했습니다.

 

어쨌든 스토리지에 파일의 경로를 데이터로 저장하는 것까지 성공했다면 삭제하는 것은 일도 아닙니다.

private void Upload_Post(final ArrayList<Uri> mediaUris, DocumentReference documentReference, final ArrayList<String> formatList, ArrayList<String> storagePath, PostInfo postInfo) {

        if(formatList.size() == mediaUris.size())
            return;

        Log.d("imageList"," 갯수: "+mediaUris.size()+"formatList.size(): "+formatList.size());

        InputStream stream = null;
        if(mediaUris.size() != 0 && mediaUris != null)
        try {
            stream = new FileInputStream(new File(getPathFromUri(mediaUris.get(formatList.size()))));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        else return;

        if(stream != null) {

            String[] pathArray = getPathFromUri(mediaUris.get(formatList.size())).split("\\.");
            String storagepath = location+"/"+ documentReference.getId() + "/" + formatList.size() + "." + pathArray[pathArray.length - 1];
            final StorageReference fileRef = storageRef.child(storagepath);
            StorageMetadata metadata = new StorageMetadata.Builder().setCustomMetadata("index", "" + formatList.size()).build();
            final UploadTask uploadTask = fileRef.putStream(stream, metadata);

            uploadTask.addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
                @Override
                public void onSuccess(final UploadTask.TaskSnapshot taskSnapshot) {

                    fileRef.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
                        @Override
                        public void onSuccess(Uri uri) {
                            Log.d("TAG", "URL = " + uri); //url of each file

                            if(formatList.size() < mediaUris.size()) {
                                formatList.add(uri.toString()); //다운로드를 위한 uri
                                storagePath.add(storagepath); //이후에 storage 수정과 삭제를 위한 storage경로
                                Upload_Post(mediaUris, documentReference, formatList, storagePath, postInfo); //Recursion
                                Log.d("포멧올리는 과정", "size: " + formatList.size()+"medi size : "+mediaUris);
                            }
                            if (formatList.size() == mediaUris.size()) { //재귀함수를 반복하다가 마지막 포멧까지 올리고 나서 내용을 firestore에 게시글을 올릴 시점.
                                Log.d("한번만 튀어나오면댐", ": " + formatList.size());
                                postInfo.setFormats(formatList);
                                postInfo.setStoragePath(storagePath);
                                postControler.Upload_Post_Store(documentReference, postInfo, new PostControler.Listener_UpLoadPost() {
                                    @Override
                                    public void onComplete() {
                                        Toast("성공적으로 게시되었습니다.");
                                        loaderView.setVisibility(View.GONE);
                                        toMain(WRITE_RESULT);
                                    }
                                    @Override
                                    public void onFail() {
                                        Toast("업로드에 실패하였습니다.");
                                        loaderView.setVisibility(View.GONE);
                                    }
                                });
                            }
                        }
                    }).addOnFailureListener(new OnFailureListener() {
                        @Override
                        public void onFailure(@NonNull Exception e) {
                            Toast.makeText(getApplicationContext(), "Upload failed", Toast.LENGTH_SHORT).show();
                            Log.e("TAG", "Failed " + e.getCause());
                        }
                    });
                }
            });
        }
    }

 

이제야 본론입니다. 게시글을 삭제할 때 파일이 있다면, 스토어+스토리지가 같이 삭제될 수 있도록 해주는 방법입니다.

삭제할 때도 마찬가지로 재귀적으로 해결했습니다.(맘에 안들지만.. ㅠ)

글 쓸때에 저장해주었던 스토리지 파일경로를 얻어와서 하나하나 제거해주는 방식입니다. 

 private void PostDelete ( int delcnt){ //게시글에 딸린 파일이 모두 제거될 때까지 재귀한다.

            if (postInfo.getFormats() != null) { //올린 게시물에 첨부파일(사진,영상,gif)가 있는 경우
                final StorageReference fileRef = storageRef.child(postInfo.getStoragePath().get(delcnt)); //게시글 올릴 당시에 저장한 파일의 storage 경로를 가져온다

                fileRef.delete().addOnSuccessListener(new OnSuccessListener<Void>() {
                    @Override
                    public void onSuccess(Void aVoid) {

                        if (delcnt < postInfo.getStoragePath().size() - 1) { //삭제할 것이 남아 있다면 재귀로 한번 더 진행
                            PostDelete(delcnt + 1);

                        } else if (delcnt == postInfo.getStoragePath().size() - 1) { //storage를 비웠다면 이제 store의 게시글을 삭제할 수 있다.
                            DB_del(); //삭제할 땐 잊지말고 관련된 모든 데이터를 지워야한다(내가 쓴 글목록,댓글 등등)
                            return;
                        }
                    }
                }).addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception exception) {
                        Log.d("storage_Delete", postInfo.getLocation() + "/" + postInfo.getDocid());
                        Toast("삭제 실패하였습니다. :storage" + postInfo.getLocation() + "/" + postInfo.getDocid());
                    }
                });
            } else {
                DB_del();
            }

        }