ルーターの設定画面が開けないのだが

ルータの設定を変更しようと思い、

OSネットワークの設定で、

ルーターのIPアドレスを見て、

ネットワーク 設定 デフォルトゲートウェイ

ブラウザのURLバーに入力して、

設定画面にアクセス!

設定画面にアクセスできない

なんでや。

Buffalo の Wi-Fiルーターなんだが、

なんでや。

 

スマホアプリで確認

スマホアプリを入れたら、 IPアドレスが分かります。

StationRadar


192.168.150.33

👉 StationRadar - Google Play のアプリ 

このIPアドレスでアクセスするといける。

ブリッジモード

どうやら「ブリッジモード」のようです。

設定で自動に

「ルーター」でなく「ブリッジ」に

なっていたようです。

 

パソコンだけで確認できないのか。

いちいちアプリを入れるのだるいです。

mac で MAC を調べます。


~ % get-oui -v
Renaming ieee-oui.txt to ieee-oui.txt.bak
Fetching OUI data from http://standards-oui.ieee.org/oui/oui.txt
Fetched 5029216 bytes
Opening output file ieee-oui.txt
31329 OUI entries written to file ieee-oui.txt

~ % sudo arp-scan -l
Password:
Interface: en1, type: EN10MB, MAC: f8:ff:c1:3a:12:ee, IPv4: 192.168.150.30
Starting arp-scan 1.9.7 with 256 hosts (https://github.com/royhills/arp-scan)
192.168.150.1	98:2c:ba:40:78:c2	Fibergate Inc.
192.168.150.5	ec:12:80:22:1b:c0	D-Link International
192.168.150.33	84:1f:ec:9c:26:08	BUFFALO.INC
192.168.150.34	14:12:a3:91:2e:e0	Motorola Mobility LLC, a Lenovo Company
192.168.150.42	d0:17:82:f3:68:2a	AzureWave Technology Inc.
192.168.150.220	01:d0:41:d6:1f:51	AMIGO TECHNOLOGY CO., LTD.
192.168.150.52	8c:45:30:14:80:21	Murata Manufacturing Co., Ltd.

BUFFALO は、


192.168.150.33

 

🧑🏻‍💻 参考

👉 【macOS】ルーターの注意喚起が出たら arp-scan がいいよ hatena-bookmark

👉 端末IPアドレス取得 

👉 ブリッジ設定にする必要はありますか/どのような場合にルーター機能を停止させますか | バッファロー 

👉 【謎?】QRコードによるデバイスのペア設定 - Android11 


【Flow】 shareIn() と stateIn()

意訳。

Flow.shareIn()

Flow.shareIn
コールドフローを、指定されたコルーチンスコープで開始されるホットな SharedFlow に変換し、上流側フローの単一の実行インスタンスからの emit を複数の下流側サブスクライバと共有し、指定された数の replay 値を新しいサブスクライバに再生します。SharedFlow の一般的な概念についてはドキュメントを参照してください。

共有コルーチンの開始は、started パラメータで制御され、以下のオプションがサポートされています。

- Eagerly
最初のサブスクライバが現れる前から上流のフローが開始されます。この場合、replay パラメータで指定された最新の値を超えて上流から emit された全ての値は直ちに破棄されますのでご注意下さい。

- Lazily
最初のサブスクライバが現れた後に上流のフローを開始します。この場合、最初のサブスクライバが emit されたすべての値を取得することが保証されますが、後続のサブスクライバは最新の replay 値のみを取得することが保証されます。すべてのサブスクライバがいなくなっても、上流のフローは継続してアクティブですが、サブスクライバがいない場合は、最新の replay 値のみがキャッシュされます。

- WhileSubscribed()
最初のサブスクライバが現れたときに上流のフローを開始し、最後のサブスクライバが消えたときに即座に停止し、リプレイ・キャッシュを永遠に維持します。WhileSubscribed() には、ドキュメントで説明されているように、追加のオプション設定パラメータがあります。

- SharingStarted
インターフェースを実装することで、カスタムストラテジーを提供することができます。

shareIn オペレータは、作成や維持にコストがかかるコールドフローがあり、その値を収集する複数のサブスクライバがある場合に便利です。

例えば、バックエンドから高コストなネットワーク接続を介してメッセージが送られてきて、その確立に多くの時間を要するフローを考えてみましょう。

概念的には次のように実装されます。


val backendMessages: Flow<Message> = flow {
  connectToBackend() // takes a lot of time
  try {
    while (true) {
      emit(receiveMessageFromBackend())
    }
  } finally {
    disconnectFromBackend()
  }
}

このフローをアプリケーションで直接使用する場合は、収集するたびに新しい接続が確立されるため、メッセージが流れ始めるまでに時間がかかります。しかし、次のように1つのコネクションを共有して、それを確立することができます。


val messages: SharedFlow<Message> = backendMessages.shareIn(scope, SharingStarted.Eagerly)

これで messages から1つのコネクションがすべてのコレクター間で共有され,必要なときにはコネクションを確立しておくことができます。

* 上流の完了とエラー処理

上流側フローの通常の完了は、サブスクライバには影響を与えず、共有コルーチンは継続して実行されます。SharingStarted.WhileSubscribed が使用されている場合は、上流側が再び再開されます。それの完了時に特別なアクションが必要な場合は、shareIn オペレータの前に onCompletion オペレータを使用して、以下のように特別な値を emit することができます。


backendMessages
  .onCompletion { cause -> if (cause == null) emit(UpstreamHasCompletedMessage) }
  .shareIn(scope, SharingStarted.Eagerly)

上流のフローで例外が発生した場合、どのサブスクライバにも影響を与えることなく共有コルーチンが終了し、それが起動したスコープで処理されます。shareIn オペレータの前に catch や retry オペレータを使用することで、カスタムの例外処理を設定することができます。例えば,IOException が発生したときに1秒の遅延で接続を再試行するには,次のようにします.


val messages = backendMessages
  .retry { e ->
    val shallRetry = e is IOException // 他の例外はバグ
    if (shallRetry) delay(1000)
    shallRetry
  }
  .shareIn(scope, SharingStarted.Eagerly)

* 初期値

上流がまだデータをロード中であることをサブスクライバに知らせるために、特別な初期値が必要な場合は、上流のフローに onStart オペレータを使用します。以下のようになります。


backendMessages
  .onStart { emit(UpstreamIsStartingMessage) }
  .shareIn(scope, SharingStarted.Eagerly, 1) // 最新のメッセージを1つ再生する

* buffer と conflate

shareIn オペレータは、別のコルーチンで上流のフローを実行し、buffer オペレータの説明にあるように、replay サイズまたはデフォルト (大きい方) のバッファを使用して、上流からの emit をバッファリングします。このデフォルトのバッファリングは,shareIn コールの前に buffer または conflate を付けることで,明示的なバッファ設定で上書きすることができます。

- buffer(0).shareIn(scope, started, 0) は、デフォルトのバッファサイズを上書きし、バッファのない SharedFlow を作成します。実際には、上流のエミッタとサブスクライバの間で順次処理が行われ、すべてのサブスクライバが値を処理するまでエミッタが停止するように設定されます。なお、サブスクライバがいない場合でも、値は直ちに破棄されます。

- buffer(b).shareIn(scope, started, r), replay = r, extraBufferCapacity = b の SharedFlow を作成します。

- conflate().shareIn(scope, started, r) が作成されます。

Flow.stateIn()

Flow.stateIn
コールドフローを、与えられたコルーチンスコープで開始される ホットな StateFlow に変換し、上流のフローの単一の実行インスタンスから最も新しく emit された値を複数の下流のサブスクライバと共有します。StateFlow の一般的な概念についてはドキュメントを参照してください。

共有コルーチンの開始は、shareIn オペレータのドキュメントで説明されているように、started パラメータによって制御されます。

stateIn オペレータは、ある状態の値の更新を提供するコールドフローがあり、作成や維持にコストがかかるが、最新の状態の値を収集する必要がある複数のサブスクライバがいる場合に便利です。例えば、バックエンドから高価なネットワーク接続を介して状態の更新が行われ、その確立に多くの時間がかかるフローを考えてみましょう。概念的には次のように実装されます。


val backendState: Flow<State> = flow {
  connectToBackend() // takes a lot of time
  try {
    while (true) {
      emit(receiveStateUpdateFromBackend())
    }
  } finally {
    disconnectFromBackend()
  }
}

このフローをアプリケーションで直接使用する場合、フローが収集されるたびに新しい接続が確立されるため、状態の更新が流れ始めるまでにしばらく時間がかかります。しかし、次のように1つのコネクションを共有し、それを熱心に確立することができます。


val state: StateFlow<State> = backendMessages.stateIn(scope, SharingStarted.Eagerly, State.LOADING)

これで、state から全てのコレクターの間で1つのコネクションが共有され、必要になった時には既にコネクションが確立されている可能性があります。

* 上流の完了とエラー処理

上流フローの正常な完了は、サブスクライバには影響を与えず、共有コルーチンは継続して実行されます。SharingStarted.WhileSubscribed が使用されている場合は、上流側が再び再開されます。その完了時に特別なアクションが必要な場合は、stateIn オペレータの前に onCompletion オペレータを使用して値を出力することができます。shareIn オペレータのドキュメントを参照してください。

上流のフローで例外が発生した場合、どのサブスクライバにも影響を与えることなく共有コルーチンが終了し、共有コルーチンが起動したスコープで処理されます。カスタム例外処理は、shareIn オペレータと同様に、stateIn の前に catch や retry オペレータを使用して設定できます。

👉 【MVVM】 Kotlin Flow で使える5つの利用パターン 
👉 【Kotlin】Flow の挙動やライフサイクルをログで確認する hatena-bookmark


Kotlin で Constants をどう書くべきか。

ふと、こんな書き方ではないのでは? と思ってしまいました。


object DbConstants {
  const val TABLE_USER_ATTRIBUTE_EMPID = "_id"
  const val TABLE_USER_ATTRIBUTE_DATA = "data"
}

以下、stackoverflow より。

通常クラスにしたり。


public class DbConstants {
  companion object {
    val TABLE_USER_ATTRIBUTE_EMPID = "_id"
    val TABLE_USER_ATTRIBUTE_DATA = "data"
  }
}

トップレベルのプロパティにしたり。


package com.project.constants
const val URL_PATH = "https:/"

結論

GitHub を眺めてみます。
Constants.kt - GitHub Search
👉 Search · Constants.kt 

これが良さげでは?

ファイル名は、Constants.kt 。


@file:JvmName("Constants")
package org.videolan.resources

const val PREF_FIRST_RUN = "first_run"
const val EXTRA_FIRST_RUN = "extra_first_run"
const val EXTRA_UPGRADE = "extra_upgrade"

@JvmField val EXTRA_SEARCH_BUNDLE = "${ACTION_REMOTE_GENERIC}extra_search_bundle"
@JvmField val ACTION_PLAY_FROM_SEARCH = "${ACTION_REMOTE_GENERIC}play_from_search"
@JvmField val ACTION_REMOTE_SWITCH_VIDEO = "${ACTION_REMOTE_GENERIC}SwitchToVideo"

👉 vlc-android/Constants.kt 

みんなは、どう書いてますか。

教えてねー。


複数の Flow を受け取る How to collect multiple flows

パラレルで同じライフサイクルの場合だけども。

flow-lifecycle



launch をネストしていますね!


View at Medium.com

👉 A safer way to collect flows from Android UIs | by Manuel Vivo | Android Developers | Medium 


【MVVM】 Kotlin Flow で使える5つの利用パターン

👉 【Kotlin】Flow の挙動やライフサイクルをログで確認する hatena-bookmark

以下、良記事の意訳です。

Migrating from LiveData to Kotlin’s Flow | Medium


View at Medium.com

LiveData は、2017年に必要とされていました。オブザーバーパターンは私たちの生活を楽にしてくれましたが、RxJava などの選択肢は当時の初心者にとって複雑すぎました。Architecture Components チームは、LiveData (Android向けに設計された、非常にこだわりをもったオブザーバ型のデータホルダークラス) を作成しました。これは、簡単に始められるようにシンプルに作られており、より複雑なリアクティブストリームのケースでは、RxJava と統合して使用することが推奨されていました。

Java開発者、初心者、そしてシンプルな状況では、やはり LiveData が最適です。それ以外の人は、Kotlin Flow に移行するのが良いでしょう。Flow はまだ学習曲線が急ですが、Kotlin 言語の一部であり、Jetbrains がサポートしています。また、リアクティブモデルにぴったりの Compose も登場します。

以前から、View と ViewModel 以外のアプリの様々な部分をつなぐために Flow を使うことを話してきました。Android UIから Flow を collect する安全な方法ができたことで、完全な移行ガイドを作成することができます。

この記事では、View に Flow を公開する方法、Flow を collect する方法、そして特定のニーズに合わせて微調整する方法を学びます。

#1 : 可変データホルダーを使用したワンショット

これは典型的なパターンで、コルーチンの結果でステートホルダーを変異させるものです。

Expose the result of a one-shot operation with a Mutable data holder


class MyViewModel {
  private val _myUiState = MutableStateFlow<Result<UiState>>(Result.Loading)
  val myUiState: StateFlow<Result<UiState>> = _myUiState

  init {
    viewModelScope.launch {
      val result = ...
      _myUiState.value = result
    }
  }
}

StateFlow は、LiveData に最も近い SharedFlow です。

- 常に値を持っています。
- 値は1つしかありません。
- 複数のオブザーバーをサポートしています(それで Flow は shared)。
- アクティブなオブザーバーの数とは関係なく、サブスクリプション時に常に最新の値を返す。

UIの状態を View に公開するときは、StateFlow を使います。これは、UI状態を保持するために設計された安全で効率的なオブザーバーです。

#2 : ワンショット

これは、前のスニペットと同じで、可変型のバッキング・プロパティを持たずに、コルーチン呼び出しの結果を公開するものです。

ステートホルダーは常に値を持っているので、UIの状態を Loading、Success、Error などでサポートする Result クラスなどでラップすることは良いアイデアです。

Expose the result of a one-shot operation


class MyViewModel(...) : ViewModel() {
  val result: StateFlow<Result<UiState>> = flow {
    emit(repository.fetchItem())
  }.stateIn(
    scope = viewModelScope,
    started = WhileSubscribed(5000),
    initialValue = Result.Loading
  )
}

stateIn は、Flow を StateFlow に変換する Flow 演算子です。 詳細は後ほど説明します。

#3 : パラメータを使用したワンショットデータロード

例えば、ユーザーIDに依存するデータをロードしたい場合、フローを公開している AuthManager からこの情報を取得するとします。

One-shot data load with parameters


class MyViewModel(authManager..., repository...) : ViewModel() {
  private val userId: Flow<UserId> = authManager.observeUser().map { user -> user.id }

  val result: StateFlow<Result<Item>> = userId.mapLatest { newUserId ->
    repository.fetchItem(newUserId)
  }.stateIn(
    scope = viewModelScope,
    started = WhileSubscribed(5000),
    initialValue = Result.Loading
  )
}

もっと柔軟性が必要な場合は、transformLatest を使用して、アイテムを明示的に emit することもできますのでご注意ください。


val result = userId.transformLatest { newUserId ->
  emit(Result.LoadingData)
  emit(repository.fetchItem(newUserId))
}.stateIn(
  scope = viewModelScope,
  started = WhileSubscribed(5000),
  initialValue = Result.LoadingUser // Note the different Loading states
)

#4 : パラメータを使用してのデータのストリーム監視

では、この例をより反応性の高いものにしてみましょう。データはフェッチするのではなく、監視するので、データのソースの変更を自動的にUIに伝播させます。

例では、データソースで fetchItem を呼び出す代わりに、Flow を返す observeItem を使用します。

Observing a stream of data with parameters


class MyViewModel(authManager..., repository...) : ViewModel() {
  private val userId: Flow<String?> =
    authManager.observeUser().map { user -> user?.id }

  val result: StateFlow<Result<Item>> = userId.flatMapLatest { newUserId ->
    repository.observeItem(newUserId)
  }.stateIn(
    scope = viewModelScope,
    started = WhileSubscribed(5000),
    initialValue = Result.LoadingUser
  )
}

公開された StateFlow は、ユーザーが変更されたり、リポジトリ内のユーザーのデータが変更されたりするたびに更新を受け取ります。

#5 : 複数のソースを組み合わせる : MediatorLiveData -> Flow.combine

1つまたは複数の更新ソースを観察し、新しいデータを取得したときに何かを行うことができます。


val flow1: Flow<Int> = ...
val flow2: Flow<Int> = ...

val result = combine(flow1, flow2) { a, b -> a + b }

conbineTransform や zip 関数も同様に利用することができます。

■ 公開する StateFlow を設定する (stateIn 演算子)

最初に stateIn を使って通常の Flow を StateFlow に変換しましたが、これにはいくつかの設定が必要です。今すぐに詳細な設定をせず、コピペで済ませたい人には以下の組み合わせがおすすめです。


val result: StateFlow<Result<UiState>> = someFlow
  .stateIn(
     scope = viewModelScope,
     started = WhileSubscribed(5000),
     initialValue = Result.Loading
   )

しかし、その一見ランダムな5秒間の開始パラメータがよくわからないという方は、ぜひ読んでみてください。
stateIn には3つのパラメータがあります(docsより)。

@param scope 共有が開始されるコルーチンのスコープ。
@param started 共有の開始と停止を制御する戦略。
@param initialValue ステートフローの初期値。

この値は SharingStarted.WhileSubscribed で replayExpirationMillis パラメータを指定して StateFlow をリセットしたときにも使用されます。

started には3つの値があります。

Lazily : 最初のサブスクライバが現れたときに開始し、スコープがキャンセルされたときに停止します。
Eagerly : すぐに開始し、スコープがキャンセルされたら停止する。
WhileSubscribed : (複雑なので次で説明します。)

ワンショットの場合は Lazily か Eagerly を使います。しかし、Flow を監視している場合は WhileSubscribed を使って、以下に説明するような小さくても重要な最適化を行うべきです。

■ WhileSubscribed

WhileSubscribed は、collector がない場合に上流の Flow をキャンセルします。stateIn を使って作成された StateFlow は View にデータを公開していますが、同時に他のレイヤーや上流からの Flow も監視しています。これらの Flow をアクティブにしておくと、例えば、データベース接続やハードウェアセンサーなどの他のソースからデータを読み込み続ける場合、リソースの無駄遣いにつながる可能性があります。アプリがバックグラウンドに移行する際には、これらのコルーチンを停止する必要があります。

WhileSubscribed は2つのパラメータを取ります。


public fun WhileSubscribed(
  stopTimeoutMillis: Long = 0,
  replayExpirationMillis: Long = Long.MAX_VALUE
)

* Stop timeout

stopTimeoutMillis は、最後の加入者がいなくなってから、上流の Flow が停止するまでの遅延時間(ミリ秒)を設定します。デフォルトはゼロ(直ちに停止)です。

これは、View がほんの数秒リスニングを停止したときに、上流の Flow をキャンセルしたくない場合に便利です。このようなことはよくあります。例えば、ユーザーがデバイスを回転させたときに、View が destroy され、すぐに再作成されるような場合です。

liveData ビルダーでの解決策は、サブスクライバーが存在しない場合にコルーチンを停止する5秒の delay を追加することでした。WhileSubscribed(5000) はまさにそれを行います。


class MyViewModel(...) : ViewModel() {
  val result = userId.mapLatest { newUserId ->
    repository.observeItem(newUserId)
  }.stateIn(
    scope = viewModelScope,
    started = WhileSubscribed(5000),
    initialValue = Result.Loading
  )
}

この方法は、以下、すべての条件を満たしています。

- ユーザーがアプリをバックグラウンドに送ると、他のレイヤーからの更新が5秒後に停止し、バッテリーを節約できます。
- 最新の値はまだキャッシュされているので、ユーザーが戻ってきたときには、View にはすぐに何らかのデータが表示されることになります。
- サブスクリプションが再開されると、新しい値が入ってきて、利用可能な場合は画面が更新されます。

* Replay expiration

ユーザーが長時間離れているときに古いデータを表示したくなく、ローディング画面を表示したい場合は、WhileSubscribed の replayExpirationMillis パラメータをチェックしてください。キャッシュされた値が stateIn で定義された初期値に復元されるため、この状況では非常に便利で、メモリも節約できます。アプリに戻ってきたときの動作は遅くなりますが、古いデータは表示されません。

replayExpirationMillis - 共有コルーチンの停止とリプレイキャッシュのリセット( shareIn 演算子の場合はキャッシュを空にし、stateIn 演算子の場合はキャッシュされた値を元の初期値にリセットする)の間の遅延時間(ミリ秒)を設定します。デフォルトは Long.MAX_VALUE です(リプレイキャッシュを永遠に保持し、バッファをリセットしない)。ゼロの値を使用すると、キャッシュは直ちに失効します。

👉 【Kotlin】Flow の挙動やライフサイクルをログで確認する hatena-bookmark

■ View から StateFlow を監視する

これまで見てきたように、View が ViewModel の StateFlow に、もう監視していないことを知らせることは非常に重要です。しかし、ライフサイクルに関連するすべてのことがそうであるように、それはそれほど単純なことではありません。

Flow を collect するためにはコルーチンが必要ですが Activity や Fragment にはコルーチンビルダーがたくさんあります。

- Activity.lifecycleScope.launch:コルーチンを直ちに開始し、アクティビティが destroy されたときにそれをキャンセルする。
- Fragment.lifecycleScope.launch:コルーチンを直ちに開始し、フラグメントが destoroy されたときにキャンセルします。
- Fragment.viewLifecycleOwner
.lifecycleScope.launch:コルーチンを直ちに開始し、フラグメントの View ライフサイクルが destroy されたときにキャンセルします。UIを変更する場合は、ビューライフサイクルを使用する必要があります。

■ LaunchWhenStarted, launchWhenResumed…

特殊な launch である launchWhenX は、lifecycleOwner が X の状態になるまで待ち、lifecycleOwner が X の状態を下回ったときにコルーチンを中断します。注意すべき点は、ライフサイクル・オーナーが破壊されるまでコルーチンをキャンセルしないことです。

LaunchWhenStarted, launchWhenResumed…

アプリがバックグラウンドで動作しているときに更新情報を受信すると、クラッシュする可能性がありますが、これはビューでの collect を中断することで解決します。しかし、アプリがバックグラウンドで動作している間、上流の Flow はアクティブに保たれるため、リソースが無駄になる可能性があります。

つまり、これまで StateFlow を設定するために行ってきたことがすべて無駄になってしまうのです。しかし、これには新しい API があります。

■ lifecycle.repeatOnLifecycle を活用する

この新しいコルーチンビルダー(lifecycle-runtime-ktx 2.4.0-alpha01から入手可能)は、私たちが必要としていることを正確に実行します:コルーチンを特定の状態で開始し、ライフサイクルオーナーがそれ以下になると停止します。

lifecycle.repeatOnLifecycle to the rescue

たとえば、フラグメントの場合:


onCreateView(...) {
  viewLifecycleOwner.lifecycleScope.launch {
    viewLifecycleOwner.lifecycle.repeatOnLifecycle(STARTED) {
      myViewModel.myUiState.collect { ... }
    }
  }
}

これは、Fragment のビューが STARTED になったときに収集を開始し、RESUMED まで継続し、STOPPED に戻ったときに停止します。
詳しくは、A safer way to collect flow from Android UI をご覧ください。

repeatOnLifecycle APIと上記の StateFlow ガイダンスを混ぜ合わせることで、デバイスのリソースを有効活用しながら最高のパフォーマンスを得ることができます。

repeatOnLifecycle API

注意:
データバインディングに最近追加された StateFlow のサポートでは、更新情報の収集に launchWhenCreated を使用していますが、安定版では代わりにrepeatOnLifecycle を使用するようになります。

データバインディングでは、あらゆる場所で Flow を使用し asLiveData() を追加するだけで View に公開することができます。データバインディングは lifecycle-runtime-ktx 2.4.0 が安定した時点で更新される予定です。

■ まとめ

ViewModel からデータを公開し、View で監視する方法:

⭕ WhileSubscribed を使って、タイムアウト付きの StateFlow を公開します。
⭕ repeatOnLifecycle を使って collect します。

これ以外の組み合わせでは、上流側の Flow がアクティブになり、リソースが無駄になります。

❌ WhileSubscribed を使って公開し、lifecycleScope.launch/launchWhenX で collect する。
❌ Lazily/Eagerlyを使って公開し、repeatOnLifecycle で collect する。

もちろん、Flow のフルパワーを必要としない場合は LiveData を使えばいいのです。

👉 StateFlow は distinctUtilChanged 不要  
👉 StateFlow の View への公開 
👉 【MVVM】Flow vs LiveData 
👉 【Kotlin】SharedFlow と BroadcastChannel