从 Cloud Storage 下载文件 (Android)

Cloud Storage for Firebase 可让您快速轻松地从 Firebase 提供和管理的 Cloud Storage 存储桶中下载文件。

创建引用

如需下载某个文件,请先为要下载的文件创建一个 Cloud Storage 引用

您可以通过将子路径附加到 Cloud Storage 存储桶的根目录来创建引用,也可以根据指向 Cloud Storage 中的对象的现有 gs://https:// 网址创建引用。

Kotlin+KTX

// Create a storage reference from our app
val storageRef = storage.reference

// Create a reference with an initial file path and name
val pathReference = storageRef.child("images/stars.jpg")

// Create a reference to a file from a Google Cloud Storage URI
val gsReference = storage.getReferenceFromUrl("gs://bucket/images/stars.jpg")

// Create a reference from an HTTPS URL
// Note that in the URL, characters are URL escaped!
val httpsReference = storage.getReferenceFromUrl(
    "https://firebasestorage.googleapis.com/b/bucket/o/images%20stars.jpg",
)

Java

// Create a storage reference from our app
StorageReference storageRef = storage.getReference();

// Create a reference with an initial file path and name
StorageReference pathReference = storageRef.child("images/stars.jpg");

// Create a reference to a file from a Google Cloud Storage URI
StorageReference gsReference = storage.getReferenceFromUrl("gs://bucket/images/stars.jpg");

// Create a reference from an HTTPS URL
// Note that in the URL, characters are URL escaped!
StorageReference httpsReference = storage.getReferenceFromUrl("https://firebasestorage.googleapis.com/b/bucket/o/images%20stars.jpg");

下载文件

有了引用之后,您便可以调用 getBytes()getStream() 方法从 Cloud Storage 下载文件。如果您希望使用其他的库下载文件,则可以使用 getDownloadUrl() 方法获取下载网址。

下载至内存

您可以使用 getBytes() 方法将文件下载到 byte[]。这是最简单的文件下载方法,但它必须将文件的全部内容加载到内存中。如果您请求下载的文件大于应用的可用内存,应用将会崩溃。为防止出现内存问题,可以为 getBytes() 设置一个下载字节数上限参数。请将该上限设为您知道应用可以处理的大小,或者使用其他下载方法。

Kotlin+KTX

var islandRef = storageRef.child("images/island.jpg")

val ONE_MEGABYTE: Long = 1024 * 1024
islandRef.getBytes(ONE_MEGABYTE).addOnSuccessListener {
    // Data for "images/island.jpg" is returned, use this as needed
}.addOnFailureListener {
    // Handle any errors
}

Java

StorageReference islandRef = storageRef.child("images/island.jpg");

final long ONE_MEGABYTE = 1024 * 1024;
islandRef.getBytes(ONE_MEGABYTE).addOnSuccessListener(new OnSuccessListener<byte[]>() {
    @Override
    public void onSuccess(byte[] bytes) {
        // Data for "images/island.jpg" is returns, use this as needed
    }
}).addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception exception) {
        // Handle any errors
    }
});

下载至本地文件

getFile() 方法可将文件直接下载至本地设备。如果用户希望离线时可以访问文件或希望在不同的应用中共享文件,请使用这种方法。getFile() 会返回一个 DownloadTask,您可以使用它来管理下载并监控下载状态。

Kotlin+KTX

islandRef = storageRef.child("images/island.jpg")

val localFile = File.createTempFile("images", "jpg")

islandRef.getFile(localFile).addOnSuccessListener {
    // Local temp file has been created
}.addOnFailureListener {
    // Handle any errors
}

Java

islandRef = storageRef.child("images/island.jpg");

File localFile = File.createTempFile("images", "jpg");

islandRef.getFile(localFile).addOnSuccessListener(new OnSuccessListener<FileDownloadTask.TaskSnapshot>() {
    @Override
    public void onSuccess(FileDownloadTask.TaskSnapshot taskSnapshot) {
        // Local temp file has been created
    }
}).addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception exception) {
        // Handle any errors
    }
});

如果您希望手动管理下载,请参阅管理下载以了解详情。

通过网址下载数据

如果您已经有了基于网址的下载基础架构,或者只需要一个网址用于共享,可通过对 Cloud Storage 引用调用 getDownloadUrl() 方法来获取文件的下载网址。

Kotlin+KTX

storageRef.child("users/me/profile.png").downloadUrl.addOnSuccessListener {
    // Got the download URL for 'users/me/profile.png'
}.addOnFailureListener {
    // Handle any errors
}

Java

storageRef.child("users/me/profile.png").getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
    @Override
    public void onSuccess(Uri uri) {
        // Got the download URL for 'users/me/profile.png'
    }
}).addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception exception) {
        // Handle any errors
    }
});

