آپلود پوشه و اکران جلو رفتن آن در کاتلین – از صفر تا صد
آپلود پوشه و اکران جلو رفتن آن در کاتلین – از صفر تا صد
درحالتی که میخواهید یک پوشه را با به کارگیری از ساختار سرراست Retrofit آپلود نمایید، شاید متوجه گردید که قابلیت و امکان اخذ سود و همینطور اکران نوار جلو رفتن در کاتلین را ندارید. ما درین نوشتهیعلمی از Retrofit برای آپلود فولدر استعمال می کنیم و ساختاری پیادهسازی می کنیم که قابلیت و امکان اخذ معیار توسعه و گسترش عمل را در برهه زمانیهای هنگامی متعدد داراست و نهایتاً با کامل شدن جواب API ریموت، نقطه طراحی اپلیکیشن در مشهد نهایی مییابد.
هر فرصت که عملیاتی بلندمدت در اکنون ایفا میباشد، بهتر میباشد که فرایند جلو رفتن عمل را به مخاطب نماد دهیم. در زمینه ی آپلود فولدر میتوانیم بسط حقیقی و واقعی عمل را که بر حسب بایتهای جابجایییافته از آحاد اندازه پوشه به حساب آوردن میشود به استفاده کننده علامت دهیم.
درپی از API-های جان دار در کتابخانههای Retrofit ،OkHttp و Okio برای تشکیل داد یک کلاس به کار گیری می کنیم که برای اکران فرآیند جلو رفتن آپلود فولدر گزینه به کارگیری قرار میگیرند.
نقطه انتهایی
فرض فرمایید در هم اکنون گسترش یک نرم افزار پیامرسانی هستیم که قابلیت و امکان الصاق پوشه به حرفه پیام را دارااست. قابل ذکر میباشد کهاین کامپوننت واکنشی از RxJava به کارگیری مینماید، ولی میاقتدار از Callback-های بی آلایش یا این که کوروتینها و تابعهای تعلیقی کاتلین نیز به کار گرفت.
نقطه انتهایی (endpoint) ما یک درخواست POST میباشد که دربرگیرنده بدنه چندبخشی میباشد که از اجزای اسم فولدر، نوع MIME پوشه، اندازه فولدر و خویش فولدر تشکیل یافته میباشد. آن را می توانیم با استعمال از Retrofit و با گزینش قسمتهای مورد نیاز به روشای همانند کد پایین تعریف و تمجید کنیم:
@Multipart
@POST("file")
fun attachFile(
@Part("name") filename: RequestBody,
@Part("type") mimeType: RequestBody,
@Part("size") fileSize: RequestBody,
@Part filePart: MultipartBody.Part
): Single
شمارش جلو رفتن
درصورتی که تنهاً میخواستیم پوشه را سوای اکران مراحل توسعه و گسترش، آپلود کنیم، کافی بود فولدر را به بدنه درخواست تبدیل کنیم و آن را در درخواست خویش بفرستیم.
fun createUploadRequestBody(file: File, mimeType: String) =
file.asRequestBody(mimeType.toMediaType())
رسیدگی بر گسترش آپلود نیز با به کار گیری از CountingRequestBody نتایج میگردد که در پوشه RequestBody جای دارد و تا قبل از اینً استعمال کردیم. دادههایی که ارسال میشوند همچون قبلی می باشند و به فولدر ناپخته RequestBody قابلیت و امکان میدهیم که نماینده نوع محتوا و ارتفاع محتوا باشد.
class CountingRequestBody(
private val requestBody: RequestBody,
private val onProgressUpdate: CountingRequestListener
) : RequestBody() {
override fun contentType() = requestBody.contentType()
@Throws(IOException::class)
override fun contentLength() = requestBody.contentLength()
...
}
جابجایی بدنه درخواست با تایپ کردن یک Sink جاری ساختن مییابد و Sink پیشفرض را داخل آن Sink قرار میدهیم که بایتهای انتقالی را میشمارد و آنها را از روش یک Callback جلو رفتن رجوع میدهد.
typealias CountingRequestListener = (bytesWritten: Long, contentLength: Long) -> Unit
class CountingSink(
sink: Sink,
private val requestBody: RequestBody,
private val onProgressUpdate: CountingRequestListener
) : ForwardingSink(sink) {
private var bytesWritten = 0L
override fun write(source: Buffer, byteCount: Long) {
super.write(source, byteCount)
bytesWritten += byteCount
onProgressUpdate(bytesWritten, requestBody.contentLength())
}
}
مشاهده بی نقص کدها
داخل CountingRequestBody خواهیم توانست Sink پیشفرض را در CountingSink تازه خویش در اختیار بگذاریم و ورژن بافر گردیدهی آن را بنویسیم تا هم فولدر جابجایی یابد و هم مراحل جلو رفتن را ببینیم.
class CountingRequestBody(...) : RequestBody() {
...
@Throws(IOException::class)
override fun writeTo(sink: BufferedSink) {
val countingSink = CountingSink(sink, this, onProgressUpdate)
val bufferedSink = countingSink.buffer()
requestBody.writeTo(bufferedSink)
bufferedSink.flush()
}
}
فیض
در طول مشاهده جلو رفتن پروسه آپلود، دو موقعیت وجود داراست یا این که پوشه در اکنون آپلود شدن میباشد و یا این که عمل به اتمام رسیده و از این رو خوب میباشد از یک کلاس مهرومومگردیده (sealed) استعمال کنیم. این کلاس قابلیت می دهد که یک نوع بازگشتی CountingRequestResult داشته باشیم و فراخوانیکنندهها میتوانند هم بهروزرسانیهای جلو رفتن به و هم فیض کامل شدنگردیده را رئیس نمایند.
sealed class CountingRequestResult {
data class Progress(
val progressFraction: Double
) : CountingRequestResult()
data class Completed(
val result: ResultT
) : CountingRequestResult()
}
اجرای آپلود
در حال حاضر که روشی برای آپلود کردن پوشه و اخذ پروسه جلو رفتن آپلود یافتیم، می توانیم FileUploader خویش را بنویسیم. ساختوساز بدنه درخواست برای درخواست آپلود دربرگیرنده به کارگیری از CountingRequestBody میباشد که جلو رفتن و کامل شدن را به یک PublishSubject گزارش میدهد.
private fun createUploadRequestBody(
file: File,
mimeType: String,
progressEmitter: PublishSubject
): RequestBody {
val fileRequestBody = file.asRequestBody(mimeType.toMediaType())
return CountingRequestBody(fileRequestBody) { bytesWritten, contentLength ->
val progress = 1.0 * bytesWritten / contentLength
progressEmitter.onNext(progress)
if (progress >= 1.0) {
progressEmitter.onComplete()
}
}
}
مشاهده بدون نقص کدها
درخواست آپلود مشمول به کارگیری از تابع Retrofit میباشد که در اولِ نوشتهی علمی پیادهسازی کردیم و جزئییات پوشه و بدنه ساخت و ساز گردیده درخواست که روند جلو رفتن را گزارش میدهند. تعریفوتمجید Retrofit و پوسته قسمتهای درخواست به طرز خاص هر API بستگی داراهستند. درین نوشتهیعلمی ما از یک درخواست به کارگیری می کنیم که مشمول قسمتهای متنی معمولی مختلفی برای ریزه کاری پوشه میباشد و بعد یک قسمت برای خویش فایلی که قرار میباشد آپلود خواهد شد، ارائه مینماید.
private fun createUploadRequest(
filename: String,
file: File,
mimeType: String,
progressEmitter: PublishSubject
): Single {
val requestBody = createUploadRequestBody(file, mimeType, progressEmitter)
return remoteApi.attachFile(
filename = filename.toPlainTextBody(),
mimeType = mimeType.toPlainTextBody(),
fileSize = file.length().toString().toPlainTextBody(),
filePart = MultipartBody.Part.createFormData(
name = "files[]",
filename = filename,
body = requestBody
)
)
}
private fun String.toPlainTextBody() = toRequestBody("text/plain".toMediaType())
مشاهده بی نقص کدها
تابع مهم آپلود ما می تواند همگی این قسمتها را کنار هم قرار داده و یک استریم منفرد ساختوساز نماید. به این ترتیب خواهیم توانست این پروسه را مشاهده کرده و فرآیند جلو رفتن آپلود را نیز در فیض پایانی ببینیم.
fun uploadAttachment(
filename: String, file: File, mimeType: String
): Observable {
val progressEmitter = PublishSubject.create()
val uploadRequest = createUploadRequest(
filename, file, mimeType, progressEmitter
)
val uploadResult = uploadRequest
.map {
CountingRequestResult.Completed(it.result)
}
.toObservable()
val progressResult = progressEmitter
.map {
CountingRequestResult.Progress(it)
}
return progressResult.mergeWith(uploadResult)
}
typealias AttachmentUploadRemoteResult =
CountingRequestResult
مشاهده بی نقص کدها
اینک خواهیم توانست پوشه را به API خویش آپلود کنیم و نما را به طور جلو رفتنهای درخواست بهروزرسانی کنیم که برای عملیات وقتگیر برهه زمانی مانند آپلود پوشههای حجیم اثر گذار میباشد.
uploader.uploadAttachment(request.filename, request.file, request.mimeType)
.subscribeOn(appRxSchedulers.io)
.observeOn(appRxSchedulers.main)
.subscribeBy(
onError = { error ->
// Display error alert
},
onComplete = {
// Display completed Snackbar
},
onNext = { progress ->
// Update progress bar
}
)
.addTo(disposeBag)
مشاهده بی نقص کدها
حرف نهایی
پژوهش بر گسترش یک درخواست اینترنت ممکن میباشد در طول تلاوت یک Retrofit API چندان بدیهی به لحاظ نرسد، ولی API-های قادر OkHttp و Okio می توانند این فعالیت را به خیر اعمال می دهند. خط مشحلی که درین راهنما معرفی کردیم، می تواند برای هر درخواست اینترنت جاری ساختن خواهد شد، زیرا شمارش جلو رفتن را میقدرت داخل هر RequestBody که مورد نیاز میباشد در درخواست ارسال خواهد شد قرار اعطا کرد.