Tải tệp lên bằng Cloud Storage trên Android

Cloud Storage cho Firebase cho phép bạn tải tệp lên nhóm Cloud Storage do Firebase cung cấp và quản lý một cách nhanh chóng và dễ dàng.

Tải tập tin lên

Để tải tệp lên Cloud Storage, trước tiên bạn tạo tham chiếu đến đường dẫn đầy đủ của tệp, bao gồm cả tên tệp.

Kotlin+KTX

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

// Create a reference to "mountains.jpg"
val mountainsRef = storageRef.child("mountains.jpg")

// Create a reference to 'images/mountains.jpg'
val mountainImagesRef = storageRef.child("images/mountains.jpg")

// While the file names are the same, the references point to different files
mountainsRef.name == mountainImagesRef.name // true
mountainsRef.path == mountainImagesRef.path // false

Java

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

// Create a reference to "mountains.jpg"
StorageReference mountainsRef = storageRef.child("mountains.jpg");

// Create a reference to 'images/mountains.jpg'
StorageReference mountainImagesRef = storageRef.child("images/mountains.jpg");

// While the file names are the same, the references point to different files
mountainsRef.getName().equals(mountainImagesRef.getName());    // true
mountainsRef.getPath().equals(mountainImagesRef.getPath());    // false

Sau khi tạo tham chiếu phù hợp, bạn gọi phương thức putBytes() , putFile() hoặc putStream() để tải tệp lên Cloud Storage.

Bạn không thể tải lên dữ liệu có tham chiếu đến thư mục gốc của bộ chứa Cloud Storage. Tham chiếu của bạn phải trỏ đến URL con.

Tải lên từ dữ liệu trong bộ nhớ

Phương thức putBytes() là cách đơn giản nhất để tải tệp lên Cloud Storage. putBytes() lấy một byte[] và trả về UploadTask mà bạn có thể sử dụng để quản lý và theo dõi trạng thái tải lên.

Kotlin+KTX

// Get the data from an ImageView as bytes
imageView.isDrawingCacheEnabled = true
imageView.buildDrawingCache()
val bitmap = (imageView.drawable as BitmapDrawable).bitmap
val baos = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos)
val data = baos.toByteArray()

var uploadTask = mountainsRef.putBytes(data)
uploadTask.addOnFailureListener {
    // Handle unsuccessful uploads
}.addOnSuccessListener { taskSnapshot ->
    // taskSnapshot.metadata contains file metadata such as size, content-type, etc.
    // ...
}

Java

// Get the data from an ImageView as bytes
imageView.setDrawingCacheEnabled(true);
imageView.buildDrawingCache();
Bitmap bitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] data = baos.toByteArray();

UploadTask uploadTask = mountainsRef.putBytes(data);
uploadTask.addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception exception) {
        // Handle unsuccessful uploads
    }
}).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
    @Override
    public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
        // taskSnapshot.getMetadata() contains file metadata such as size, content-type, etc.
        // ...
    }
});

putBytes() chấp nhận byte[] nên ứng dụng của bạn phải giữ toàn bộ nội dung của tệp trong bộ nhớ cùng một lúc. Hãy cân nhắc sử dụng putStream() hoặc putFile() để sử dụng ít bộ nhớ hơn.

Tải lên từ một luồng

Phương thức putStream() là cách linh hoạt nhất để tải tệp lên Cloud Storage. putStream() nhận một InputStream và trả về một UploadTask mà bạn có thể sử dụng để quản lý và theo dõi trạng thái tải lên.

Kotlin+KTX

val stream = FileInputStream(File("path/to/images/rivers.jpg"))

uploadTask = mountainsRef.putStream(stream)
uploadTask.addOnFailureListener {
    // Handle unsuccessful uploads
}.addOnSuccessListener { taskSnapshot ->
    // taskSnapshot.metadata contains file metadata such as size, content-type, etc.
    // ...
}

Java

InputStream stream = new FileInputStream(new File("path/to/images/rivers.jpg"));

