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
1
530
大きい画像をたくさんアップロードするために
2018/12/11に開催されたOtemachi.apk #1にて発表した「大きい画像をたくさんアップロードするために」のスライドです。
Yoshihiro WADA
December 11, 2018
Tweet
Share
More Decks by Yoshihiro WADA
See All by Yoshihiro WADA
AndroidデバイスにFTPサーバを建立する
e10dokup
0
390
Gradleの実行環境設定を見直す
e10dokup
0
1k
Firebase App Distributionのテストアプリ配信を試しやすくする
e10dokup
0
620
アプリに署名する 〜GitHub ActionsでのCIも見据えて〜
e10dokup
0
1.2k
Profileable buildでより正確なパフォーマンスを掴む
e10dokup
0
740
[DroidKaigi 2021] メディアアクセス古今東西 / Now and Future of Media Access
e10dokup
0
3.6k
今更「dp」を考える / Let's think about "dp" now
e10dokup
0
5.7k
1から学ぶAndroidアプリデバッグ - アプリの動作を追いかけよう / Learn Android application debugging from the scratch - track apps' behaviors
e10dokup
10
3.2k
Guide to background processingを読んでみる / Reading "Guide to background processing"
e10dokup
0
260
Other Decks in Programming
See All in Programming
XSLTで作るBrainfuck処理系
makki_d
0
190
Spring gRPC で始める gRPC 入門 / Introduction to gRPC with Spring gRPC
mackey0225
2
480
Cursor Meetup Tokyo ゲノミクスとCursor: 進化と制約のあいだ
koido
2
970
Webからモバイルへ Vue.js × Capacitor 活用事例
naokihaba
0
520
生成AIで日々のエラー調査を進めたい
yuyaabo
0
520
コードに語らせよう――自己ドキュメント化が内包する楽しさについて / Let the Code Speak
nrslib
6
1.4k
統一感のある Go コードを生成 AI の力で手にいれる
otakakot
0
2.9k
OpenNext + Hono on Cloudflare でイマドキWeb開発スタックを実現する
rokuosan
0
120
Practical Tips and Tricks for Working with Compose Multiplatform Previews (mDevCamp 2025)
stewemetal
0
120
Elixir で IoT 開発、 Nerves なら簡単にできる!?
pojiro
1
120
#QiitaBash TDDでAIに設計イメージを伝える
ryosukedtomita
2
1.7k
[初登壇@jAZUG]アプリ開発者が気になるGoogleCloud/Azure+wasm/wasi
asaringo
0
120
Featured
See All Featured
The Language of Interfaces
destraynor
158
25k
Optimising Largest Contentful Paint
csswizardry
37
3.3k
Large-scale JavaScript Application Architecture
addyosmani
512
110k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
52
2.8k
Raft: Consensus for Rubyists
vanstee
139
7k
How to Think Like a Performance Engineer
csswizardry
24
1.7k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
248
1.3M
Thoughts on Productivity
jonyablonski
69
4.7k
How GitHub (no longer) Works
holman
314
140k
Building Flexible Design Systems
yeseniaperezcruz
328
39k
Building Adaptive Systems
keathley
43
2.6k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
228
22k
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() } }
おわり