بارگذاری کردن فایل با Cloud Storage در Android

Cloud Storage for Firebase به شما امکان می‌دهد به‌سرعت و به‌آسانی فایل‌ها را در یک Cloud Storage bucket ارائه‌شده و مدیریت‌شده توسط Firebase بارگذاری کنید.

بارگذاری فایل‌ها

برای بارگذاری فایل در Cloud Storage، ابتدا مرجعی برای مسیر کامل فایل، ازجمله نام فایل، ایجاد می‌کنید.

Kotlin

// 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

پس‌از ایجاد مرجع مناسب، سپس روش putBytes()، putFile()، یا putStream() را برای بارگذاری فایل در Cloud Storage فراخوانی می‌کنید.

نمی‌توانید داده‌ها را با ارجاع به ریشه Cloud Storage bucket بارگذاری کنید. مرجع شما باید به نشانی وب فرزند اشاره کند.

بارگذاری از داده‌های موجود در حافظه

روش putBytes() ساده‌ترین راه برای بارگذاری فایل در Cloud Storage است. putBytes() byte[] را می‌گیرد و UploadTask را برمی‌گرداند که می‌توانید از آن برای مدیریت و نظارت بر وضعیت بارگذاری استفاده کنید.

Kotlin

// 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() byte[] را می‌پذیرد، لازم است برنامه‌تان کل محتوای فایل را به‌طور هم‌زمان در حافظه نگه دارد. برای استفاده از حافظه کمتر، از putStream() یا putFile() استفاده کنید.

بارگذاری از جاری‌سازی

روش putStream() همه‌کاره‌ترین روش برای بارگذاری فایل در Cloud Storage است. putStream() یک InputStream می‌گیرد و یک UploadTask برمی‌گرداند که می‌توانید از آن برای مدیریت و نظارت بر وضعیت بارگذاری استفاده کنید.

Kotlin

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.
        // ...
    }
});

بارگذاری از فایل محلی

می‌توانید فایل‌های محلی موجود در دستگاه، مثل عکس‌ها و ویدیوهای دوربین را با روش putFile() بارگذاری کنید. putFile() File را می‌گیرد و UploadTask را برمی‌گرداند که می‌توانید از آن برای مدیریت و نظارت بر وضعیت بارگذاری استفاده کنید.

Kotlin

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.
        // ...
    }
});

دریافت نشانی وب بارگیری

پس‌از بارگذاری فایل، می‌توانید با فراخوانی روش getDownloadUrl() در StorageReference، نشانی وب را برای بارگیری فایل دریافت کنید:

Kotlin

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
            // ...
        }
    }
});

افزودن فراداده فایل

همچنین می‌توانید هنگام بارگذاری فایل‌ها، فراداده اضافه کنید. این فراداده حاوی ویژگی‌های فراداده فایل معمولی مانند name، size، و contentType (که معمولاً به‌عنوان نوع MIME شناخته می‌شود) است. روش putFile() به‌طور خودکار نوع MIME را از افزونه File استنباط می‌کند، اما می‌توانید نوع شناسایی‌شده خودکار را با مشخص کردن contentType در فراداده لغو کنید. اگر contentType ارائه نکنید و Cloud Storage نتواند پیش‌فرضی را از پسوند فایل استنباط کند، Cloud Storage از application/octet-stream استفاده می‌کند. برای اطلاعات بیشتر درباره فراداده فایل، بخش استفاده از فراداده فایل را ببینید.

Kotlin

// 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);

مدیریت بارگذاری‌ها

علاوه‌بر شروع بارگذاری، می‌توانید بااستفاده از روش‌های pause()، resume()، و cancel() بارگذاری‌ها را موقتاً متوقف کنید، ازسر بگیرید، و لغو کنید. رویدادهای توقف موقت و ازسرگیری به‌ترتیب تغییرات وضعیت pause و progress را ایجاد می‌کنند. لغو کردن بارگذاری باعث می‌شود بارگذاری با خطایی مواجه شود که نشان می‌دهد بارگذاری لغو شده است.

Kotlin

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();

نظارت بر پیشرفت بارگذاری

می‌توانید شنوندگانی را برای مدیریت موفقیت، شکست، پیشرفت، یا توقف در کار بارگذاری خود اضافه کنید:

نوع شنونده استفاده معمول
OnProgressListener این شنونده به‌صورت دوره‌ای با انتقال داده‌ها فراخوانی می‌شود و می‌توان از آن برای پر کردن نشانگر بارگذاری/بارگیری استفاده کرد.
OnPausedListener هرزمان که تکلیف موقتاً متوقف شود، این شنونده فراخوانده می‌شود.
OnSuccessListener این شنونده زمانی فراخوانی می‌شود که تکلیف با موفقیت تکمیل شده باشد.
OnFailureListener این شنونده هرزمان که بارگذاری ناموفق باشد فراخوانده می‌شود. این اتفاق ممکن است به‌دلیل اتمام مهلت شبکه، ناموفق بودن مجوز، یا لغو کردن تکلیف ازسوی شما رخ دهد.

‫OnFailureListener با نمونه Exception فراخوانی می‌شود. شنوندگان دیگر با شیء UploadTask.TaskSnapshot فراخوانده می‌شوند. این شیء نمای تغییرناپذیری از تکلیف در زمان وقوع رویداد است. UploadTask.TaskSnapshot حاوی ویژگی‌های زیر است:

