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
580
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.5k
Gradleの実行環境設定を見直す
e10dokup
0
1.3k
Firebase App Distributionのテストアプリ配信を試しやすくする
e10dokup
1
740
アプリに署名する 〜GitHub ActionsでのCIも見据えて〜
e10dokup
0
1.4k
Profileable buildでより正確なパフォーマンスを掴む
e10dokup
0
810
[DroidKaigi 2021] メディアアクセス古今東西 / Now and Future of Media Access
e10dokup
0
4k
今更「dp」を考える / Let's think about "dp" now
e10dokup
0
6k
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 Engineeringは、AIプロダクトだけのものか? 〜AIがソフトウェアを作る時代の新しい当たり前〜 / No AI in your product. AI Engineering in your development.
rkaga
4
380
「寝てても仕事が進む」Claude Codeで組む第二の脳
tomoyafujita2016
0
310
メールのエイリアス機能を履き違えない
isshinfunada
0
230
全PRの83%がAIレビューだけでマージできるようになった開発組織はその後どうなったか
athug
1
1.5k
そこに3びきプロダクトがいるじゃろう——生成AI時代における“価値が届かない理由”の構造
kosuket
0
440
ITヒヤリハットを整理してみた ~ライフサイクルと原因から考える再発防止策~
koukimiura
1
140
Japan Community Day at Kubecon + CloudNativeCon Japan 2026: Learning Container Privilege Control by Building My Own Low-Level Container Runtime
ternbusty
1
150
これって Effect でできたのでは? / TSKaigi Mashup Kansai #2
susisu
0
150
Laravel Boostに学ぶ、AIにPHPを書かせる技術 〜OSSの実装から蒸留するエージェント制御の王道〜
kentaroutakeda
3
670
仕様書を書く前にハーネスを作る - Agent Native開発は「探索を速く、判定を固く」
gotalab555
4
1.6k
AI時代のPHPer生存戦略 ~「言語、もうなんでもよくない?」に本気で向き合う~
vivion
0
300
わからない話を追いかけたら、プログラミング言語を作る側にいた
ydah
3
480
Featured
See All Featured
The Illustrated Children's Guide to Kubernetes
chrisshort
51
53k
It's Worth the Effort
3n
188
29k
Why Your Marketing Sucks and What You Can Do About It - Sophie Logan
marketingsoph
0
360
The untapped power of vector embeddings
frankvandijk
2
1.8k
Git: the NoSQL Database
bkeepers
PRO
432
67k
Exploring anti-patterns in Rails
aemeredith
3
460
Large-scale JavaScript Application Architecture
addyosmani
515
110k
Information Architects: The Missing Link in Design Systems
soysaucechin
0
1.1k
What Being in a Rock Band Can Teach Us About Real World SEO
427marketing
0
1.1k
How to build an LLM SEO readiness audit: a practical framework
nmsamuel
1
850
How to Grow Your eCommerce with AI & Automation
katarinadahlin
PRO
1
230
GraphQLの誤解/rethinking-graphql
sonatard
75
12k
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() } }
おわり