uploadTask = mountainsRef.putStream(stream);
uploadTask.addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception exception) {
        // Handle unsuccessful uploads
    }
}).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
    @Override
    public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
        // taskSnapshot.getMetadata() contains file metadata such as size, content-type, etc.
        // ...
    }
});

Tải lên từ một tập tin cục bộ

Bạn có thể tải các tệp cục bộ lên thiết bị, chẳng hạn như ảnh và video từ máy ảnh, bằng phương thức putFile() . putFile() lấy một File và trả về một UploadTask mà bạn có thể sử dụng để quản lý và theo dõi trạng thái tải lên.

Kotlin+KTX

var file = Uri.fromFile(File("path/to/images/rivers.jpg"))
val riversRef = storageRef.child("images/${file.lastPathSegment}")
uploadTask = riversRef.putFile(file)

// Register observers to listen for when the download is done or if it fails
uploadTask.addOnFailureListener {
    // Handle unsuccessful uploads
}.addOnSuccessListener { taskSnapshot ->
    // taskSnapshot.metadata contains file metadata such as size, content-type, etc.
    // ...
}

Java

Uri file = Uri.fromFile(new File("path/to/images/rivers.jpg"));
StorageReference riversRef = storageRef.child("images/"+file.getLastPathSegment());
uploadTask = riversRef.putFile(file);

// Register observers to listen for when the download is done or if it fails
uploadTask.addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception exception) {
        // Handle unsuccessful uploads
    }
}).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
    @Override
    public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
        // taskSnapshot.getMetadata() contains file metadata such as size, content-type, etc.
        // ...
    }
});

Nhận URL tải xuống

Sau khi tải tệp lên, bạn có thể nhận URL để tải xuống tệp bằng cách gọi phương thức getDownloadUrl() trên StorageReference :

Kotlin+KTX

val ref = storageRef.child("images/mountains.jpg")
uploadTask = ref.putFile(file)

val urlTask = uploadTask.continueWithTask { task ->
    if (!task.isSuccessful) {
        task.exception?.let {
            throw it
        }
    }
    ref.downloadUrl
}.addOnCompleteListener { task ->
    if (task.isSuccessful) {
        val downloadUri = task.result
    } else {
        // Handle failures
        // ...
    }
}

Java

final StorageReference ref = storageRef.child("images/mountains.jpg");
uploadTask = ref.putFile(file);

Task<Uri> urlTask = uploadTask.continueWithTask(new Continuation<UploadTask.TaskSnapshot, Task<Uri>>() {
    @Override
    public Task<Uri> then(@NonNull Task<UploadTask.TaskSnapshot> task) throws Exception {
        if (!task.isSuccessful()) {
            throw task.getException();
        }

        // Continue with the task to get the download URL
        return ref.getDownloadUrl();
    }
}).addOnCompleteListener(new OnCompleteListener<Uri>() {
    @Override
    public void onComplete(@NonNull Task<Uri> task) {
        if (task.isSuccessful()) {
            Uri downloadUri = task.getResult();
        } else {
            // Handle failures
            // ...
        }
    }
});

Thêm siêu dữ liệu tệp

Bạn cũng có thể bao gồm siêu dữ liệu khi tải tệp lên. Siêu dữ liệu này chứa các thuộc tính siêu dữ liệu tệp điển hình như name , sizecontentType (thường được gọi là loại MIME). Phương thức putFile() tự động suy ra loại MIME từ phần mở rộng File , nhưng bạn có thể ghi đè loại được phát hiện tự động bằng cách chỉ định contentType trong siêu dữ liệu. Nếu bạn không cung cấp contentType và Cloud Storage không thể suy ra giá trị mặc định từ phần mở rộng tệp thì Cloud Storage sẽ sử dụng application/octet-stream . Xem phần Sử dụng siêu dữ liệu tệp để biết thêm thông tin về siêu dữ liệu tệp.

Kotlin+KTX

// Create file metadata including the content type
var metadata = storageMetadata {
    contentType = "image/jpg"
}