دارایی نوع شرح
getDownloadUrl String نشانی وبی که می‌توان از آن برای بارگیری شیء استفاده کرد. این نشانی وب عمومی غیرقابل‌حدس است که می‌توان آن را با مشتریان دیگر هم‌رسانی کرد. این مقدار پس‌از تکمیل بارگذاری پر می‌شود.
getError Exception اگر تکلیف ناموفق باشد، علت آن به‌عنوان «استثنا» نشان داده می‌شود.
getBytesTransferred long تعداد کل بایت‌هایی که هنگام گرفتن این عکس آنی منتقل شده است.
getTotalByteCount long تعداد کل بایت‌هایی که انتظار می‌رود بارگذاری شود.
getUploadSessionUri String شناسه منبع یکسانی که می‌تواند برای ادامه این تکلیف ازطریق تماس دیگری با putFile استفاده شود.
getMetadata StorageMetadata پیش‌از تکمیل بارگذاری، این فراداده به سرور ارسال می‌شود. پس‌از تکمیل بارگذاری، این فراداده‌ای است که سرور برمی‌گرداند.
getTask UploadTask تکلیفی که این عکس آنی را ایجاد کرده است. از این تکلیف برای لغو، توقف موقت، یا ازسرگیری بارگذاری استفاده کنید.
getStorage StorageReference ‫StorageReference استفاده‌شده برای ایجاد UploadTask.

شنوندگان رویداد UploadTask روشی ساده و قدرتمند برای نظارت بر رویدادهای بارگذاری ارائه می‌دهند.

Kotlin

// 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");
    }
});

مدیریت تغییرات چرخه حیات فعالیت

بارگذاری‌ها در پس‌زمینه ادامه می‌یابند، حتی پس‌از تغییرات چرخه حیات فعالیت (مانند ارائه یک کادر گفتگو یا چرخاندن صفحه). هر شنونده‌ای که پیوست کرده بودید نیز پیوست‌شده باقی خواهد ماند. اگر این روش‌ها پس‌از توقف فعالیت فراخوانی شوند، ممکن است نتایج غیرمنتظره‌ای ایجاد کنند.

می‌توانید این مشکل را با مشترک کردن شنوندگان خود با یک دامنه فعالیت حل کنید تا وقتی فعالیت متوقف می‌شود، به‌طور خودکار ثبت‌نام آن‌ها لغو شود. سپس، از روش getActiveUploadTasks هنگام بازراه‌اندازی فعالیت برای دریافت تکالیف بارگذاری که هنوز درحال اجرا هستند یا اخیراً تکمیل شده‌اند استفاده کنید.

مثال زیر این موضوع را نشان می‌دهد و همچنین نحوه حفظ مسیر مرجع فضای ذخیره‌سازی استفاده‌شده را نشان می‌دهد.

Kotlin

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 همه تکالیف بارگذاری فعال را در مرجع ارائه‌شده و پایین‌تر از آن بازیابی می‌کند، بنابراین ممکن است لازم باشد چندین تکلیف را مدیریت کنید.

ادامه بارگذاری‌ها در سراسر بازراه‌اندازی‌های فرایند

اگر فرایند شما متوقف شود، هرگونه بارگذاری درحال انجام قطع خواهد شد. اما پس‌از بازراه‌اندازی فرایند، می‌توانید با ازسرگیری جلسه بارگذاری با سرور، بارگذاری را ادامه دهید. این کار می‌تواند با شروع نکردن بارگذاری از ابتدای فایل، در زمان و پهنای باند صرفه‌جویی کند.

برای انجام این کار، بارگذاری را ازطریق putFile شروع کنید. در StorageTask حاصل، getUploadSessionUri را فراخوانی کنید و مقدار حاصل را در فضای ذخیره‌سازی پایا (مثل SharedPreferences) ذخیره کنید.

Kotlin

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.
        }
    }
});

پس‌از اینکه فرایندتان با بارگذاری قطع‌شده بازراه‌اندازی شد، دوباره putFile را فراخوانی کنید. اما این بار شناسه منبع یکسانی را که ذخیره شده است نیز ارسال کنید.

Kotlin

// 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);

جلسه‌ها یک هفته طول می‌کشد. اگر بخواهید جلسه‌ای را پس‌از منقضی شدن یا پس‌از مواجه شدن با خطا ازسر بگیرید، فراخوانی برگشتی ناموفق دریافت خواهید کرد. مسئولیت اطمینان از اینکه فایل بین بارگذاری‌ها تغییر نکرده است برعهده شما است.

مدیریت خطا

دلایل متعددی برای بروز خطا در بارگذاری وجود دارد، ازجمله عدم وجود فایل محلی، یا نداشتن اجازه کاربر برای بارگذاری فایل موردنظر. می‌توانید اطلاعات بیشتری درباره خطاها در بخش رسیدگی به خطاها در اسناد پیدا کنید.

نمونه کامل

نمونه کاملی از بارگذاری با پایش پیشرفت و رسیدگی به خطا در زیر نشان داده شده است:

Kotlin

// 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
        // ...
    }
});

اکنون که فایل‌ها را بارگذاری کرده‌اید، بیایید با نحوه بارگیری آن‌ها از Cloud Storage آشنا شویم.