新しいノートブック

Android大好き

umeda_apk #4 メモ

2018/06/07 にCAさんの大阪支社で開催された umeda.apk #4 - Report from Google I/O 2018 に関するメモです

shibuya-apk.connpass.com

What's new in Android @hi6484 / 株式会社メルカリ

Google I/O 2018 で発表された内容の全体像

Android App Bundles

  • Legacy APK
    • リソースはすべて入れる
  • Dynamic Delivery
    • 必要なリソースだけ入れる

Android Jetpack

  • サポートライブラリが変わった
  • Android KTX (Kotlin Extension)
  • etc...

Battery

  • Adaptive Battery

    • 消費電力をアプリの使用状況に合わせて調整する
  • App Standby Buckets

    • 4つの状態がある
      • Active
      • Working set
      • Frequent
      • Rare
    • 制限されるのは
      • Job
      • Alarms
      • High Priority Firebase Cloud Message
      • Network

Background Input & Privacy

  • マイク、カメラ、センサー情報
    • バックグラウンドで使わない!

Location

Security

  • Fingerprint ManagerがDeprecated

↓↓↓

Enterpise

企業向けの機能 (回転寿司にある注文用のタブレットアプリとかああいう向けのやつ)

  • android.content.pm.CrossProfile
    • Profileをスイッチ
  • DevicePolicyManager.setLockTaskPackage()
  • DevicePolicyManager.createAndManagerUser(MAKE_USER_EPHEMERAL)
    • ユーザを作成する

Notification

ユーザがメッセージを受信したときに新しいAPIを追加

  • Inline images/stickers
  • Participant images
  • Smart reply UI
    • RemoteInput.setChoices()

Deprecated Policy

  • 2018/08
    • 新しいアプリはTarget API 26以上
  • 2018/11
    • アプリの更新はTarget API 26以上
  • 2019/09
    • 64bit対応 (32bit Optional)

App Compatibility

privateと@hideのAPIを使わない!

g.co/dev/appcompatへリクエストして、APIに対して3タイプのリストを持っている

  • Blacklist
  • Dark Greylist
  • Light Greylist

Camera

  • タイムスタンプ
  • Stabilization (手ブレ補正)
  • Display Flash
  • USBカメラ
  • マルチカメラ

ImageDecoder

  • Animated Image Drawable (GIFファイルをロードできる)
  • BitmapFactoryは使わずImageDecoderつかってね

Media

  • HDRをサポート

    • HDRビデオ再生できるようにVP9サポート
  • High Effeiciency Image Format(HEIF)

    • HEVC/H.256コーデック
    • .heif とか .heic

Chrome OS

Preview Android Studio on Chomebooks


Android Jetpack @satorufujiwara / 株式会社サイバーエージェント

Android Jetpack とは...

  • 良いアプリを早く簡単につくるための、ライブラリやツールや設計指針
  • Foundation(基本), Archtecture(アプリ設計), Behavior(動作), UI の4つに分類されている
  • Support LibraryやArchtecture Commponentも含まれる

What's new in Android Jetpack

今回更新があったもの

  • WorkManager
  • Navigation
  • Paging
  • Slices
  • Android KTX

WorkManager

  • バックグラウンド処理を行うためのライブラリ
  • 画像のアップロードのような、アプリを終了しても継続したい処理につかう
  • アプリを終了した場合に中断したい処理にはThreadPoolもしくはRxJavaを使う
  • 内部的にはJobScheduler or FirebaseJobDispatcher or AlarmManagerが使われる

WorkManagerの実行例

class UploadPhotoWorker : Worker() {
  override fun doWork() {
    // do in background
    uploadPhoto()
    return WorkerResult.SUCCESS
  }
}

val request = OneTimeWorkerRequestBuilder<UploadPhotoWorker>().build()
WorkManager.getInstance().enqueue(request)

Navigation

  • 単一Activity内のFragmentの画面遷移(Fragment Transaction)を行うフレームワーク
  • 変数(bundle)の受け渡しUp/Backの制御やDeep Linksも定義することができる
  • Android Studio 3.2 から導入されたNavigation Editorを使い編集する
    • Navigation Editor の編集結果はXMLで保存される
  • コードからはNavigationControlleなどを用いて遷移を呼び出す
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
      findViewById<Button>(R.id.next_button).setOnClickListener(
        Navigation.createNavigationOnClickListener(R.id.next)
      )

      findViewById<Button>(R.id.settings_button).setOnClickListener { v ->
        val navController = v.findNavController()
        navController.navigate(R.id.settings)
      }
    }

