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
560
1
Share
大きい画像をたくさんアップロードするために
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.1k
Gradleの実行環境設定を見直す
e10dokup
0
1.3k
Firebase App Distributionのテストアプリ配信を試しやすくする
e10dokup
1
720
アプリに署名する 〜GitHub ActionsでのCIも見据えて〜
e10dokup
0
1.3k
Profileable buildでより正確なパフォーマンスを掴む
e10dokup
0
780
[DroidKaigi 2021] メディアアクセス古今東西 / Now and Future of Media Access
e10dokup
0
3.9k
今更「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.6k
Guide to background processingを読んでみる / Reading "Guide to background processing"
e10dokup
0
300
Other Decks in Programming
See All in Programming
[PHPerKaigi 2026]PHPerKaigi2025の企画CodeGolfが最高すぎて社内で内製して半年運営して得た内製と運営の知見
ikezoemakoto
0
320
Goの型安全性で実現する複数プロダクトの権限管理
ishikawa_pro
2
1.4k
Radical Imagining - LIFT 2025-2027 Policy Agenda
lift1998
0
230
Rethinking API Platform Filters
vinceamstoutz
0
8.6k
Migration to Signals, Signal Forms, Resource API, and NgRx Signal Store @Angular Days 03/2026 Munich
manfredsteyer
PRO
0
230
Xdebug と IDE による デバッグ実行の仕組みを見る / Exploring-How-Debugging-Works-with-Xdebug-and-an-IDE
shin1x1
0
340
The Monolith Strikes Back: Why AI Agents ❤️ Rails Monoliths
serradura
0
150
Everything Claude Code OSS詳細 — 5層構造の中身と導入方法
targe
0
160
モックわからないマン卒業記 ~振る舞いを起点に見直した、フロントエンドテストにおけるモックの使いどころ~
tasukuwatanabe
3
440
forteeの改修から振り返るPHPerKaigi 2026
muno92
PRO
3
220
夢の無限スパゲッティ製造機 -実装篇- #phpstudy
o0h
PRO
0
190
Coding as Prompting Since 2025
ragingwind
0
710
Featured
See All Featured
Joys of Absence: A Defence of Solitary Play
codingconduct
1
330
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
510
Designing for humans not robots
tammielis
254
26k
The Power of CSS Pseudo Elements
geoffreycrofte
82
6.2k
Digital Ethics as a Driver of Design Innovation
axbom
PRO
1
250
The Language of Interfaces
destraynor
162
26k
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
210
Bootstrapping a Software Product
garrettdimon
PRO
307
120k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
162
16k
Un-Boring Meetings
codingconduct
0
250
The Curse of the Amulet
leimatthew05
1
11k
Getting science done with accelerated Python computing platforms
jacobtomlinson
2
160
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() } }
おわり