安卓考特林学習日記4


開始します。


自分が勉強しながら整理したい部分を書いた文章です.👀
一緒に勉強している人に役に立つことを願っています.
もし私が間違っているところがあれば、お知らせください.💌

🔹 はんのうプログラムせっけい


変化する伝播とデータ・ストリームに関連する宣言プログラミング・モード
  • 変化の伝播とデータストリーム:データが変化するたびにイベントが発生し、データの伝達を継続します.
  • 宣言プログラミング:実行する動作を具体的に説明するコマンドプログラミングとは異なり、単純にターゲットを宣言するだけです.
  • 🎈 アクティブな概念を適用する例


    プッシュ方式:データが変化した場合、変化した場所からデータを送信する.
  • リアルタイム通信(RTC):データ直接プッシュ方式ex)Apache嵐
  • スロットプログラミング
  • DB Trigger
  • Springのアプリケーションイベント
  • データバインディング
  • Angular
  • スマートフォンのプッシュメッセージ
  • ≪送信方法|Push By|emdw≫:リクエストを送信して、変更されたデータがあるかどうかを問合せ、変更されたデータを取得します.
  • クライアント要求&サーバ応答型アプリケーション
  • Javaなどのプログラミング言語
  • 🔹 ReactiveX(Rx)


    観測可能なストリームを使用した非同期プログラミングAPI
    Observable pattern + Iterator pattern + Functional programming
    (上記のような反応式プログラミングが可能なライブラリです.)
    純粋な関数、すなわち、外部データを変更せずに内部処理から受信した値を外部に戻す関数の連鎖反応.開発者のエラーによるエラーを回避し、スレッドの同時アクセスによるエラーやインタリーブの問題からプログラミングできます.

  • 観測可能(データソース)
    変更可能なデータのセット
    これは、将来の変更データを観察できることを意味します.

  • オペレータ(反応演算子)
    ファイバの関数の処理
    傍観者から伝達されたデータを加工して最終結果データを生成する

  • スヶジューラ
    スレッドマネージャ

  • Subcriber(サブスクライバ)
    傍観者によって発行されたデータを購読する購読者
    購読していない場合、傍観者が発行したデータは受信できません.

  • かんすうしきプログラミング
    RxJavaで提供される演算子(Operator)関数の使用
  • RxJavaでは,可視性を購読するオブザーバが存在し,可視性は順次発行されるデータに反応する.Observerableは、次の3つのイベントを使用して操作します.
  • OnNext():ObserverからObserverまで、データを一度に連続して公開します.
  • onComplete():完了したイベントをObserverに送信し、データのパブリケーションが終了し、OnNext()が呼び出されなくなったことを示します.
  • onError():Observerにエラーを送信します.nullは発行できません.
  • 以上のイベントはEmitterというインタフェースで発表されました.中間はオペレータ演算子でフィルタリングすることもできます.
    次は検索語を入力し、0.8秒後に自動的に検索するコードです.
    // 구독하고 나서 나오는 반환형이 disposable,
    // 모아서 한꺼번에 처리하고 메모리를 날림
    // CompositeDisposable -> 한번에 담아서 관리
    // 전역변수로 선언
    private var myCompositeDisposable = CompositeDisposable()
    
    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        val editTextChangeObservable = mySearchViewEditText.textChanges()
        // Disposable 인터페이스를 이용하여 옵저버블을 사용함으로서 발생할 수 있는 메모리 누수를 막을 수 있음
        // 옵저버블이 onComplete() 알림을 보냈을 때 자동으로 dispose()를 호출해 옵저버블과 구독자의 관계를 끊게 됨
        val searchEditTextSubscription: Disposable =
            // 옵저버블에 오퍼레이터(연산자)를 추가
            // debounce : 특정 시간이 지난 후에 마지막으로 들어온 이벤트만 받을 수 있는 오퍼레이터
            editTextChangeObservable.debounce(800, TimeUnit.MILLISECONDS)
                .subscribeOn(Schedulers.io()) // IO 스레드에서 돌리겠다
                .subscribeBy( // 구독 행위
                    onNext = { // 데이터를 수신
                        if (it.isNotEmpty()) { // 필터로도 가능
                            searchPhotoApiCall(it.toString())
                        }
                    },
                    onComplete = { 
                           // 완료가 되어 데이터 흐름이 끊김
                    },
                    onError = { 
                           // 데이터 흐름 끊김
                    }
                )
        // 살아있는 옵저버블 compositeDisposable에 추가
        myCompositeDisposable.add(searchEditTextSubscription)
    }
    
    override fun onDestroy() {
            // 지워주지 않으면 계속 메모리에 남음
            this.myCompositeDisposable.clear()
            super.onDestroy()
    }

    🔹 サブルーチン


    非同期で動作するコードをシンプル化するため、Androidで使用できる同時設計モード
    軽量スレッドは、Thread/AsyncTask/Rx Backgroundタスクに代わる非同期/非ブロックプログラミングを提供します.
    🎈 コラボレーション+ルーチン
    プライマリ・スレッドがブロックされる可能性がある部分に役立ちます.
    前回自分の実行が最後に停止した点以降の位置で実行を続行します.
    非同期処理を連続コードにする.

  • CoroutineScope
    コルディンの範囲;コルディンブロックの制御可能ユニット

  • GlobalScope
    CoroutineScopeの一種で、プログラム全体で事前定義された方法でバックグラウンドで実行される

  • CoroutineContext
    coutinをどのように処理するかに関する各種情報の集合.
    主にJobとDispatcherを含む

  • Dispatcher
    Dispatchers.Default:CPU集約型タスクに使用します.プライマリ・スレッドでの作業時間が長すぎるタスクに適しています.
    Dispatchers.IO:ネットワークとディスクを使用する場合.ファイルの読み書き/ソケットの読み書き操作を最適化します.
    Dispatchers.Main:AndroidではUIスレッドを使用します.
  • 🙋🏻‍♀️ サブルーチンの使用
    1.使用するDispatcherを特定し、
    2.Dispatcherを使用してCoroutineScopeを作成します.
    3.コードブロックをCoroutineScope起動またはasyncに渡せばよい.
    LaunchおよびasyncはCoroutineScopeの拡張関数であり、入力されたコードブロックを使用してcoutineを作成および実行するcoutineビルダーである.
    ジョブの開始オブジェクトに戻る
  • join():
  • コルディンブロックが完了するまで、次のコードの完了を待つ.
  • cancel():コルディンブロックの操作をキャンセル
  • async†Deferredオブジェクトを返します
    コルディンブロックの結果値を返すときに作成
  • wait():コルディンブロックが完了するまで、次のコードの実行を待機し、完了後に結果値を返します.
    (複数のasync coutionブロックで同じDeferredオブジェクトを使用する場合、最終結果値は最初のasync coutionブロックから)
  • .
  • cancel():コルディンブロックの操作をキャンセル

  • もう一つの一時停止関数suspend
    元ならmain関数は1000秒で終わり、doworld()の中のworld!出力できません.ただし、funの前にsuspendを付けて宣言すると、左側でストリームを切断する矢印のように一時停止し、suspend関数の処理が完了するとmain関数も終了します.
    上記のRxを使用したコードと同様に、検索語を入力して0.8秒後に自動的に検索するコードです.まだ知るべきことがたくさんあるので、欠けている概念を注釈(持続時間;)
    // 에딧텍스트 텍스트변경을 flow로 받기
    // Flow : 옵저버블와 비슷
    @ExperimentalCoroutinesApi
    fun EditText.textChangesToFlow(): Flow<CharSequence?> {
        // flow 콜백 받기 -> 콜백 자체가 suspend 제공
        return callbackFlow<CharSequence?> {
            val listener = object : TextWatcher {
                override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) = Unit
    
                override fun afterTextChanged(p0: Editable?) = Unit
    
                override fun onTextChanged(text: CharSequence?, p1: Int, p2: Int, p3: Int) {
                    Log.d(TAG, "onTextChanged() / textChangesToFlow() 에 달려있는 텍스트 와쳐 / text : $text")
                    // 값 내보내기
                    offer(text)
                }
            }
    
            // 위에서 설정한 리스너 달아주기
            addTextChangedListener(listener)
    
            // 콜백이 사라질때 실행됨
            awaitClose {
                Log.d(TAG, "textChangesToFlow() awaitClose 실행")
                removeTextChangedListener(listener)
            }
        }.onStart { // 콜백이 시작될 때 안의 내용을 발동 시켜라
            Log.d(TAG, "textChangesToFlow() / onStart 발동")
            // emit으로 이벤트 전달, Rx에서 onNext와 동일
            emit(text)
        }
    }
    // 전역으로 선언
    // Job : 백그라운드에서 실행되는 작업
    private var myCoroutineJob: Job = Job()
    // get() : 연산자(operator) 함수로써 주어진 key에 해당하는 컨텍스트 요소를 반환
    private val myCoroutineContext: CoroutineContext
       get() = Dispatchers.IO + myCoroutineJob
       
    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        // Rx의 스케줄러와 비슷
        // IO 스레드에서 돌리겠다고 설정
        // launch 코루틴 빌더 : 내부적으로 코루틴을 만들어서 Job 객체를 반환
        // job.join() : 코루틴이 완료될 때까지 기다렸다가 해당 메소드를 종료
        GlobalScope.launch(context = myCoroutineContext) {
            // editText가 변경되었을 때 Flow 형태로 받음 = 옵저버블
            val editTextFlow = mySearchViewEditText.textChangesToFlow()
            editTextFlow
                .debounce(800)
                .filter { // true, false로 적용됨
                    it?.length!! > 0
                }
                .onEach { // 흘러들어온 데이터(flow)를 받음
                    searchPhotoApiCall(it.toString())
                }
                .launchIn(this)
        }
    }
    
    override fun onDestroy() {
            myCoroutineContext.cancel()
            super.onDestroy()
    }