// Upload the file and metadata
uploadTask = storageRef.child("images/mountains.jpg").putFile(file, metadata)

Java

// Create file metadata including the content type
StorageMetadata metadata = new StorageMetadata.Builder()
        .setContentType("image/jpg")
        .build();

// Upload the file and metadata
uploadTask = storageRef.child("images/mountains.jpg").putFile(file, metadata);

Quản lý tải lên

Ngoài việc bắt đầu tải lên, bạn có thể tạm dừng, tiếp tục và hủy tải lên bằng các phương thức pause() , resume()cancel() . Các sự kiện tạm dừng và tiếp tục lần lượt làm tăng các thay đổi trạng thái pauseprogress . Việc hủy tải lên khiến quá trình tải lên không thành công kèm theo lỗi cho biết quá trình tải lên đã bị hủy.

Kotlin+KTX

uploadTask = storageRef.child("images/mountains.jpg").putFile(file)

// Pause the upload
uploadTask.pause()

// Resume the upload
uploadTask.resume()

// Cancel the upload
uploadTask.cancel()

Java

uploadTask = storageRef.child("images/mountains.jpg").putFile(file);

// Pause the upload
uploadTask.pause();

// Resume the upload
uploadTask.resume();

// Cancel the upload
uploadTask.cancel();

Theo dõi tiến trình tải lên

Bạn có thể thêm người nghe để xử lý thành công, thất bại, tiến độ hoặc tạm dừng trong tác vụ tải lên của mình:

Loại người nghe Cách sử dụng điển hình
OnProgressListener Trình nghe này được gọi định kỳ khi dữ liệu được truyền và có thể được sử dụng để điền vào chỉ báo tải lên/tải xuống.
OnPausedListener Trình nghe này được gọi bất cứ khi nào tác vụ bị tạm dừng.
OnSuccessListener Trình nghe này được gọi khi tác vụ đã hoàn thành thành công.
OnFailureListener Trình nghe này được gọi bất cứ khi nào quá trình tải lên không thành công. Điều này có thể xảy ra do hết thời gian chờ mạng, lỗi ủy quyền hoặc nếu bạn hủy tác vụ.

OnFailureListener được gọi với phiên bản Exception . Các trình nghe khác được gọi bằng đối tượng UploadTask.TaskSnapshot . Đối tượng này là một chế độ xem bất biến của nhiệm vụ tại thời điểm sự kiện xảy ra. UploadTask.TaskSnapshot chứa các thuộc tính sau:

Tài sản Kiểu Sự miêu tả
getDownloadUrl String Một URL có thể được sử dụng để tải xuống đối tượng. Đây là một URL công khai không thể đoán được và có thể được chia sẻ với các khách hàng khác. Giá trị này được điền sau khi quá trình tải lên hoàn tất.
getError Exception Nếu tác vụ thất bại, điều này sẽ có nguyên nhân là Ngoại lệ.
getBytesTransferred long Tổng số byte đã được chuyển khi chụp ảnh nhanh này.
getTotalByteCount long Tổng số byte dự kiến ​​sẽ được tải lên.
getUploadSessionUri String Một URI có thể được sử dụng để tiếp tục tác vụ này thông qua một lệnh gọi khác tới putFile.
getMetadata StorageMetadata Trước khi quá trình tải lên hoàn tất, siêu dữ liệu sẽ được gửi đến máy chủ. Sau khi quá trình tải lên hoàn tất, đây là siêu dữ liệu được máy chủ trả về.
getTask UploadTask Tác vụ đã tạo ảnh chụp nhanh này. Sử dụng tác vụ này để hủy, tạm dừng hoặc tiếp tục tải lên.
getStorage StorageReference StorageReference được sử dụng để tạo UploadTask .

Trình xử lý sự kiện UploadTask cung cấp một cách đơn giản và mạnh mẽ để theo dõi các sự kiện tải lên.

Kotlin+KTX