Paging

  • Archtecture ComponentsのPagingのStableバージョンがでた
  • Recycler Viewに表示しているデータの「続きを読み込む」ライブラリ
  • 読み込み先はネットワーク、データベース、またはその両方

Slices

  • Google検索(今後はGoogleアシスタントなどにも)にアプリのコンテンツを表示するためのUIテンプレート
  • Android 4.4 (API 19) 以降で使える
  • 自身のアプリのエンゲージメントを高めるのにつかう

Andoird KTX

  • AndoirdのAPIをKotlinから扱いやすくするためのKotlinの拡張関数群
  • 既にバージョン0.3.0が公開されていたが、1.0.0-alphaが公開された
  • Android Framework以外のライブラリに対応した拡張関数が多く追加されている

Android KTXの例

// Before
adapterView.setPaging(10, avatarView.paddingTop, 10, adapterView.paddingBottom)

// After (名前付き引数を使い実現している)
adapterView.updatePadding(left = 10, right = 10)

BTW: Kotlinについて

  • Kotlinを使ったPlaySotre上のアプリは昨年比で6倍
  • ディベロッパーの35%がKotlinを使っており、毎月増加している
  • Android DevelopersのドキュメントもKotlin対応版が提供されるようになった

googlesamples/android-sunflower

Android Jetpackをふんだんに使ったサンプル(ベストプラクティス?)

AndroidX

サポートライブラリの名前が分かりづらかった問題(v4とかv7とか...) → AndroidXという名前でリファクタリング

  • 新しいAndroidのバージョンではありません
  • Support Libraryなどのパッケージをリファクタリングしたもの
  • OSにバンドルされないAndroidの拡張ライブラリ
  • JetpackにはAndroidXに含まれるものもあるし、含まれないものもある

AndroidXのリファクタリング

  • パッケージをリファクタリング
    • com.android.support.**androidx.**
    • android.databinding.**androidx.databinding.**
    • android.arch.**androidx.arch.core.**
  • v4やv7などの表記が消える
  • バージョンが28.0.0から1.0.0にリセットされる
  • 管理も厳密に (メジャーバージョンが同じなら互換性あり)

AndroidXへの移行

  • Android Studioリファクタリングツールが提供される
    • 上部メニュー > Refactor > Refactor to AndroidX...
  • 使っているライブラリのJAR/AARを変換するJetifierというツールも提供される

One more thing

一番盛り上がってたやつ

MotionLayout

  • ConstraintLayout 2.2から導入されるConstraintLayoutのサブクラス
  • Viewの状態(ConstraintSet)間をアニメーションを使って動かすことができる
  • What's new with ConstraintLayout and Android Studio design tools
  • Motion Editorでアニメーションを編集することができる

Dynamic Feature @punchdrunker / 株式会社ミクシィ

Android App Bundleの目玉機能の一つである、Dynamic Feature Modulesについてのお話。

Android App Bundle概要

アプリをいままでよりスマートに配信する事が出来る機能群の総称

  • Multi APKの代替 (何らかの理由で端末別にapkを用意できる仕組み)
  • APKサイズの最適化 (aab)
  • 必要になった時に追加でモジュールをインストールできる
    • Dynamic Feature Moduleとしてベータ公開中
  • アプリをインストールしていなくてもモジュール単位で利用可能になる
    • instant enableとして近日公開予定

(Android Studio 3.2 RC14以降でしか使えない)

Dynamic Feature Module?

アプリのインストール後に、必要になった時に機能やリソースを事後的にインストール(Dynamic Delivery)することができる仕組みのこと。

一部の端末やユーザ向けのものはアプリインストール後に必要になったときにインストールすることで、その機能が必要の無いユーザに対してはストレージ容量を抑えられる。

また回線速度に依存するが、モジュールのインストールには数秒以上かかると思ったほうがよい。

必要なくなったらuninstallすることもできる。

Dynamic Feature Moduleの使い道

  • 有料コンテンツやプレミアム機能
    • 有料登録時にインストールできればよい
  • ゲームのステージ情報
    • ステージが進んだ時にインストールすればよい
  • とにかく大きな画像などのリソースをたまに使う
    • 必要だとわかったらインストールすればよい
  • 利用者が少なく、ある程度分離された機能
    • 他サービスとの連携する機能など

