Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
大きい画像をたくさんアップロードするために
Search
Yoshihiro WADA
December 11, 2018
Programming
570
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
大きい画像をたくさんアップロードするために
2018/12/11に開催されたOtemachi.apk #1にて発表した「大きい画像をたくさんアップロードするために」のスライドです。
Yoshihiro WADA
December 11, 2018
More Decks by Yoshihiro WADA
See All by Yoshihiro WADA
AndroidデバイスにFTPサーバを建立する
e10dokup
0
1.4k
Gradleの実行環境設定を見直す
e10dokup
0
1.3k
Firebase App Distributionのテストアプリ配信を試しやすくする
e10dokup
1
730
アプリに署名する 〜GitHub ActionsでのCIも見据えて〜
e10dokup
0
1.3k
Profileable buildでより正確なパフォーマンスを掴む
e10dokup
0
800
[DroidKaigi 2021] メディアアクセス古今東西 / Now and Future of Media Access
e10dokup
0
4k
今更「dp」を考える / Let's think about "dp" now
e10dokup
0
5.9k
1から学ぶAndroidアプリデバッグ - アプリの動作を追いかけよう / Learn Android application debugging from the scratch - track apps' behaviors
e10dokup
10
3.7k
Guide to background processingを読んでみる / Reading "Guide to background processing"
e10dokup
0
310
Other Decks in Programming
See All in Programming
「AIで開発し、AIを届ける」をEvalでつなぐ 〜AIネイティブに始めるプロダクト開発の実践〜 / Connecting "Develop with AI, deliver AI" with Eval
rkaga
4
5.3k
「なぜそう決めたのか」を残し続ける仕組み ― Notion AI カスタムエージェント × Slack連携による設計判断の自動記録 - NIKKEI Tech Talk #47
niftycorp
PRO
0
210
OSもどきOS
arkw
0
570
RTSPクライアントを自作してみた話
simotin13
0
610
技術的負債解消で開発者の未来を開く- AIの力でコード刷新
kmd2kmd
0
110
Inside Stream API
skrb
1
740
AI 輔助遺留系統現代化的經驗分享
jame2408
1
780
Datadog × OpenTelemetry 入門と実践のあいだ
kn_to_maxpno
1
160
「エンジニアインターン、どうやって取った?」準備のリアルを語るLT会 Progate BAR
akiomatic
0
140
Spec Driven Development | AI Summit Lisbon
danielsogl
PRO
0
200
Performance Engineering for Everyone
elenatanasoiu
0
180
Semantic Version 単位で戦略を柔軟に変えて、パッケージアップデートを自動化する
daitasu
1
260
Featured
See All Featured
Hiding What from Whom? A Critical Review of the History of Programming languages for Music
tomoyanonymous
2
860
Reality Check: Gamification 10 Years Later
codingconduct
0
2.2k
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
2
1.5k
Applied NLP in the Age of Generative AI
inesmontani
PRO
4
2.3k
The Language of Interfaces
destraynor
162
27k
Color Theory Basics | Prateek | Gurzu
gurzu
0
370
How To Speak Unicorn (iThemes Webinar)
marktimemedia
1
490
Exploring the relationship between traditional SERPs and Gen AI search
raygrieselhuber
PRO
2
4k
A designer walks into a library…
pauljervisheath
211
24k
A Tale of Four Properties
chriscoyier
163
24k
Building the Perfect Custom Keyboard
takai
2
800
Docker and Python
trallard
47
3.9k
Transcript
大きい画像をたくさんアップロードするために Cyber Agent Inc. Yoshihiro Wada a.k.a. @e10dokup 2018/12/11 Otemachi.apk
自己紹介 • Yoshihiro Wada a.k.a. @e10dokup • 大体左のアイコンで息をしています • CyberAgant
Inc. / Ameba • Amebaブログやってます • We’re Hiring • カメラ沼 • 財布の透過率が高いのが最近の悩み
今回のお話 • 大きい画像をいっぱいアップロードしたい • スマホで撮った写真とか • デジタルカメラやFlashAirからWi-Fiで持ってきた写真とか • 別に画像に限った話ではない •
立ちはだかる壁 • 通信量 • モバイルネットワークでやると無限にギガが減る • メモリ • 展開の仕方によってはOOMでドゥンとクラッシュしてしまう
普通に考えると… • そもそも大きい画像を扱わないようにする • スマートフォンの小さい画面に2000万画素オーバーの大きさのサイズはオーバースペック • 500万画素くらいの大きさならまだわかるレベルになる • 「Android 画像
リサイズ」で検索すると出てくるようなお話 • UI上に扱う画像を表示する際はもちろんリサイズは大事 • 今回本当にやりたいこと • UI上の表示ではなく、Google Photosのようなアルバムサービスへのアップロード • できるなら撮影した画質そのままで扱いたい • 圧縮しようのないデータのアップロード
というわけでやっていきましょう
まず一連の流れを把握 • 扱う画像・ファイルを取得する • ストレージだったり、FlashAirだったり、LAN内のNASだったり… • この時点で端末メモリ上には配置される • 端末メモリ上に配置したファイルをアップロード •
ファイルアップロードが完了するまでメモリ上には当然残る • 失敗したら…の処理も存在する • これがファイル1つに対しての処理の流れになる • 複数存在している場合は当然複数回繰り返す、並列に走らせるといった対応が必要
だいたいこんな感じ…? ファイル取得 アップロード ファイル取得 アップロー とか ファイル取得 アップロード ファイル取得 アップロード
時系列
要するに、同時に走る処理の数を いい感じに制限してあげればいい
やってみる • ファイル一覧がListで存在 • 画像取得、アップロードを行う処理を作る • 具体的な処理についてはキリが無くなるので省略で…
Rxだとこんな感じ Observable.fromIterable(fileList) .concatMap { // ϑΝΠϧऔಘॲཧ } .concatMap { //
Ξοϓϩʔυॲཧ } .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe { // ௨৴ྃ࣌ॲཧ }
Rxだとこんな感じ Observable.fromIterable(fileList) .concatMap { // ϑΝΠϧऔಘॲཧ } .concatMap { //
Ξοϓϩʔυॲཧ } .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe { // ௨৴ྃ࣌ॲཧ } ファイルリストをObservableに
Rxだとこんな感じ Observable.fromIterable(fileList) .concatMap { // ϑΝΠϧऔಘॲཧ } .concatMap { //
Ξοϓϩʔυॲཧ } .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe { // ௨৴ྃ࣌ॲཧ } 流れてくるストリームをファイル取得に使う。 (ストレージアクセスなりネットワークアクセスなり)
Rxだとこんな感じ Observable.fromIterable(fileList) .concatMap { // ϑΝΠϧऔಘॲཧ } .concatMap { //
Ξοϓϩʔυॲཧ } .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe { // ௨৴ྃ࣌ॲཧ } 流れてきたファイルをアップロード
えっ、これで大丈夫なの? • fromIterableでファイルリストの中身を一つずつストリームに流している • flatMapではなくconcatMapでストリーム順序を優先するようにした • 50MBのファイルがストリームに流れると流石にOOMが出るので注意 • Android Profilerでメモリアロケーションを見てるとGCがだいぶ愉快
という感じなんですが 手元では問題無く動いているように見えるだけで 自信がないので詳しい人に助けてほしい…
• ファイル一つに対しての処理は以下の感じ • ファイルを取得する • その結果をawaitして、アップロードにつなげる • この処理自体もawaitして、終わり次第次のファイルについて同様の処理をする… といった再帰的な実行をすることになりそう たぶんCoroutinesだと
ファイル取得 アップロード await await 全部終了 まだ次がある
アクセシビリティに気をつける • ファイルサイズが大きいぶん、当然アップロードまでにかかる処理が長い • 画面でダイアログ出してぐるぐる…なんてやってるとキリがない • アップロード処理をフォアグラウンドサービスに移行させる • アップロード中であることの通知をしっかりさせる •
巨大なアップロードになるのでモバイルネットワーク通信時にアップロードさせない • NetworkInfoのTypeがTYPE_WIFIになっている時以外はブロックする…といった処理も 検討する
フォアグラウンドサービスでアップロードさせる • サービス起動時にフォアグラウンドで通知させることが必要 • Android O + API Level 26から
• Context.startForegroundService() で起動 • サービス起動から5秒以内に Service.startForeground() しないとクラッシュする • RemoteServiceException • アップロードする観点では起動直後に通知させるで良さそう • 処理が終了したら stopSelf(), stopForeground() で止めないと通知が残り続ける • ちゃんと止めよう
サービス起動 fun start(context: Context) { val intent = Intent(context,ForegroundService::class.java) if
(ifVersionLaterThanO()) { // check SDK_INT context.startForegroundService(intent) } else { context.startService(intent) } }
起動直後に通知して処理を実行 override fun onCreate() { super.onCreate() // Ξοϓϩʔυ௨༻ʹnotificationΛ࡞͓ͬͯ͘ startForeground(NOTIFICATION_ID, notification)
uploadItems() { // ΞοϓϩʔυྃͰαʔϏεΛऴྃ͢Δ stopSelf() } }
おわり