// Observe state change events such as progress, pause, and resume
// You'll need to import com.google.firebase.storage.component1 and
// com.google.firebase.storage.component2
uploadTask.addOnProgressListener { (bytesTransferred, totalByteCount) ->
    val progress = (100.0 * bytesTransferred) / totalByteCount
    Log.d(TAG, "Upload is $progress% done")
}.addOnPausedListener {
    Log.d(TAG, "Upload is paused")
}

Java

// Observe state change events such as progress, pause, and resume
uploadTask.addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
    @Override
    public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
        double progress = (100.0 * taskSnapshot.getBytesTransferred()) / taskSnapshot.getTotalByteCount();
        Log.d(TAG, "Upload is " + progress + "% done");
    }
}).addOnPausedListener(new OnPausedListener<UploadTask.TaskSnapshot>() {
    @Override
    public void onPaused(UploadTask.TaskSnapshot taskSnapshot) {
        Log.d(TAG, "Upload is paused");
    }
});

Xử lý các thay đổi trong vòng đời hoạt động

Quá trình tải lên tiếp tục ở chế độ nền ngay cả sau khi thay đổi vòng đời hoạt động (chẳng hạn như hiển thị hộp thoại hoặc xoay màn hình). Bất kỳ người nghe nào bạn đã đính kèm cũng sẽ vẫn được đính kèm. Điều này có thể gây ra kết quả không mong muốn nếu chúng được gọi sau khi hoạt động bị dừng.

Bạn có thể giải quyết vấn đề này bằng cách đăng ký phạm vi hoạt động cho người nghe của mình để tự động hủy đăng ký họ khi hoạt động dừng lại. Sau đó, sử dụng phương thức getActiveUploadTasks khi hoạt động khởi động lại để nhận các tác vụ tải lên vẫn đang chạy hoặc đã hoàn thành gần đây.

Ví dụ dưới đây chứng minh điều này và cũng cho thấy cách duy trì đường dẫn tham chiếu lưu trữ được sử dụng.

Kotlin+KTX

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

    // If there's an upload 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 an upload in progress, get its reference and create a new StorageReference
    val stringRef = savedInstanceState.getString("reference") ?: return

    storageRef = Firebase.storage.getReferenceFromUrl(stringRef)

    // Find all UploadTasks under this StorageReference (in this example, there should be one)

    val tasks = storageRef.activeUploadTasks

    if (tasks.size > 0) {
        // Get the task monitoring the upload
        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 an upload 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 an upload 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 UploadTasks under this StorageReference (in this example, there should be one)
    List<UploadTask> tasks = mStorageRef.getActiveUploadTasks();
    if (tasks.size() > 0) {
        // Get the task monitoring the upload
        UploadTask task = tasks.get(0);

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

getActiveUploadTasks truy xuất tất cả các tác vụ tải lên đang hoạt động ở và bên dưới tham chiếu được cung cấp, do đó bạn có thể cần phải xử lý nhiều tác vụ.

Tiếp tục tải lên trong toàn bộ quá trình Khởi động lại

Nếu quá trình của bạn bị tắt, mọi quá trình tải lên đang diễn ra sẽ bị gián đoạn. Tuy nhiên, bạn có thể tiếp tục tải lên khi quá trình khởi động lại bằng cách tiếp tục phiên tải lên với máy chủ. Điều này có thể tiết kiệm thời gian và băng thông bằng cách không bắt đầu tải lên từ đầu tệp.

Để thực hiện việc này, hãy bắt đầu tải lên qua putFile . Trên StorageTask kết quả, hãy gọi getUploadSessionUri và lưu giá trị kết quả vào bộ lưu trữ liên tục (chẳng hạn như SharedPreferences).

Kotlin+KTX

uploadTask = storageRef.putFile(localFile)
uploadTask.addOnProgressListener { taskSnapshot ->
    sessionUri = taskSnapshot.uploadSessionUri
    if (sessionUri != null && !saved) {
        saved = true
        // A persisted session has begun with the server.
        // Save this to persistent storage in case the process dies.
    }
}

Java

uploadTask = mStorageRef.putFile(localFile);
uploadTask.addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
    @Override
    public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
        Uri sessionUri = taskSnapshot.getUploadSessionUri();
        if (sessionUri != null && !mSaved) {
            mSaved = true;
            // A persisted session has begun with the server.
            // Save this to persistent storage in case the process dies.
        }
    }
});

