Upgrade to Pro — share decks privately, control downloads, hide ads and more …

kotlinコルーチンで作ってみる画像ローダ @ potatotips #43

kotlinコルーチンで作ってみる画像ローダ @ potatotips #43

potatotips #43にて発表したkotlinコルーチンを使って画像ローダを作る話です。今は発表したスライドそのままなのですがあとで差し替え予定です

Yoshihiro WADA

August 28, 2017
Tweet

More Decks by Yoshihiro WADA

Other Decks in Technology

Transcript

  1. こういう感じのものを作る 画像ギャラリー っぽく多数の画像をインター ネットからロー ドする 表示時の画像は B i t m

    a p F a c t o r y . O p t i o n s で縮小する I m a g e L o a d e r . w i t h ( c o n t e x t ) . l o a d ( u r l ) . i n t o ( i m a g e V i e w ) みたいな感じでImageView に ロー ドさせたい
  2. とりあえず画像ロー ド以外… c l a s s I m a

    g e L o a d e r p r i v a t e c o n s t r u c t o r ( p r i v a t e v a l c o n t e x t : C o n t e x t ) { p r i v a t e v a r u r l : S t r i n g ? = n u l l c o m p a n i o n o b j e c t { f u n w i t h ( c o n t e x t : C o n t e x t ) : I m a g e L o a d e r { r e t u r n I m a g e L o a d e r ( c o n t e x t ) } } f u n l o a d ( u r l : S t r i n g ) : I m a g e L o a d e r { t h i s . u r l = u r l r e t u r n t h i s } f u n i n t o ( t a r g e t : I m a g e V i e w ) { / / ここで画像ロー ド } }
  3. いつも通りのロー ド f u n i n t o (

    t a r g e t : I m a g e V i e w ) { / / R e q u e s t の生成は省略… c l i e n t . n e w C a l l ( r e q u e s t ) . e n q u e u e ( o b j e c t : C a l l b a c k { o v e r r i d e f u n o n R e s p o n s e ( c a l l : C a l l ? , r e s p o n s e : R e s p o n s e ? ) { v a l b o d y = r e s p o n s e ? . b o d y ( ) b o d y ? : r e t u r n / / 取得した画像バイト配列から縮小画像生成 v a l b y t e A r r a y = b o d y . b y t e s ( ) v a l o p t i o n s = g e t B i t m a p O p t i o n s ( b y t e A r r a y ) v a l b i t m a p = g e t S c a l e d B i t m a p ( t a r g e t , o p t i o n s , b y t e A r r a y ) / / 対象のI m a g e V i e w に画像を表示 ( c o n t e x t a s A c t i v i t y ) . r u n O n U i T h r e a d { t a r g e t . s e t I m a g e B i t m a p ( b i t m a p ) } } } ) }
  4. Coroutine を使ってみる( 導入) app/build.gradle d e p e n d

    e n c i e s { i m p l e m e n t a t i o n " o r g . j e t b r a i n s . k o t l i n x : k o t l i n x - c o r o u t i n e s - c o r e : 0 . 1 8 " i m p l e m e n t a t i o n " o r g . j e t b r a i n s . k o t l i n x : k o t l i n x - c o r o u t i n e s - a n d r o i d : 0 . 1 8 " } k o t l i n { e x p e r i m e n t a l { c o r o u t i n e s " e n a b l e " } }
  5. 例えばこんなコー ドが f u n r e q u e

    s t I t e m s ( ) { i t e m A p i . g e t I t e m s ( o b j e c t : C a l l b a c k { o v e r r i d e f u n o n S u c c e s s ( i t e m : I t e m ) { t e x t V i e w . t e x t = i t e m . n a m e } } ) }
  6. こんな感じになる f u n r e q u e s

    t I t e m s ( ) { v a l j o b = l a u n c h ( U I ) { / / 一旦ここで関数の実行がi t e m A p i . g e t I t e m s ( ) が完了するまで止まる v a l i t e m = a s y n c ( C o m m o n P o o l ) { i t e m A p i . g e t I t e m s ( ) } . a w a i t ( ) t e x t V i e w . t e x t = i t e m . n a m e } }
  7. API クラスに分けて c l a s s I m a

    g e A p i { p r i v a t e v a l c l i e n t = O k H t t p C l i e n t ( ) f u n g e t I m a g e ( u r l : S t r i n g ? ) : R e s p o n s e B o d y { v a l r e q u e s t = R e q u e s t . B u i l d e r ( ) . u r l ( u r l ) . b u i l d ( ) v a l b o d y = c l i e n t . n e w C a l l ( r e q u e s t ) . e x e c u t e ( ) / / a s y n c させるしe x e c u t e で良さそう? . b o d y ( ) b o d y ? : t h r o w E x c e p t i o n ( " R e s p o n s e B o d y i s n u l l " ) r e t u r n b o d y } }
  8. async/await させてみる f u n i n t o (

    t a r g e t : I m a g e V i e w ) { v a l j o b = l a u n c h ( U I ) { v a l b y t e A r r a y = a s y n c ( C o m m o n P o o l ) { I m a g e A p i ( ) . g e t I m a g e ( u r l ) . b y t e s ( ) } . a w a i t ( ) v a l o p t i o n s = a s y n c ( C o m m o n P o o l ) { g e t B i t m a p O p t i o n s ( b y t e A r r a y ) } . a w a i t ( ) v a l b i t m a p = a s y n c ( C o m m o n P o o l ) { g e t S c a l e d B i t m a p ( t a r g e t , o p t i o n s , b y t e A r r a y ) } . a w a i t ( ) t a r g e t . s e t I m a g e B i t m a p ( b i t m a p ) } }
  9. Call の e x e c u t e (

    ) をawait する拡張サスペンド関数を作る s u s p e n d f u n C a l l . a w a i t ( ) : R e s p o n s e B o d y { r e t u r n s u s p e n d C a n c e l l a b l e C o r o u t i n e { c o n t i n u a t i o n - > e n q u e u e ( o b j e c t : C a l l b a c k { o v e r r i d e f u n o n R e s p o n s e ( c a l l : C a l l , r e s p o n s e : R e s p o n s e ) { v a l r e s p o n s e B o d y = r e s p o n s e . b o d y ( ) i f ( r e s p o n s e B o d y = = n u l l ) { c o n t i n u a t i o n . r e s u m e W i t h E x c e p t i o n ( E x c e p t i o n ( " R e s p o n s e B o d y i s n u l l " ) ) } e l s e { c o n t i n u a t i o n . r e s u m e ( r e s p o n s e B o d y ) } } o v e r r i d e f u n o n F a i l u r e ( c a l l : C a l l , e : I O E x c e p t i o n ) { i f ( c o n t i n u a t i o n . i s C a n c e l l e d ) r e t u r n c o n t i n u a t i o n . r e s u m e W i t h E x c e p t i o n ( e ) } } ) } }
  10. ImageApi のメソッドもCall を返すようにする c l a s s I m

    a g e A p i { p r i v a t e v a l c l i e n t = O k H t t p C l i e n t ( ) f u n g e t I m a g e ( u r l : S t r i n g ? ) : C a l l { v a l r e q u e s t = R e q u e s t . B u i l d e r ( ) . u r l ( u r l ) . b u i l d ( ) r e t u r n c l i e n t . n e w C a l l ( r e q u e s t ) } }
  11. async/await するときに C a l l . a w a

    i t ( ) を呼ぶ f u n i n t o ( t a r g e t : I m a g e V i e w ) { v a l j o b = l a u n c h ( U I ) { v a l b y t e A r r a y = a s y n c ( C o m m o n P o o l ) { / / R e s p o n s e を待ってからバイト配列を取得 I m a g e A p i ( ) . g e t I m a g e ( u r l ) . a w a i t ( ) . b y t e s ( ) } . a w a i t ( ) v a l o p t i o n s = a s y n c ( C o m m o n P o o l ) { / / 結果からB i t m a p F a c t o r y . O p t i o n s を取得 g e t B i t m a p O p t i o n s ( b y t e A r r a y ) } . a w a i t ( ) v a l b i t m a p = a s y n c ( C o m m o n P o o l ) { / / 上2 つが終わったらB i t m a p を縮小 g e t S c a l e d B i t m a p ( t a r g e t , o p t i o n s , b y t e A r r a y ) } . a w a i t ( ) t a r g e t . s e t I m a g e B i t m a p ( b i t m a p . a w a i t ( ) ) / / b i t m a p が出力されたらt a r g e t に表示 } } r u n O n U i T h r e a d とかしなくていいのでcontext が不要になった
  12. まとめ 明示的にUI スレッド/ サブスレッドでの動作と処理の完了待機が宣言できるので良い 非同期処理が簡潔に書ける Rx とも連携可能っぽい r x S

    i n g l e で S i n g l e < T > を返すコルー チンを作ってくれるみたい 標準ライブラリに早く入ってくれないかな