(あくまで妄想)

どんな対応が必要か

  • play coreライブラリを使用
    • com.google.android.play.core.splitinstall.*
  • SplitInstallManagerを使って、利用可能なモジュールの確認やインストールを行う
    • 確認: SplitInstallManager.getInstalledModules()
    • 追加: SplitInstallManager.startInstall(module)
    • 削除: SplitInstallManager.defferedUnsintall(modules)
  • インストール完了したら(SplitInstallStateUpdatedListener)を使うだけ
    • パッケージ名を指定して、startActivity()やcreatePackageContext()するだけ

デモ

  1. 設定アプリでhochoアプリのストレージ使用量を確認
  2. hochoアプリを起動
  3. メニューからDynamic Feature Moduleを選択
  4. 写真一覧が表示されるまで待機
  5. 写真一覧が表示されたら再度設定アプリでhochoのストレージ使用量を確認

サンプルアプリ: インストールURL → hocho - Google Play

ハマりどころ(1)

  • Modules 'base' and 'gallery' contain entry 'res/layout/activity_main.xml' with different content.
    • 別モジュールでも同じリソース名は不可
  • オンデマンドモジュールのタイトルはリソースIDには、ベースモジュールで定義された文字列を指定する必要があります。無効なモジュールは「gallery」です
    • ベースとなるアプリ側でリソースIDを定義しておく必要がある(feature_names.xml)
  • implementationで利用するライブラリを定義すると、dynamic feature module側から使えない
    • apiでロードするようにしたら使えた

ハマりどころ(2)

  • ベータ機能なので、申請フォームに記入が必要
    • 半日くらい待つと使えるようになっていた
  • aabリリースしたらminSdkVersion21なのに、hdpi端末でベクターがぼやけた(伝聞)
    • VectorDrawableCompatのissueが上がっているので、そのうち直りそう

Work Manager @takahirom / 株式会社AbemaTV

Workmanagerとは

Android Jetpack - Architectureの中の1つ Google I/O 2018 で発表

Deferrable guaranteed execution (延期保証実行)

  • ツイートの送信
  • ログ送信
  • データ同期
  • メディアファイルのサーバへのアップロード

Deferrable guaranteed execution の何が問題か

  • タイミングが後になってもよく、動作が保証したい場合たくさんの解決方法がある
    • JobScheduler, FirebaseJobDespatcher, AlarmManager + BroadCastReceivers
  • たくさんのことを考慮しながら、たくさんのAPIの呼び出しを書く必要がある
    • APILevel?, FirebaseJobDespatcher? ...
    • これにWorkManagerが対応する

どんなタスクにWorkManagerを使うべきか?

  • システムがアプリを終了したとしても、動作保証したいタスクのために使う
  • アプリのプロセスが終了しても、安全に終了できるタスクのためには利用しない

    • それは、ThreadPoolかRxJavaかCoroutineを使うべき
  • 出典: Guide to background processing

例えばどんなタスク

  • ○: ツイート
  • ○: メディアファイルのサーバへのアップロード
  • ○: データのパースとデータベースへの保存

  • ×: パレットカラーを抽出してImageViewをアップデート (※1)

  • ×: データをパースしてViewをアップデート (※1)
  • ×: 課金のトランザクションを実行 (※2)

(※1): ThreadPool, RxJava, Kotlin Coroutine を使う
(※2): Foreground Service を使う

WorkManagerの使い方

// 必須
implementation "android.arch.work:work-runtime:1.0.0-alpha02"

// Firebase JobDispatcherを使う場合必要
implementation "android.arch.work:work-firebase:1.0.0-alpha02"

// Kotlinを使う場合、あったほうが簡潔に書ける
implementation "android.arch.work:work-runtime-ktx:1.0.0-alpha02"

// テストを書ける
androidTestImplementation "android.arch.work:work-testing:1.0.0-alpha02"

WorkManagerの中心となるクラス

  • Work: 作業をするクラス。実際にやりたいことを継承して記述する
  • WorkRequest: Workのリクエストクラス
    • OneTimeWorkRequest: 一度きりのWorkを実行する場合のRequest
    • PeriodicWorkRequest: 繰り返しWorkを実行する場合のRequest

