How to get a list of all files in Cloud Storage in a Firebase app?

后端 未结 19 1006
傲寒
傲寒 2020-11-21 11:25

I\'m working on uploading images, everything works great, but I have 100 pictures and I would like to show all of them in my View, as I get the complete list of

相关标签:
19条回答
  • 2020-11-21 11:51

    I also encountered this problem when I was working on my project. I really wish they provide an end api method. Anyway, This is how I did it: When you are uploading an image to Firebase storage, create an Object and pass this object to Firebase database at the same time. This object contains the download URI of the image.

    trailsRef.putFile(file).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
            @Override
            public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
                Uri downloadUri = taskSnapshot.getDownloadUrl();
                DatabaseReference myRef = database.getReference().child("trails").child(trail.getUnique_id()).push();
                Image img = new Image(trail.getUnique_id(), downloadUri.toString());
                myRef.setValue(img);
            }
        });
    

    Later when you want to download images from a folder, you simply iterate through files under that folder. This folder has the same name as the "folder" in Firebase storage, but you can name them however you want to. I put them in separate thread.

     @Override
    protected List<Image> doInBackground(Trail... params) {
    
        String trialId = params[0].getUnique_id();
        mDatabase = FirebaseDatabase.getInstance().getReference();
        mDatabase.child("trails").child(trialId).addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                images = new ArrayList<>();
                Iterator<DataSnapshot> iter = dataSnapshot.getChildren().iterator();
                while (iter.hasNext()) {
                    Image img = iter.next().getValue(Image.class);
                    images.add(img);
                }
                isFinished = true;
            }
    
            @Override
            public void onCancelled(DatabaseError databaseError) {
    
            }
        });
    

    Now I have a list of objects containing the URIs to each image, I can do whatever I want to do with them. To load them into imageView, I created another thread.

        @Override
    protected List<Bitmap> doInBackground(List<Image>... params) {
    
        List<Bitmap> bitmaps = new ArrayList<>();
    
        for (int i = 0; i < params[0].size(); i++) {
            try {
                URL url = new URL(params[0].get(i).getImgUrl());
                Bitmap bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());
                bitmaps.add(bmp);
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        return bitmaps;
    }
    

    This returns a list of Bitmap, when it finishes I simply attach them to ImageView in the main activity. Below methods are @Override because I have interfaces created and listen for completion in other threads.

        @Override
    public void processFinishForBitmap(List<Bitmap> bitmaps) {
        List<ImageView> imageViews = new ArrayList<>();
        View v;
        for (int i = 0; i < bitmaps.size(); i++) {
            v = mInflater.inflate(R.layout.gallery_item, mGallery, false);
            imageViews.add((ImageView) v.findViewById(R.id.id_index_gallery_item_image));
            imageViews.get(i).setImageBitmap(bitmaps.get(i));
            mGallery.addView(v);
        }
    }
    

    Note that I have to wait for List Image to be returned first and then call thread to work on List Bitmap. In this case, Image contains the URI.

        @Override
    public void processFinish(List<Image> results) {
        Log.e(TAG, "get back " + results.size());
    
        LoadImageFromUrlTask loadImageFromUrlTask =  new LoadImageFromUrlTask();
        loadImageFromUrlTask.delegate = this;
        loadImageFromUrlTask.execute(results);
    }
    

    Hopefully someone finds it helpful. It will also serve as a guild line for myself in the future too.

    0 讨论(0)
  • 2020-11-21 11:51

    One more way to add the image to Database using Cloud Function to track every uploaded image and store it in Database.

    exports.fileUploaded = functions.storage.object().onChange(event => {
    
        const object = event.data; // the object that was just uploaded
        const contentType = event.data.contentType; // This is the image Mimme type\
    
        // Exit if this is triggered on a file that is not an image.
        if (!contentType.startsWith('image/')) {
            console.log('This is not an image.');
            return null;
        }
    
        // Get the Signed URLs for the thumbnail and original image.
        const config = {
            action: 'read',
            expires: '03-01-2500'
        };
    
        const bucket = gcs.bucket(event.data.bucket);
        const filePath = event.data.name;
        const file = bucket.file(filePath);
    
        file.getSignedUrl(config, function(err, fileURL) {
            console.log(fileURL);
            admin.database().ref('images').push({
                src: fileURL
            });
        });
    });
    

    Full code here: https://gist.github.com/bossly/fb03686f2cb1699c2717a0359880cf84

    0 讨论(0)
  • 2020-11-21 11:51

    You can list files in a directory of firebase storage by listAll() method. To use this method, have to implement this version of firebase storage. 'com.google.firebase:firebase-storage:18.1.1'

    https://firebase.google.com/docs/storage/android/list-files

    Keep in mind that upgrade the Security Rules to version 2.

    0 讨论(0)
  • 2020-11-21 11:51

    I faced the same issue, mine is even more complicated.

    Admin will upload audio and pdf files into storage:

    • audios/season1, season2.../class1, class 2/.mp3 files

    • books/.pdf files

    Android app needs to get the list of sub folders and files.

    The solution is catching the upload event on storage and create the same structure on firestore using cloud function.

    Step 1: Create manually 'storage' collection and 'audios/books' doc on firestore

    Step 2: Setup cloud function

    Might take around 15 mins: https://www.youtube.com/watch?v=DYfP-UIKxH0&list=PLl-K7zZEsYLkPZHe41m4jfAxUi0JjLgSM&index=1

    Step 3: Catch upload event using cloud function

    import * as functions from 'firebase-functions';
    import * as admin from 'firebase-admin';
    admin.initializeApp(functions.config().firebase);
    const path = require('path');
    
    export const onFileUpload = functions.storage.object().onFinalize(async (object) => {
            let filePath = object.name; // File path in the bucket.
            const contentType = object.contentType; // File content type.
            const metageneration = object.metageneration; // Number of times metadata has been generated. New objects have a value of 1.
            if (metageneration !== "1") return;
    
            // Get the file name.
            const fileName = path.basename(filePath);
            filePath = filePath.substring(0, filePath.length - 1);
            console.log('contentType ' + contentType);
            console.log('fileName ' + fileName);
            console.log('filePath ' + filePath);
            console.log('path.dirname(filePath) ' + path.dirname(filePath));
            filePath = path.dirname(filePath);
            const pathArray = filePath.split("/");
            let ref = '';
            for (const item of pathArray) {
                if (ref.length === 0) {
                    ref = item;
                }
                else {
                    ref = ref.concat('/sub/').concat(item);
                }
            }
    
            ref = 'storage/'.concat(ref).concat('/sub')
            admin.firestore().collection(ref).doc(fileName).create({})
                    .then(result => {console.log('onFileUpload:updated')})
                    .catch(error => {
                        console.log(error);
                    });
        });
    

    Step 4: Retrieve list of folders/files on Android app using firestore

    private static final String STORAGE_DOC = "storage/";
        public static void getMediaCollection(String path, OnCompleteListener onCompleteListener) {
            String[] pathArray = path.split("/");
            String doc = null;
            for (String item : pathArray) {
                if (TextUtils.isEmpty(doc)) doc = STORAGE_DOC.concat(item);
                else doc = doc.concat("/sub/").concat(item);
            }
            doc = doc.concat("/sub");
    
            getFirestore().collection(doc).get().addOnCompleteListener(onCompleteListener);
        }
    

    Step 5: Get download url

    public static void downloadMediaFile(String path, OnCompleteListener<Uri> onCompleteListener) {
            getStorage().getReference().child(path).getDownloadUrl().addOnCompleteListener(onCompleteListener);
        }
    

    Note

    We have to put "sub" collection to each item since firestore doesn't support to retrieve the list of collection.

    It took me 3 days to find out the solution, hopefully will take you 3 hours at most.

    Cheers.

    0 讨论(0)
  • 2020-11-21 11:51

    You can use the following code. Here I am uploading the image to firebase storage and then I am storing the image download url to firebase database.

    //getting the storage reference
                StorageReference sRef = storageReference.child(Constants.STORAGE_PATH_UPLOADS + System.currentTimeMillis() + "." + getFileExtension(filePath));
    
                //adding the file to reference 
                sRef.putFile(filePath)
                        .addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
                            @Override
                            public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
                                //dismissing the progress dialog
                                progressDialog.dismiss();
    
                                //displaying success toast 
                                Toast.makeText(getApplicationContext(), "File Uploaded ", Toast.LENGTH_LONG).show();
    
                                //creating the upload object to store uploaded image details 
                                Upload upload = new Upload(editTextName.getText().toString().trim(), taskSnapshot.getDownloadUrl().toString());
    
                                //adding an upload to firebase database 
                                String uploadId = mDatabase.push().getKey();
                                mDatabase.child(uploadId).setValue(upload);
                            }
                        })
                        .addOnFailureListener(new OnFailureListener() {
                            @Override
                            public void onFailure(@NonNull Exception exception) {
                                progressDialog.dismiss();
                                Toast.makeText(getApplicationContext(), exception.getMessage(), Toast.LENGTH_LONG).show();
                            }
                        })
                        .addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
                            @Override
                            public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
                                //displaying the upload progress 
                                double progress = (100.0 * taskSnapshot.getBytesTransferred()) / taskSnapshot.getTotalByteCount();
                                progressDialog.setMessage("Uploaded " + ((int) progress) + "%...");
                            }
                        });
    

    Now to fetch all the images stored in firebase database you can use

    //adding an event listener to fetch values
            mDatabase.addValueEventListener(new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot snapshot) {
                    //dismissing the progress dialog 
                    progressDialog.dismiss();
    
                    //iterating through all the values in database
                    for (DataSnapshot postSnapshot : snapshot.getChildren()) {
                        Upload upload = postSnapshot.getValue(Upload.class);
                        uploads.add(upload);
                    }
                    //creating adapter
                    adapter = new MyAdapter(getApplicationContext(), uploads);
    
                    //adding adapter to recyclerview
                    recyclerView.setAdapter(adapter);
                }
    
                @Override
                public void onCancelled(DatabaseError databaseError) {
                    progressDialog.dismiss();
                }
            });
    

    Fore more details you can see my post Firebase Storage Example.

    0 讨论(0)
  • 2020-11-21 11:53

    As of May 2019, version 6.1.0 of the Firebase SDK for Cloud Storage now supports listing all objects from a bucket. You simply need to call listAll() in a Reference:

        // Since you mentioned your images are in a folder,
        // we'll create a Reference to that folder:
        var storageRef = firebase.storage().ref("your_folder");
    
    
        // Now we get the references of these images
        storageRef.listAll().then(function(result) {
          result.items.forEach(function(imageRef) {
            // And finally display them
            displayImage(imageRef);
          });
        }).catch(function(error) {
          // Handle any errors
        });
    
        function displayImage(imageRef) {
          imageRef.getDownloadURL().then(function(url) {
            // TODO: Display the image on the UI
          }).catch(function(error) {
            // Handle any errors
          });
        }
    

    Please note that in order to use this function, you must opt-in to version 2 of Security Rules, which can be done by making rules_version = '2'; the first line of your security rules:

        rules_version = '2';
        service firebase.storage {
          match /b/{bucket}/o {
            match /{allPaths=**} {
    

    I'd recommend checking the docs for further reference.

    Also, according to setup, on Step 5, this script is not allowed for Node.js since require("firebase/app"); won't return firebase.storage() as a function. This is only achieved using import * as firebase from 'firebase/app';.

    0 讨论(0)
提交回复
热议问题