package Ġcom . fen bi . android . y tk resource cache . downloader Ċ Ċ import Ġandroid . os . Handler Ċ import Ġandroid . os . Looper Ċ import Ġandroid . util . Log Ċ import Ġcom . fen bi . android . y tk resource cache . File Cache Storage Ċ import Ġkotlinx . coroutines .* Ċ import Ġkotlinx . coroutines . channels . Receive Channel Ċ import Ġkotlinx . coroutines . channels . produce Ċ import Ġokhttp 3 . Ok HttpClient Ċ import Ġjava . util .* Ċ import Ġjava . util . concurrent . Executors Ċ import Ġjava . util . concurrent . atomic . Atomic Long Ċ import Ġkotlin . concurrent . timer Ċ Ċ /** Ċ Ġ* Ġ@ author Ġzh eng Ġon Ġ 1 1 / 2 6 / 1 8 Ċ Ġ*/ Ċ Ċ class ĠDownload Task ( ĊĠĠĠ Ġprivate Ġval Ġresource Urls : ĠList < String >, ĊĠĠĠ Ġprivate Ġval Ġcache Storage : ĠFile Cache Storage , ĊĠĠĠ Ġprivate Ġval ĠhttpClient : ĠOk HttpClient Ġ= Ġdefault Ok HttpClient , ĊĠĠĠ Ġprivate Ġval Ġskip Existing : ĠBoolean Ġ= Ġtrue , ĊĠĠĠ Ġprivate Ġval ĠonSuccess : Ġ(() Ġ-> ĠUnit )? Ġ= Ġnull , ĊĠĠĠ Ġprivate Ġval Ġon Failed : Ġ(( Throwable ) Ġ-> ĠUnit )? Ġ= Ġnull , ĊĠĠĠ Ġprivate Ġval Ġon Progress : Ġ(( List < Progress >) Ġ-> ĠUnit )? Ġ= Ġnull , ĊĠĠĠ Ġprivate Ġval Ġon Speed Update : Ġ(( String ) Ġ-> ĠUnit )? Ġ= Ġnull Ċ ) Ġ{ ĊĊĠĠĠ Ġprivate Ġlateinit Ġvar Ġprogress List : ĠList < Progress > ĊĠĠĠ Ġvar Ġis Downloading Ġ= Ġfalse ĊĠĠĠ Ġprivate Ġvar Ġdownloaded Count : ĠInt Ġ= Ġ 0 ĊĠĠĠ Ġprivate Ġval Ġdownload ers Ġ= Ġmutable ListOf < Resource Downloader >() ĊĠĠĠ Ġprivate Ġval Ġdownload Size Ġ= ĠAtomic Long ( 0 L ) ĊĠĠĠ Ġprivate Ġvar Ġdownload Time Start Ġ= Ġ 0 L ĊĠĠĠ Ġprivate Ġvar Ġtimer : ĠTimer ? Ġ= Ġnull ĊĠĠĠ Ġprivate Ġval Ġthread Pool Ġby Ġlazy Ġ{ ĠExec utors . new Fixed ThreadPool ( THREADS ). as Coroutine Dispatcher () Ġ} ĊĠĠĠ Ġprivate Ġlateinit Ġvar Ġchannel : ĠReceive Channel < Indexed Value < String >> ĊĠĠĠ Ġprivate Ġval Ġui Handler Ġ= ĠHandler ( Looper . get Main Looper ()) ĊĊĠĠĠ Ġfun Ġstart () Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( is Downloading ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġis Downloading Ġ= Ġtrue ĊĠĠĠĠĠĠĠ Ġprogress List Ġ= Ġresource Urls . map Ġ{ ĠProgress ( it ) Ġ} ĊĠĠĠĠĠĠĠ Ġdownloaded Count Ġ= Ġ 0 ĊĠĠĠĠĠĠĠ Ġdownload ers . clear () ĊĠĠĠĠĠĠĠ Ġdownload Size . set ( 0 L ) ĊĠĠĠĠĠĠĠ Ġdownload Time Start Ġ= ĠSystem . currentTimeMillis () ĊĠĠĠĠĠĠĠ Ġchannel Ġ= ĠGlobal Scope . produce Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġresource Urls . with Index (). forEach Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsend ( it ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġlaunch Download ers () ĊĠĠĠĠĠĠĠ Ġstart Timer () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun Ġcancel () Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( is Downloading ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġis Downloading Ġ= Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠ Ġchannel . cancel () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġdownload ers . forEach Ġ{ Ġit . pause () Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġtimer ?. cancel () ĊĠĠĠĠĠĠĠ Ġtimer Ġ= Ġnull ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġlaunch Download ers () Ġ{ ĊĠĠĠĠĠĠĠ ĠGlobal Scope . launch ( Dispatch ers . Main ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġrun Downloads () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠThrowable ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠLog . e ( TAG , Ġ" launch Download ers ", Ġe ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( e Ġ! is ĠC ancellation Exception ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġon Failed ?. invoke ( e ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn @ launch ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġfinally Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthis @ Download Task . cancel () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ ĠonSuccess ?. invoke () ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġsuspend Ġfun Ġrun Downloads () Ġ= Ġcoroutine Scope Ġ{ ĊĠĠĠĠĠĠĠ Ġrepeat ( THREADS ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġdown loader Ġ= ĠResource Downloader ( cache Storage , ĠhttpClient ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġdownload ers . add ( downloader ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlaunch ( thread Pool ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġrun Download ( downloader ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġsuspend Ġfun Ġrun Download ( downloader : ĠResource Downloader ) Ġ{ ĊĠĠĠĠĠĠĠ Ġvar Ġdownload Index Ġ= Ġ 0 ĊĠĠĠĠĠĠĠ Ġdown loader . on Downloaded Bytes Ġ= Ġ{ Ġlength Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġdownload Size . add AndGet ( length ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġdown loader . on Progress Ġ= Ġ{ Ġloaded , Ġtotal Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġui Handler . post Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwith ( progress List [ download Index ]) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthis . loaded Ġ= Ġloaded ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthis . total Ġ= Ġtotal ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġupdate Total Progress () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġwhile Ġ( is Downloading Ġ&& Ġ! channel . is Closed For Receive ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġ( index , Ġurl ) Ġ= Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġchannel . receive () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠThrowable ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġbreak ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġdownload Index Ġ= Ġindex ĊĠĠĠĠĠĠĠĠĠĠĠ ĠLog . d ( TAG , Ġ" download Ġ$ url ") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġfile Ġ= Ġcache Storage . getCache File ( url ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( skip Existing Ġ&& Ġfile ?. exists () Ġ== Ġtrue Ġ&& Ġfile . length () Ġ> Ġ 0 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwith Context ( Dispatch ers . Main ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġprogress List [ download Index ]. total Ġ= Ġfile . length () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdown loader . download ( url ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠThrowable ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthrow Ġe ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġwith Context ( Dispatch ers . Main ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwith ( progress List [ download Index ]) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġloaded Ġ= Ġtotal ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġupdate Total Progress () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġstart Timer () Ġ{ ĊĠĠĠĠĠĠĠ Ġtimer Ġ= Ġtimer ( period Ġ= Ġ 5 0 0 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġui Handler . post Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġdur Ġ= ĠSystem . currentTimeMillis () Ġ- Ġdownload Time Start ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġspeed Ġ= Ġdownload Size . get AndSet ( 0 L ) Ġ* Ġ 1 0 0 0 L Ġ/ Ġdur ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdownload Time Start Ġ= ĠSystem . currentTimeMillis () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġon Speed Update ?. invoke ( speed . readable () Ġ+ Ġ" B / s ") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġupdate Total Progress () Ġ{ ĊĠĠĠĠĠĠĠ Ġon Progress ?. invoke ( progress List ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġdata Ġclass ĠProgress ( val Ġurl : ĠString , Ġvar Ġloaded : ĠLong Ġ= Ġ 0 L , Ġvar Ġtotal : ĠLong Ġ= Ġ 0 L ) ĊĊĠĠĠ Ġcompanion Ġobject Ġ{ ĊĠĠĠĠĠĠĠ Ġprivate Ġconst Ġval ĠTHREAD S Ġ= Ġ 4 ĊĊĠĠĠĠĠĠĠ Ġconst Ġval ĠTAG Ġ= Ġ" Download Task " ĊĊĠĠĠĠĠĠĠ Ġprivate Ġval Ġdefault Ok HttpClient : ĠOk HttpClient Ġby Ġlazy Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠOk HttpClient . Builder () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. build () ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġprivate Ġfun ĠLong . readable (): ĠString Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġvar Ġbytes Ġ= Ġthis ĊĠĠĠĠĠĠĠĠĠĠĠ Ġvar Ġu Ġ= Ġ 0 ĊĠĠĠĠĠĠĠĠĠĠĠ Ġwhile Ġ( bytes Ġ> Ġ 1 0 2 4 Ġ* Ġ 1 0 2 4 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġu ++ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġbytes Ġ= Ġbytes Ġshr Ġ 1 0 ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( bytes Ġ> Ġ 1 0 2 4 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġu ++ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠString . format ("% . 1 f % c ", Ġbytes Ġ/ Ġ 1 0 2 4 f , Ġ" Ġk M GT PE "[ u ]) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ċ } Ċ