Workerを使ってみる

コードなので省略

WorkManagerの機能紹介

  • Workの依存グラフが作れる
    • then()でWorkを繋げられる
    • RxJavaのzipみたいなことができる
      • InputMergerを使う
    • Workに条件をつけられる
    • LiveDataで今の状態が見られる
      • Workにタグをつけて絞り込みなどができる
      • チェイン開始時にユニークな名前をつけて絞り込みや、同じ名前が流れたときの制御ができる

then()でWorkを繋げられる

  • 写真にフィルターをかけた後アップロードしたいときなどに利用する
  • 今回は World -> Hello, World -> HELLO, WORLD をやってみた
WorkManager.getInstance()
    .beginWith(OneTimeWorkRequestBuilder<AddHelloWorker>()
      .setInputData(mapOf(KEY to "World").toWorkData())
      .buiild()
    )
    // ここ
    .then(OneTimeWorkRequestBuilder<UpperCaseWorker>().build())
    .enqueue()

Workに条件をつけられる

  • ネットワークに繋がっている時のみ、充電時のみ実行などの条件がつけられる
    • setConstraintsで設定してあげる
val workRequest = OneTimeWorkRequestBuilder<AddHelloWorker>()
    .setInputData(mapOf(KEY to "World").toWorkData())
    // 充電がはじまると、実行される
    .setConstranits(Constraints.Builder().setRequiresCharging(true).build())
    .build()

Workにタグをつけて絞り込みなどができる

  • 好きにネームスペースが作れる
    • addTag()でタグ追加
    • getStateusesByTag()で絞り込み
    • 他にもタグ単位でキャンセルしたりできる
val taggedRequest = OneTimeWorkerRequestBuilder<AddHelloWorker>()
    .setInputData(mapOf(KEY to "WorkManager").toWorkData())
    // タグ追加
    .addTag("tag")
    .build()
WorkManager.getInstance().enqueue(taggedRequest)

WorkManager.getInstance()
    // getStatusesByTag()で絞り込み
    .getStatusesByTag("tag")
    .observe(this, Observer<List<WorkStatus>> { workStatuses ->
      val workStatus = workStatuses?.getOrNull(0) ?: return@observer
      when (workStatus.state) {
        State.SUCCEEDED -> {
          ...
        }
      }
    })

チェイン開始時にユニークな名前をつけて絞り込みや、制御ができる

  • beginUniqueWorkを使う
  • ExistingWorkPolicy は同じ名前でWorkを始めたときのポリシー
    • KEEP: 先に始めたWorkだけ実行
    • REPLACE: 先に初めたWorkをキャンセルして削除、新しいWorkを開始
    • APPEND: 先に始めたWorkの後に、両方行う
val workRequest = OneTimeWorkRequestBuilder<AddHelloWorker>()
    .setInputData(mapOf(KEY to "World").toWorkData())
    .build()
WorkManager.getInstance()
  .beginUniqueWork("Hello", ExistingWorkPolicy.KEEP, workRequest)
  .enqueue()

Inside WorkManager

WorkManagerの内部実装の基本

DBに情報を入れてから、①まずExecutorで実行する。その間にプロセスが止まっても良いように②JobSchedulerなどからExecutorを実行する

  • ① Executor
  • API 23+?
    • YES: JobScheduler
      • Executor
    • NO: App include Firebase JobDispatcher?
      • YES: Firebase JobDispatcher
        • Executor
      • NO: AlarmManager + Broadcast Receivers
        • Executor

WorkManagerの依存関係

  • Roomに依存している
    • DBの中をStethoで確認できる
      • androidx.work.workdbにWorkerが登録されている

WorkManagerのテスト

TestDriver()を使って同期的に動かしてテストできる

@Test
func test() {
  val testDriver = WorkManagerTestInitHelper.getTestDriver()
  val workRequest = OneTimeWorkRequestBuilder<AddHelloWorker>()
      .setInputData(mapOf(KEY to "World").toWorkData())
      .build()

  WorkManager.getInstance().enqueue()
  testDriver.setAllConstraintsMet(workRequest.id)

  val outputData = WorkManager.getInstance()
      .synchronous()
      .getStatusByIdSync(workRequest.id)
      .outputData
  
  assertThat(outputData.getString(KEY, "none"), equalTo("Hello World"))
}