Sau khi quá trình của bạn khởi động lại với quá trình tải lên bị gián đoạn, hãy gọi lại putFile. Nhưng lần này cũng vượt qua Uri đã được lưu.

Kotlin+KTX

// resume the upload task from where it left off when the process died.
// to do this, pass the sessionUri as the last parameter
uploadTask = storageRef.putFile(
    localFile,
    storageMetadata { },
    sessionUri,
)

Java

//resume the upload task from where it left off when the process died.
//to do this, pass the sessionUri as the last parameter
uploadTask = mStorageRef.putFile(localFile,
        new StorageMetadata.Builder().build(), sessionUri);

Các phiên kéo dài một tuần. Nếu bạn cố gắng tiếp tục một phiên sau khi phiên đó hết hạn hoặc nếu phiên đó gặp lỗi, bạn sẽ nhận được lệnh gọi lại không thành công. Bạn có trách nhiệm đảm bảo tệp không bị thay đổi giữa các lần tải lên.

Xử lý lỗi

Có một số lý do khiến lỗi có thể xảy ra khi tải lên, bao gồm cả tệp cục bộ không tồn tại hoặc người dùng không có quyền tải tệp mong muốn lên. Bạn có thể tìm thêm thông tin về lỗi trong phần Xử lý lỗi của tài liệu.

Ví dụ đầy đủ

Dưới đây là một ví dụ đầy đủ về quá trình tải lên có theo dõi tiến trình và xử lý lỗi:

Kotlin+KTX

// File or Blob
file = Uri.fromFile(File("path/to/mountains.jpg"))

// Create the file metadata
metadata = storageMetadata {
    contentType = "image/jpeg"
}

// Upload file and metadata to the path 'images/mountains.jpg'
uploadTask = storageRef.child("images/${file.lastPathSegment}").putFile(file, metadata)

// Listen for state changes, errors, and completion of the upload.
// You'll need to import com.google.firebase.storage.component1 and
// com.google.firebase.storage.component2
uploadTask.addOnProgressListener { (bytesTransferred, totalByteCount) ->
    val progress = (100.0 * bytesTransferred) / totalByteCount
    Log.d(TAG, "Upload is $progress% done")
}.addOnPausedListener {
    Log.d(TAG, "Upload is paused")
}.addOnFailureListener {
    // Handle unsuccessful uploads
}.addOnSuccessListener {
    // Handle successful uploads on complete
    // ...
}

Java

// File or Blob
file = Uri.fromFile(new File("path/to/mountains.jpg"));

// Create the file metadata
metadata = new StorageMetadata.Builder()
        .setContentType("image/jpeg")
        .build();

// Upload file and metadata to the path 'images/mountains.jpg'
uploadTask = storageRef.child("images/"+file.getLastPathSegment()).putFile(file, metadata);

// Listen for state changes, errors, and completion of the upload.
uploadTask.addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
    @Override
    public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
        double progress = (100.0 * taskSnapshot.getBytesTransferred()) / taskSnapshot.getTotalByteCount();
        Log.d(TAG, "Upload is " + progress + "% done");
    }
}).addOnPausedListener(new OnPausedListener<UploadTask.TaskSnapshot>() {
    @Override
    public void onPaused(UploadTask.TaskSnapshot taskSnapshot) {
        Log.d(TAG, "Upload is paused");
    }
}).addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception exception) {
        // Handle unsuccessful uploads
    }
}).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
    @Override
    public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
        // Handle successful uploads on complete
        // ...
    }
});

Bây giờ bạn đã tải tệp lên, hãy tìm hiểu cách tải chúng xuống từ Cloud Storage.