通过 FirebaseUI 下载图片

FirebaseUI 提供简单、可定制且适合生产环境的原生移动绑定,以消除样板代码并促进遵循 Google 最佳实践。借助与 Glide 的集成,您可以使用 FirebaseUI 快速轻松地下载、缓存和显示 Cloud Storage 中的图片。

首先,将 FirebaseUI 添加到您的 app/build.gradle 文件:

dependencies {
    // FirebaseUI Storage only
    implementation 'com.firebaseui:firebase-ui-storage:7.2.0'
}

然后,您可以直接将 Cloud Storage 中的图片加载到 ImageView

Kotlin+KTX

// Reference to an image file in Cloud Storage
val storageReference = Firebase.storage.reference

// ImageView in your Activity
val imageView = findViewById<ImageView>(R.id.imageView)

// Download directly from StorageReference using Glide
// (See MyAppGlideModule for Loader registration)
Glide.with(context)
    .load(storageReference)
    .into(imageView)

Java

// Reference to an image file in Cloud Storage
StorageReference storageReference = FirebaseStorage.getInstance().getReference();

// ImageView in your Activity
ImageView imageView = findViewById(R.id.imageView);

// Download directly from StorageReference using Glide
// (See MyAppGlideModule for Loader registration)
Glide.with(context)
        .load(storageReference)
        .into(imageView);

处理 Activity 生命周期变更

即使 activity 生命周期发生变化(例如显示对话框或旋转屏幕),下载也将继续在后台进行。您连接的所有监听器也都会保持连接状态。如果在 activity 停止后调用这些监听器,有可能产生意外的结果。

您可以采取以下方法来解决此问题:向 activity 作用域订阅您的监听器,以便在 activity 停止时自动取消注册。然后,在 activity 重启后使用 getActiveDownloadTasks 方法获取仍在进行或刚刚完成的下载任务。

下面的示例演示了这一操作,还说明了如何保留使用的存储引用路径。

Kotlin+KTX

override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)

    // If there's a download in progress, save the reference so you can query it later
    outState.putString("reference", storageRef.toString())
}

override fun onRestoreInstanceState(savedInstanceState: Bundle) {
    super.onRestoreInstanceState(savedInstanceState)

    // If there was a download in progress, get its reference and create a new StorageReference
    val stringRef = savedInstanceState.getString("reference") ?: return

    storageRef = Firebase.storage.getReferenceFromUrl(stringRef)

    // Find all DownloadTasks under this StorageReference (in this example, there should be one)
    val tasks = storageRef.activeDownloadTasks

    if (tasks.size > 0) {
        // Get the task monitoring the download
        val task = tasks[0]

        // Add new listeners to the task using an Activity scope
        task.addOnSuccessListener(this) {
            // Success!
            // ...
        }
    }
}

Java

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

    // If there's a download in progress, save the reference so you can query it later
    if (mStorageRef != null) {
        outState.putString("reference", mStorageRef.toString());
    }
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);

    // If there was a download in progress, get its reference and create a new StorageReference
    final String stringRef = savedInstanceState.getString("reference");
    if (stringRef == null) {
        return;
    }
    mStorageRef = FirebaseStorage.getInstance().getReferenceFromUrl(stringRef);

    // Find all DownloadTasks under this StorageReference (in this example, there should be one)
    List<FileDownloadTask> tasks = mStorageRef.getActiveDownloadTasks();
    if (tasks.size() > 0) {
        // Get the task monitoring the download
        FileDownloadTask task = tasks.get(0);

        // Add new listeners to the task using an Activity scope
        task.addOnSuccessListener(this, new OnSuccessListener<FileDownloadTask.TaskSnapshot>() {
            @Override
            public void onSuccess(FileDownloadTask.TaskSnapshot state) {
                // Success!
                // ...
            }
        });
    }
}

处理错误

导致下载出错的原因有很多,包括文件不存在,或者用户不具备访问相应文件的权限。如需了解有关错误的详细信息,请参阅文档的处理错误部分。

完整示例

包含错误处理的下载完整示例如下:

Kotlin+KTX

storageRef.child("users/me/profile.png").getBytes(Long.MAX_VALUE).addOnSuccessListener {
    // Use the bytes to display the image
}.addOnFailureListener {
    // Handle any errors
}

Java

storageRef.child("users/me/profile.png").getBytes(Long.MAX_VALUE).addOnSuccessListener(new OnSuccessListener<byte[]>() {
    @Override
    public void onSuccess(byte[] bytes) {
        // Use the bytes to display the image
    }
}).addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception exception) {
        // Handle any errors
    }
});

对于存储在 Cloud Storage 中的文件,您还可以获取和更新元数据