WorkManagerのサンプル実装

Android Sunflower (alpha) 内にあるWorkManager

Android Sunflower (alpha) は、Android JetpackAndroid開発のベストプラクティスを示すガーデニングアプリ。

Workerの中でのDIは?

  • Redditに質問が上がっていた
    • 乞うご期待

ベストプラクティス

  • システムがアプリが終了したとしても、動作保証したタスクのために使う
  • DataクラスはデータストアではないのでちゃんとRoomなどを使う
  • 実行できる機会をうかがうようにConstraintで条件を書こう

    例えば画像の書こうとアップロードをするときに、アップロードのWorkにネットワークが必要だとしておけば、飛行機に乗っている間に画像の加工までは終わって、繋がったらアップロードしてくれるなどができる

まとめ

  • システムがアプリが終了したとしても、動作保証したいタスクのために使う
  • OSの依存、使うべき仕組みの切り替えなど、とても楽になる。ボイラープレートがなくなる
  • Workに制約をつけれる、繋げられる、タグがつけられる、名前がつけられる、状態をLiveDataで取得できる
  • 使いみちは多いので、使ってみると良さそう

Android Studio 2.3にアップデートするとandoird-aptがエラーを吐く対応

Gradle2.2より、アノテーションプロセッサがサポートが組み込まれています。 これによって、Gradle2.3よりandroid-aptプラグインのサポートが公式に廃止されています。

build.gradle

android-aptプラグインを削除します。

dependencies {
  classpath 'com.android.tools.build:gradle:2.3.0'
//  classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
  classpath 'me.tatarka:gradle-retrolambda:3.2.5'
}

app/build.gradle

android-aptに依存するライブラリを使用していた場合は、依存設定も変更する必要があります。 annotationProcessor構文を使用するには、必ず最新のGradleバージョンにアップデートしてください。

dagger2の設定

// apply plugin: 'com.neenbedankt.android-apt'
...
dependencies {
  compile "com.google.dagger:dagger:2.9"
  annotationProcessor "com.google.dagger:dagger-compiler:2.9"
  provided 'javax.annotation:jsr250-api:1.0'
}

参考URL

Raspberry Pi3にsambaを導入

sambaの導入

sudo apt-get update
sudo apt-get install samba

設定ファイルの変更

設定ファイルは/etc/samba/smb.confになります。まずはバックアップしておく。

sudo cp -p /etc/samba/smb.conf /etc/smb.conf.orig

共有ディレクトリを追加。ファイル下部に設定を追記していく。

ログインしたユーザがpathに対しての書き込み権限が無い場合、ファイルの書き込みが出来ないので注意。force userが設定されている場合は、ログイン・ゲストにかかわらずforce userの権限による。

sudo vim /etc/samba/smb.conf

# 設定例
[share] # ディレクトリの表示名
   comment = Network Logon Service # ディレクトリ説明欄に表示される文章
   path = /mnt/hdd1/storage # 実際に参照されるディレクトリパス
   guest ok = yes # ゲストユーザを許可
   writable = yes # 書き込み許可
   force user = pi # ファイル作成時のオーナー

sambaを再起動

sudo service smbd restart
sudo service nmbd restart

自動起動の設定

sudo update-rc.d samba defaults

Macからアクセス

cmd + KもしくはFinderメニューの表示 > サーバへ接続...を選択。 サーバアドレスにsmb://IPアドレスと入力します。

Windowsからアクセス

エクスプローラのアドレス欄に¥¥IPアドレスと入力します。

参考URL

Raspberry Pi3で外付けHDDをマウントする

RaspberryでNASを構築するため、外付けHDDをマウントします。 今回はこちらのHDDを使用しました。
I-O DATA HDD 外付けハードディスク 4TB USB3.0

HDDの接続

外付けHDDをUSB接続し認識されているか確認。

# ディスクをリスト表示
sudo fdisk -l | grep /dev/sda

/dev/sda1      34     262177     262144  128M Microsoft reserved
/dev/sda2  264192 7814036063 7813771872  3.7T Microsoft basic data

USB給電タイプの場合、Raspberryからの供給電力に制限があり、必要電力に足りなくなる場合があるので注意が必要です。 Raspberry側のconfigを弄ることで供給電力の変更もできますが、設定次第で動作が不安定になることもあるので、ここらへんは購入前に調査しておく必要があります。

HDDをフォーマット

パーティションファイルシステムの設定を行います。

# パーティションテーブルの設定を行います
sudo fdisk /dev/sda

# d でパーティションを削除
Command (m for help): d
Selected partition 1
Partition 1 has been deleted.

# p で現在の状態を確認
Command (m for help): p
Disk /dev/sda: 3.7 TiB, 4000787030016 bytes, 7814037168 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: gpt
Disk identifier: F3BA4D9C-C2F7-43FF-837C-D3BFBFBF5C1D

# n でパーティションを作成 その後の設定で何も入力しない場合全てデフォルトとなる
Command (m for help): n
Partition number (1-128, default 1):
First sector (34-7814037134, default 2048):
Last sector, +sectors or +size{K,M,G,T,P} (2048-7814037134, default 7814037134):

Created a new partition 1 of type 'Linux filesystem' and of size 3.7 TiB.

# p でもう一度確認 パーティションが追加されています
Command (m for help): p
Disk /dev/sda: 3.7 TiB, 4000787030016 bytes, 7814037168 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: gpt
Disk identifier: F3BA4D9C-C2F7-43FF-837C-D3BFBFBF5C1D

Device     Start        End    Sectors  Size Type
/dev/sda1   2048 7814037134 7814035087  3.7T Linux filesystem


# w で変更を書き込みます
Command (m for help): w
The partition table has been altered!
Calling ioctl() to re-read partition table.
Syncing disks.

ext4でフォーマットする

ext4でフォーマットするとLinuxシステムでの読み込みがNTFSより早くなります。その代わりWindowsで認識できなくなります。

sudo mkfs.ext4 /dev/sda1

Creating filesystem with 976754385 4k blocks and 244195328 inodes
Filesystem UUID: fa16b72b-a2d0-4331-9693-e417727f3b53
Superblock backups stored on blocks:
    32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
    4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968,
    102400000, 214990848, 512000000, 550731776, 644972544

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done   

マウントする

/etc/fstabにデバイスを登録することにより、起動時に自動マウントすることができます。 またデバイスのパスではなくUUIDを登録しておくことにより、デバイスのパスが変更されてもマウントすることが可能です。

マウントポイントを作成

必要に応じてマウントポイントを作成します。今回は/mnt/hdd1としました。

sudo mkdir /mnt/hdd1

UUIDを調べる

# ブロックデバイスの情報を表示する
sudo blkid /dev/sda1
/dev/sda1: UUID="fbab8a4f-3211-4b03-b53a-1579c93054aa" TYPE="ext4"

fstabを編集

fstabでの設定が正しくない場合、再起動時にemergency modeで起動されます。 ハマるとずっと起動できないといったことになるので、必ずバックアップをとっておく。 また、オプションにnofailを指定することで、エラーの設定項目を無視して起動してくれる。

# バックアップをとっておく
cd /etc
sudo cp fstab fstab.bak

# fstabを編集しマウント設定を追加
sudo vim fstab
# デバイス名 マウントポイント ファイルシステム オプション dump指定 fsck指定
UUID=fbab8a4f-3211-4b03-b53a-1579c93054aa /mnt/hdd1 ext4 nofail 0 0

# 再起動
sudo reboot

確認

マウントされていることを確認します。

df | grep /mnt/hdd1
/dev/sda1       3845578572   69632 3650141680    1% /mnt/hdd1

参考URL

RxJava私的メモ

Observableの生成

・from
IterableなオブジェクトからObservableを生成。

Observable.from(T[] array)  
Observable.from(Iterable<? extends T> iterable)  
Observable.from(new String[]{"a", "b", "c"})  

・create
OnSubscribeを指定してObservableを生成。

Observable<String> o = Observable.create(subscriber -> {
            subscriber.onNext("Hello");
            subscriber.onNext("world!");
            subscriber.onCompleted();
        });

・range
要素の範囲を指定してObservableを生成。

Observable<Integer> o = Observable.range(1, 5);  

・just
引数で直接Observableを生成

Observable<Integer> o = Observable.just(1, 2, 3);  

subscribeOnとobserveOn

・subscribeOn
ObservableのonSubscribe を実行するスレッドを変更する。
subscribeOnはどのタイミングで呼んでも全てのオペレータに適用される。

・observeOn
以降のオペレータでのコールバックを処理するスケジューラをきめる。

・指定しない場合
Observableの実装や叩いたOperator(map()やfilter()などのメソッド)によりますが、基本的に現在のスレッド(subscribe()を呼び出したスレッド)で「同期的に」実行されます。

Schedulers

指定したオペレータをどのスレッドで実行するかを指定できます。
最初はSchedulers#newThreadとAndroidSchedulers#mainThreadから入ると良いと思います。

・#io
I/O処理のためのScheduler。

・#computation
計算処理のためのScheduler。イベントループ 処理コールバックなど。

・#immediate
現在のスレッドで作業するためのScheduler。処理を割り込んで実行させます。

・#newThread
新規にスレッドを生成します。

・#trampoline
擬似的なマルチタスクとして実行します。

・AndroidSchedulers#mainThread()
メイン(UI)スレッドで実行します。 (RxAndroidを導入する必要あり)

ライフサイクル

意識しないといけないのはsubscribeメソッドが発行するSubscription。

・ライフサイクルに合わせてunsubscribeする
SubscriberのonNext, onErrorでunsubscribeが呼ばれる。
非同期のSubscriptionは投げっぱなしにするとリークするので適所でunsubscribe!

・複数のSubscription
CompositeSubscriptionを利用します。Subscriptionが発行される都度CompositeSubscription#addする。
こちらもライフサイクルに合わせてunsubscribeする。

error operators

通常はsubscribe内でonErrorを実装する. subscribe内がonNextだけの実装になっている場合は,
下記のメソッドを実装する必要がある.
・onErrorReturn
Observableチェインのなかで発生したErrorをキャッチして、大体のObjectに変換することでsubscriberにErrorが渡されるのを防ぐことができます。

・onErrorResumeNext
Observableチェインのなかで発生したErrorをキャッチして、その中で再度Observableを呼び出すことで、エラー時に代替のStreamを返すことができます。

ハマりどころ

onErrorにコンテキストの参照をもたせるとリークする

既存処理をRxに移行する

// 非同期処理に乗せるAPIからのデータ取得メソッド
public List getDataFromApi() {…}

// 戻り値の型をObservableでラップ
public Observable<List> getDataFromApi() {…}

参考URL

RxJava Javadoc 2.0.7

Raspberry Pi3で固定IPを設定する

ローカルIPを固定する

Linuxのネットワーク設定は通常下記に記載されているかと思います。 /etc/network/interfaces

とりあえず開いてみると…

# Please note that this file is written to be used with dhcpcd
# For static IP, consult /etc/dhcpcd.conf and ‘man dhcpcd.conf’

上の方になにやらコメントが書いてあり、 固定IP設定するならdhcpd.confを編集しろだそうです。

一番下の下記を記入(数値は適当に置き換えてください)

$ sudo vi /etc/dhcpcd.conf  
interface eth0  
static ip_address=192.168.11.10  
static routers=192.168.11.1  
static domain_name_server=192.168.11.1  

SSHのポートを設定

デフォルトは22に設定されています

$ sudo vi /etc/ssh/sshd_config

Port 22
49152 ~ 65535の間で任意のポート番号を指定します

ssh の再起動

$ sudo /etc/init.d/ssh restart

接続

Terminalから下記を叩きます

$ssh pi@IPアドレス -p ポート番号

リフレクションで生成した文字列に何かの参照の跡のようなものがぶちこまれてる件

リフレクションでモデルクラスから直接GETリクエストを作っちゃうようなケース。
お尻に全然知らないパラメータがくっついてました。

原因

同じ症状にぶち当たってる人を発見した。
http://stackoverflow.com/questions/34647546/a-weird-field-appear-in-android-studio どうやらAndroid Studio 2.0でInstrant Runをサポートするための参照が追加されてるようだ。

備考

Class<? extends Object> clazz = obj.getClass();
clazz.getDeclaredFields();

上記の配列をデバッガで確認すると、

public static transient volatile com.android.tools.fd.runtime.IncrementalChange.{…}.hoge.$change

という参照が確認出来る。

対策

File > Settings > Build, Execution, Deployment > Instant Run
Enable Instant Run to hot swap code/resource change on deploy(default enabled)
チェックを外す

もしくはUSBを抜く。繋いでる時だけ発生するので最初はわけ分からなかった。

リフレクションのご利用は計画的に。