<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>hyeals study</title>
    <link>https://hyeals.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Tue, 4 Aug 2026 23:23:47 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>hyeals</managingEditor>
    <item>
      <title>구글 TTS API를 안드로이드에서 써보기!(2??)</title>
      <link>https://hyeals.tistory.com/81</link>
      <description>&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;지난 포스팅에서 구글 TTS API를 안드로이드에 써보는 걸 시도해봤는데 여기에 RxJava를 이용해서 리액티브한 요소를 한 번 집어넣어보면 어떨까해서 소소한 2탄을 준비했다. ㅎㅎ&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;목표는 EditText의 입력을 RxTextView를 이용해서 Observable로 만들어서 입력에 대한 변화를 관찰하게 만든다. 그 다음 이걸&amp;nbsp; Disposable과 함께 사용해서 좀 더 리액티브하게, 간단한 코드로 사용할 수 있도록 하는 것이다!&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;s&gt;&lt;b&gt;*RxTextView는 EditText를 Observable로 만들어준다.(RxBinding라이브러리에 포함되어 있다.)&lt;/b&gt;&lt;/s&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hyeals.tistory.com/80&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2021/02/10 - [안드로이드] - 구글 TTS API를 안드로이드에서 써보기!&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;opengraph&quot; data-og-title=&quot;구글 TTS API를 안드로이드에서 써보기!&quot; data-og-description=&quot;TTS란? Text To Speech의 약자로 텍스트를 음성으로 출력해주는 기술이다. (안드로이드에서는 무료로 제공해준다. 구글 TTS를 내장 API로 지원해주고 있다!) 물론 반대인 STT(Speech To Text)로 지원해준다. &quot; data-og-host=&quot;hyeals.tistory.com&quot; data-og-source-url=&quot;https://hyeals.tistory.com/80&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cwCZkg/hyJgmyrMgw/XRHqa69ZreclTvl8u7pvv1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800&quot; data-og-url=&quot;https://hyeals.tistory.com/80&quot;&gt;&lt;a href=&quot;https://hyeals.tistory.com/80&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://hyeals.tistory.com/80&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cwCZkg/hyJgmyrMgw/XRHqa69ZreclTvl8u7pvv1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;구글 TTS API를 안드로이드에서 써보기!&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;TTS란? Text To Speech의 약자로 텍스트를 음성으로 출력해주는 기술이다. (안드로이드에서는 무료로 제공해준다. 구글 TTS를 내장 API로 지원해주고 있다!) 물론 반대인 STT(Speech To Text)로 지원해준다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;hyeals.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;일단 gradle에 아래와 같이 라이브러리들을 추가해줘야한다.&lt;/p&gt;
&lt;pre class=&quot;clean&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	//RxAndroid와 RxJava , RxKotlin 추가
    implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
    implementation 'io.reactivex.rxjava3:rxjava:3.0.6'
    implementation 'io.reactivex.rxjava3:rxkotlin:3.0.0'

    // 필요한 API를 찾아서 추가
    implementation 'com.jakewharton.rxbinding4:rxbinding:4.0.0'&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;그리고 activity_main.xml에 TextView를 추가해줘야 한다.&lt;/p&gt;
&lt;pre class=&quot;xml&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&amp;gt;
&amp;lt;LinearLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    android:orientation=&quot;vertical&quot;
    tools:context=&quot;.MainActivity&quot;&amp;gt;

    &amp;lt;EditText
        android:id=&quot;@+id/editText&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:layout_marginTop=&quot;30dp&quot;
        android:inputType=&quot;textPersonName&quot; /&amp;gt;

    &amp;lt;TextView
        android:id=&quot;@+id/textView&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:layout_marginTop=&quot;30dp&quot;
        android:textAppearance=&quot;@style/TextAppearance.AppCompat.Large&quot;&amp;gt;&amp;lt;/TextView&amp;gt;

    &amp;lt;Button
        android:id=&quot;@+id/button&quot;
        android:layout_gravity=&quot;center_horizontal&quot;
        android:layout_width=&quot;wrap_content&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:layout_marginTop=&quot;30dp&quot;
        android:text=&quot;음성 출력&quot; /&amp;gt;
&amp;lt;/LinearLayout&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;요정도 추가해주고 저번&lt;b&gt; MainActivity.java&lt;/b&gt;코드를 아래와 같이 조금 수정해준다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package com.example.tts_test;

import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Build;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.jakewharton.rxbinding4.InitialValueObservable;
import com.jakewharton.rxbinding4.widget.RxTextView;

import java.util.Locale;

import io.reactivex.rxjava3.annotations.NonNull;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.Observer;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.observers.DisposableObserver;
import io.reactivex.rxjava3.subjects.BehaviorSubject;

public class MainActivity extends AppCompatActivity implements TextToSpeech.OnInitListener {

    private Disposable disposable;
    private TextToSpeech tts;
    private Button speak_out;
    private EditText input_text;
    private TextView result_text;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tts = new TextToSpeech(this, this);
        speak_out = findViewById(R.id.button);
        input_text = findViewById(R.id.editText);
        result_text = findViewById(R.id.textView);

        observeTextWatcher(input_text);

        speak_out.setOnClickListener(new View.OnClickListener(){
            @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) // LOLLIPOP이상 버전에서만 실행 가능
            @Override
            public void onClick(View v){
                speakOut();
            }
        });
    }

    public void observeTextWatcher(TextView tv){
        Observable ob = RxTextView.textChanges(tv);
        disposable = ob.subscribe(text -&amp;gt; result_text.setText(&quot;INPUT: &quot; + text.toString()));
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void speakOut(){
        CharSequence text = input_text.getText();
        tts.setPitch((float)0.6); // 음성 톤 높이 지정
        tts.setSpeechRate((float)0.1); // 음성 속도 지정

        // 첫 번째 매개변수: 음성 출력을 할 텍스트
        // 두 번째 매개변수: 1. TextToSpeech.QUEUE_FLUSH - 진행중인 음성 출력을 끊고 이번 TTS의 음성 출력
        //                 2. TextToSpeech.QUEUE_ADD - 진행중인 음성 출력이 끝난 후에 이번 TTS의 음성 출력
        tts.speak(text, TextToSpeech.QUEUE_FLUSH, null, &quot;id1&quot;);
    }

    @Override
    public void onDestroy() {
        if(tts!=null){ // 사용한 TTS객체 제거
            tts.stop();
            tts.shutdown();
        }
        disposable.dispose();
        super.onDestroy();
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    public void onInit(int status) { // OnInitListener를 통해서 TTS 초기화
        if(status == TextToSpeech.SUCCESS){
            int result = tts.setLanguage(Locale.KOREA); // TTS언어 한국어로 설정

            if(result == TextToSpeech.LANG_NOT_SUPPORTED || result == TextToSpeech.LANG_MISSING_DATA){
                Log.e(&quot;TTS&quot;, &quot;This Language is not supported&quot;);
            }else{
                speak_out.setEnabled(true);
                speakOut();
            }
        }else{
            Log.e(&quot;TTS&quot;, &quot;Initialization Failed!&quot;);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;이렇게 하면 resultText에 EditText에 입력한 문자열?이 결과로 출력된다. 입력값이 변화함에 따라 함께 계속 바뀐다!&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;이런 방식은 UI이벤트가 Rxjava로 인해 &lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;data stream&lt;/span&gt;&lt;/b&gt;형태로 출력되는것을 나타낸다!&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;아마 더 복잡한 내용을 다룰 수 있을 것 같다. (&lt;s&gt;공부하면 할수록 헷갈리는 부분이 많아서 책 한 권사서 정리하는것도 나쁘지 않을 것 같다 ㅠ&lt;/s&gt;)&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;*&lt;b&gt; Disposable을 선언한 이유&lt;/b&gt;: &lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;메모리 누수를 방지&lt;/span&gt;&lt;/b&gt;하기 위해서 &lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;Destroy부분에서 꼭 .dispose()를 이용해서 구독을 끝내야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;아래는 실행화면이다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;

            &lt;figure class=&quot;unsupported component-kakaotv&quot; contenteditable=&quot;false&quot; style=&quot;background:#000;margin:16px 0;min-height:72px;padding:10px 16px;display:flex;align-items:center;justify-content:center;text-align:center;box-sizing:border-box;width:100%;max-width:100%;&quot;&gt;
                &lt;p contenteditable=&quot;false&quot; style=&quot;margin:0;color:#8a8a8a;font-size:13px;line-height:1.6;user-select:none;pointer-events:none;&quot;&gt;동영상 서비스가 종료되어 해당 콘텐츠를 재생할 수 없습니다.&lt;/p&gt;
            &lt;/figure&gt;
        </description>
      <category>안드로이드</category>
      <category>Android</category>
      <author>hyeals</author>
      <guid isPermaLink="true">https://hyeals.tistory.com/81</guid>
      <comments>https://hyeals.tistory.com/81#entry81comment</comments>
      <pubDate>Sun, 14 Feb 2021 23:10:35 +0900</pubDate>
    </item>
    <item>
      <title>구글 TTS API를 안드로이드에서 써보기!</title>
      <link>https://hyeals.tistory.com/80</link>
      <description>&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;TTS란?&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Text To Speech&lt;/b&gt;의 약자로 텍스트를 음성으로 출력해주는 기술이다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;(안드로이드에서는 무료로 제공해준다. &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;구글 TTS&lt;/b&gt;&lt;/span&gt;를 내장 API로 지원해주고 있다!)&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;물론 반대인 &lt;b&gt;STT(Speech To Text)&lt;/b&gt;로 지원해준다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;안드로이드에서 TTS 적용해보기&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;activicy_main.xml&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;xml&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&amp;gt;
&amp;lt;LinearLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    android:orientation=&quot;vertical&quot;
    tools:context=&quot;.MainActivity&quot;&amp;gt;

    &amp;lt;EditText
        android:id=&quot;@+id/editText&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:layout_marginTop=&quot;30dp&quot;
        android:inputType=&quot;textPersonName&quot; /&amp;gt;

    &amp;lt;Button
        android:id=&quot;@+id/button&quot;
        android:layout_gravity=&quot;center_horizontal&quot;
        android:layout_width=&quot;wrap_content&quot;
        android:layout_height=&quot;wrap_content&quot;
        android:layout_marginTop=&quot;30dp&quot;
        android:text=&quot;음성 출력&quot; /&amp;gt;
&amp;lt;/LinearLayout&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;MainActivity.java&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1612935415787&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package com.example.tts_test;

import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Build;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import java.util.Locale;

public class MainActivity extends AppCompatActivity implements TextToSpeech.OnInitListener {

    private TextToSpeech tts;
    private Button speak_out;
    private EditText input_text;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tts = new TextToSpeech(this, this);
        speak_out = findViewById(R.id.button);
        input_text = findViewById(R.id.editText);

        speak_out.setOnClickListener(new View.OnClickListener(){
            @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) // LOLLIPOP이상 버전에서만 실행 가능
            @Override
            public void onClick(View v){
                speakOut();
            }
        });
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void speakOut(){
        CharSequence text = input_text.getText();
        tts.setPitch((float)0.6); // 음성 톤 높이 지정
        tts.setSpeechRate((float)0.1); // 음성 속도 지정

        // 첫 번째 매개변수: 음성 출력을 할 텍스트
        // 두 번째 매개변수: 1. TextToSpeech.QUEUE_FLUSH - 진행중인 음성 출력을 끊고 이번 TTS의 음성 출력
        //                 2. TextToSpeech.QUEUE_ADD - 진행중인 음성 출력이 끝난 후에 이번 TTS의 음성 출력
        tts.speak(text, TextToSpeech.QUEUE_FLUSH, null, &quot;id1&quot;);
    }

    @Override
    public void onDestroy() {
        if(tts!=null){ // 사용한 TTS객체 제거
            tts.stop();
            tts.shutdown();
        }
        super.onDestroy();
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    public void onInit(int status) { // OnInitListener를 통해서 TTS 초기화
        if(status == TextToSpeech.SUCCESS){
            int result = tts.setLanguage(Locale.KOREA); // TTS언어 한국어로 설정

            if(result == TextToSpeech.LANG_NOT_SUPPORTED || result == TextToSpeech.LANG_MISSING_DATA){
                Log.e(&quot;TTS&quot;, &quot;This Language is not supported&quot;);
            }else{
                speak_out.setEnabled(true);
                speakOut();// onInit에 음성출력할 텍스트를 넣어줌
            }
        }else{
            Log.e(&quot;TTS&quot;, &quot;Initialization Failed!&quot;);
        }
    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;테스트 해보기!&lt;/b&gt;&lt;/h4&gt;
&lt;div class=&quot;og-text&quot; style=&quot;display: inline !important;&quot;&gt;&amp;nbsp;&lt;/div&gt;

            &lt;figure class=&quot;unsupported component-kakaotv&quot; contenteditable=&quot;false&quot; style=&quot;background:#000;margin:16px 0;min-height:72px;padding:10px 16px;display:flex;align-items:center;justify-content:center;text-align:center;box-sizing:border-box;width:100%;max-width:100%;&quot;&gt;
                &lt;p contenteditable=&quot;false&quot; style=&quot;margin:0;color:#8a8a8a;font-size:13px;line-height:1.6;user-select:none;pointer-events:none;&quot;&gt;동영상 서비스가 종료되어 해당 콘텐츠를 재생할 수 없습니다.&lt;/p&gt;
            &lt;/figure&gt;
        
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;잘된다~&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.android.com/reference/android/speech/tts/TextToSpeech&quot;&gt;developer.android.com/reference/android/speech/tts/TextToSpeech&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1612934026525&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;TextToSpeech &amp;nbsp;|&amp;nbsp; Android 개발자 &amp;nbsp;|&amp;nbsp; Android Developers&quot; data-og-description=&quot;&quot; data-og-host=&quot;developer.android.com&quot; data-og-source-url=&quot;https://developer.android.com/reference/android/speech/tts/TextToSpeech&quot; data-og-url=&quot;https://developer.android.com/reference/android/speech/tts/TextToSpeech?hl=ko&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/zUVCD/hyJc2f6uel/A2M0W4fbeJ7LkNKdNIWJYK/img.png?width=1201&amp;amp;height=676&amp;amp;face=0_0_1201_676&quot;&gt;&lt;a href=&quot;https://developer.android.com/reference/android/speech/tts/TextToSpeech&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.android.com/reference/android/speech/tts/TextToSpeech&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/zUVCD/hyJc2f6uel/A2M0W4fbeJ7LkNKdNIWJYK/img.png?width=1201&amp;amp;height=676&amp;amp;face=0_0_1201_676');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;TextToSpeech &amp;nbsp;|&amp;nbsp; Android 개발자 &amp;nbsp;|&amp;nbsp; Android Developers&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;developer.android.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;a href=&quot;https://ebbnflow.tistory.com/188#recentComments&quot;&gt;ebbnflow.tistory.com/188#recentComments&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1612934038167&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Android] 구글STT, TTS 사용하기 (android.speech)&quot; data-og-description=&quot;● Android Speech Recognizer 안드로이드에서는 구글 SpeechToText, TextToSpeech 기술인 stt, tts를 내장 API로 지원하고 있습니다. 별도의 설치 없이 gradle에 특별한 세팅이 필요하지 않고 manifest에 몇 가..&quot; data-og-host=&quot;ebbnflow.tistory.com&quot; data-og-source-url=&quot;https://ebbnflow.tistory.com/188#recentComments&quot; data-og-url=&quot;https://ebbnflow.tistory.com/188&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bsgDQm/hyJcYktRze/wIFsZ90jmekGRp5DetEulK/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/bp7t6p/hyJex6CNMH/bKo1EsISdiTI0GQKzu5HvK/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/WRHyL/hyJcRFE3D5/7HS9LH2b8irWVv2POFn8fk/img.png?width=604&amp;amp;height=965&amp;amp;face=0_0_604_965&quot;&gt;&lt;a href=&quot;https://ebbnflow.tistory.com/188#recentComments&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ebbnflow.tistory.com/188#recentComments&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bsgDQm/hyJcYktRze/wIFsZ90jmekGRp5DetEulK/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/bp7t6p/hyJex6CNMH/bKo1EsISdiTI0GQKzu5HvK/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/WRHyL/hyJcRFE3D5/7HS9LH2b8irWVv2POFn8fk/img.png?width=604&amp;amp;height=965&amp;amp;face=0_0_604_965');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;[Android] 구글STT, TTS 사용하기 (android.speech)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;● Android Speech Recognizer 안드로이드에서는 구글 SpeechToText, TextToSpeech 기술인 stt, tts를 내장 API로 지원하고 있습니다. 별도의 설치 없이 gradle에 특별한 세팅이 필요하지 않고 manifest에 몇 가..&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;ebbnflow.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/sdsb8432/TextToSpeech-Android/blob/master/README.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;github.com/sdsb8432/TextToSpeech-Android/blob/master/README.md&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1612935589355&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;object&quot; data-og-title=&quot;sdsb8432/TextToSpeech-Android&quot; data-og-description=&quot;Text to Speech for Android Application with Google API - sdsb8432/TextToSpeech-Android&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/sdsb8432/TextToSpeech-Android/blob/master/README.md&quot; data-og-url=&quot;https://github.com/sdsb8432/TextToSpeech-Android&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bfrdiu/hyJcWUxaxK/oc1n2Wa9Bqx7kIykyw0MO0/img.png?width=420&amp;amp;height=420&amp;amp;face=0_0_420_420,https://scrap.kakaocdn.net/dn/r4PKY/hyJcTQ3H2W/m60JjYigJKAld9x6piTgAK/img.png?width=1080&amp;amp;height=1920&amp;amp;face=0_0_1080_1920&quot;&gt;&lt;a href=&quot;https://github.com/sdsb8432/TextToSpeech-Android/blob/master/README.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/sdsb8432/TextToSpeech-Android/blob/master/README.md&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bfrdiu/hyJcWUxaxK/oc1n2Wa9Bqx7kIykyw0MO0/img.png?width=420&amp;amp;height=420&amp;amp;face=0_0_420_420,https://scrap.kakaocdn.net/dn/r4PKY/hyJcTQ3H2W/m60JjYigJKAld9x6piTgAK/img.png?width=1080&amp;amp;height=1920&amp;amp;face=0_0_1080_1920');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;sdsb8432/TextToSpeech-Android&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Text to Speech for Android Application with Google API - sdsb8432/TextToSpeech-Android&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>안드로이드</category>
      <category>Android</category>
      <category>Java</category>
      <category>tts</category>
      <author>hyeals</author>
      <guid isPermaLink="true">https://hyeals.tistory.com/80</guid>
      <comments>https://hyeals.tistory.com/80#entry80comment</comments>
      <pubDate>Wed, 10 Feb 2021 14:43:09 +0900</pubDate>
    </item>
    <item>
      <title>Rxjava를 안드로이드에 적용시켜보기!</title>
      <link>https://hyeals.tistory.com/79</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;지난 포스팅에서는 Rxjava에서 데이터를 발행 및 구독하는 방법을 알아봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Rxjava를 안드로이드에 적용시키기 위해서 지금까지 공부했기 때문에 한 번 안드로이드 스튜디오를 이용해서 Rxjava를 안드로이드에 적용시켜서 실행할 계획이다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;일단 Rxjava를 안드로이드 스튜디오에서 사용하기 위해서는&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;build.gradle(:app)에 dependencies에 몇 가지를 추가&lt;/b&gt;&lt;/span&gt;해줘야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1612781002231&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;   //RxAndroid와 RxJava , RxKotlin 추가
    implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
    implementation 'io.reactivex.rxjava3:rxjava:3.0.6'
    implementation 'io.reactivex.rxjava3:rxkotlin:3.0.0'

    // 필요한 API를 찾아서 추가
    implementation 'com.jakewharton.rxbinding4:rxbinding:4.0.0'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이정도를 추가했는데 각각을 설명해보자면&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. Rxandroid:&lt;/b&gt; RxJava에 안드로이드용 스케쥴러 등 몇 가지 클래스를 추가해서 안드로이드 개발을 쉽게 해주는 라이브러리다. (+&lt;s&gt; 안드로이드의 스레드와 Rxjava에서 사용하는 스케쥴러를 연결해준다?&lt;/s&gt;)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. Rxjava 및 RxKotlin:&lt;/b&gt; Rxjava를 사용하려면 기본적으로 필요!&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3. Rxbinding:&lt;/b&gt; 안드로이드에서 editText와 같은 뷰 컴포넌트들을 손쉽게 Observable형태로 만들어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;각 버전의 정보는 아래 링크를 참고하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;a href=&quot;https://github.com/ReactiveX/RxJava&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;github.com/ReactiveX/RxJava&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1612781077725&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;object&quot; data-og-title=&quot;ReactiveX/RxJava&quot; data-og-description=&quot;RxJava &amp;ndash; Reactive Extensions for the JVM &amp;ndash; a library for composing asynchronous and event-based programs using observable sequences for the Java VM. - ReactiveX/RxJava&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/ReactiveX/RxJava&quot; data-og-url=&quot;https://github.com/ReactiveX/RxJava&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/YUcTJ/hyJc20dCKq/tlKq6iujAd8a8LehlyVRFK/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400&quot;&gt;&lt;a href=&quot;https://github.com/ReactiveX/RxJava&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/ReactiveX/RxJava&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/YUcTJ/hyJc20dCKq/tlKq6iujAd8a8LehlyVRFK/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;ReactiveX/RxJava&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;RxJava &amp;ndash; Reactive Extensions for the JVM &amp;ndash; a library for composing asynchronous and event-based programs using observable sequences for the Java VM. - ReactiveX/RxJava&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;* activity_main.xml에 id=textView라는 textView를 정의해놓았다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이제 &lt;b&gt;MainActivity.java&lt;/b&gt;에 RxJava를 사용한 코드를 작성해봤다.&lt;/p&gt;
&lt;pre id=&quot;code_1612781627356&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package com.example.rxjavatest;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import io.reactivex.rxjava3.annotations.NonNull;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.observers.DisposableObserver;
import io.reactivex.rxjava3.schedulers.Schedulers;


public class MainActivity extends AppCompatActivity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Observable&amp;lt;String&amp;gt; observable = Observable.create(emitter -&amp;gt; {
            emitter.onNext(Thread.currentThread().getName() + &quot;\n: RxJava Observer Test&quot;);
            emitter.onComplete();
            }
        );

        observable.subscribe(observer); // main스레드에서 실행

    }

    DisposableObserver&amp;lt;String&amp;gt; observer = new DisposableObserver&amp;lt;String&amp;gt;() {
        @Override
        public void onNext(@NonNull String s) {
            TextView rxjava_text = findViewById(R.id.textView);
            rxjava_text.setText(s);
        }

        @Override
        public void onError(@NonNull Throwable e) {
            Log.d(&quot;TEST&quot;, &quot;Observer Error...&quot;);
        }

        @Override
        public void onComplete() {
            Log.d(&quot;TEST&quot;, &quot;Observer Complete!&quot;);
        }
    };
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;-이렇게 작성하면 위의 코드는 메인 스레드에서 실행이 된다.&amp;nbsp;실제로 실행시켜보면 아래와 같은 결과를 보여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;386&quot; data-origin-height=&quot;635&quot; width=&quot;250&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZsBPN/btqWBAwWXSj/FbAxVzCQ7ObdFJfplCA8O1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZsBPN/btqWBAwWXSj/FbAxVzCQ7ObdFJfplCA8O1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZsBPN/btqWBAwWXSj/FbAxVzCQ7ObdFJfplCA8O1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZsBPN%2FbtqWBAwWXSj%2FFbAxVzCQ7ObdFJfplCA8O1%2Fimg.png&quot; data-origin-width=&quot;386&quot; data-origin-height=&quot;635&quot; width=&quot;250&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;* 다른 스레드에서 처리하고 싶다면 아래와 같이 변경해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1612781847871&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package com.example.rxjavatest;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import io.reactivex.rxjava3.annotations.NonNull;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.observers.DisposableObserver;
import io.reactivex.rxjava3.schedulers.Schedulers;


public class MainActivity extends AppCompatActivity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Observable&amp;lt;String&amp;gt; observable = Observable.create(emitter -&amp;gt; {
            emitter.onNext(Thread.currentThread().getName() + &quot;\n: RxJava Observer Test&quot;);
            emitter.onComplete();
            }
        );

        observable.subscribeOn(Schedulers.io()).subscribe(observer); // io스레드에서 실행

    }

    DisposableObserver&amp;lt;String&amp;gt; observer = new DisposableObserver&amp;lt;String&amp;gt;() {
        @Override
        public void onNext(@NonNull String s) {
            TextView rxjava_text = findViewById(R.id.textView);
            rxjava_text.setText(s);
        }

        @Override
        public void onError(@NonNull Throwable e) {
            Log.d(&quot;TEST&quot;, &quot;Observer Error...&quot;);
        }

        @Override
        public void onComplete() {
            Log.d(&quot;TEST&quot;, &quot;Observer Complete!&quot;);
        }
    };
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- 위 코드의 결과는 아래와 같으며, RxCachedThreadScheduler-1이라는 스레드에서 실행됨을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;381&quot; data-origin-height=&quot;633&quot; width=&quot;250&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UOqeq/btqWsIv4r99/0tKVK2LtK64m9Xg4TOr9MK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UOqeq/btqWsIv4r99/0tKVK2LtK64m9Xg4TOr9MK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UOqeq/btqWsIv4r99/0tKVK2LtK64m9Xg4TOr9MK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUOqeq%2FbtqWsIv4r99%2F0tKVK2LtK64m9Xg4TOr9MK%2Fimg.png&quot; data-origin-width=&quot;381&quot; data-origin-height=&quot;633&quot; width=&quot;250&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;아마 실제로는 더 훨씬 복잡하게 코드를 짤거다.. ㅜ&lt;/p&gt;</description>
      <category>안드로이드</category>
      <category>rxjava</category>
      <author>hyeals</author>
      <guid isPermaLink="true">https://hyeals.tistory.com/79</guid>
      <comments>https://hyeals.tistory.com/79#entry79comment</comments>
      <pubDate>Mon, 8 Feb 2021 20:01:25 +0900</pubDate>
    </item>
    <item>
      <title>RxJava 사용해보기</title>
      <link>https://hyeals.tistory.com/78</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;지난 포스팅에서 RxJava에 대한 개념을 정리했으니 이번에는 본격적으로 코드를 작성해보면서 공부할 예정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;일단 RxJava를 위해 알아야 할 것이 5가지 정도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. Observable&lt;/b&gt;: 데이터 소스&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;지속적으로 변경이 가능한 데이터의 집합이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;RxJava에서는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;Observable을 관찰하는 Observer가 존재&lt;/b&gt;&lt;/span&gt;하고, Observable이 순차적으로 발행하는 데이터에 대해서 반응한다. 다시말해서 &lt;b&gt;Observer pattern&lt;/b&gt;이 구현되어있는 클래스이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;* &lt;b&gt;Observer pattern&lt;/b&gt;: 객체의 상태 변화를 관찰하는 관찰자들(옵저버 목록)을 객체에 등록해서 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;상태 변화가 있을 때 마다&lt;/span&gt; 메서드 등을 통해 객체가 직접 목록의 각 옵저버에게 통지하도록 하는 패턴&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Observable에는 3가지 이벤트가 있다.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. onNext():&lt;/b&gt; 하나의 소스 Observable에서 Observer까지 한 번에 하나씩 순차적으로 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;데이터를 발행&lt;/b&gt;&lt;/span&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. onComplete():&lt;/b&gt; 데이터 발행이 끝났음을 알리는 완료 이벤트를 Observer에 전달해서 onNext()를 더 호출하지 않음을 나타낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3. onError():&lt;/b&gt; 오류가 발생했음을 Observer에게 전달한다. 만약 이 이벤트가 발생했다면 그 이후에는 onNext와 onComplete이벤트가 발생하지 않고 Observable이 종료한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이 이벤트들은 &lt;s&gt;Emitter라는 인터페이스에 의해 선언&lt;/s&gt;되며, 데이터나 오류 내용을 발행할 때 null은 발행할 수 없다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Observable생성하는 법&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;RxJava에서는 연산자(operator)를 이용해서 Observable을 생성할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Observable을 생성하는 함수는 아래와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. just()&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- 인자로 넣은 데이터를 차례대로 발행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- 인자로는 최대 10개를 넣을 수 있다. (이 때 인자들은 &lt;s&gt;타입이 서로 같아야 한다&lt;/s&gt;.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1612698292026&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import io.reactivex.rxjava3.core.Observable;

public class RxjavaTest {
    public static void main(String[] args){
        Observable&amp;lt;String&amp;gt; observable = Observable.just(&quot;Hi(1)&quot;, &quot;RxJava(1)&quot;, &quot;!!!(1)&quot;);
        observable.subscribe(data -&amp;gt; System.out.println(data));
        //observable.subscribe(System.out::println);

        Observable.just(&quot;Hi(2)&quot;, &quot;RxJava(2)&quot;, &quot;!!!(2)&quot;).subscribe(System.out::println);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;[결과]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Jnfyp/btqV2aNMqec/0HfEUKDtN5LbaYlGTlz670/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Jnfyp/btqV2aNMqec/0HfEUKDtN5LbaYlGTlz670/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Jnfyp/btqV2aNMqec/0HfEUKDtN5LbaYlGTlz670/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJnfyp%2FbtqV2aNMqec%2F0HfEUKDtN5LbaYlGTlz670%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. create()&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- just()와 달리 onNext(), onComplete(), onError()같은 이벤트를 개발자가 직접 호출해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- 등록된 콜백들을 제대로 처리하지 않으면 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;메모리 누수&lt;/b&gt;&lt;/span&gt;가 발생하기 때문에 신경써서 사용해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1612698667795&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import io.reactivex.rxjava3.core.Observable;

public class RxjavaTest_create {
    public static void main(String[] args){
        Observable &amp;lt;String&amp;gt; observable = Observable.create(emitter -&amp;gt;{
            emitter.onNext(&quot;Hello&quot;);
            emitter.onNext(&quot;Observable&quot;);
            emitter.onNext(&quot;Create!&quot;);
            emitter.onComplete();
                });

        observable.subscribe(System.out::println);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;[결과]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Bk0QQ/btqWjoYaRqR/G0lgDrv0J15YcugplIhbMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Bk0QQ/btqWjoYaRqR/G0lgDrv0J15YcugplIhbMK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Bk0QQ/btqWjoYaRqR/G0lgDrv0J15YcugplIhbMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBk0QQ%2FbtqWjoYaRqR%2FG0lgDrv0J15YcugplIhbMK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;onError&lt;/b&gt;를 처리하고 싶은 경우에는 아래와 같이 코드를 작성하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1612698914762&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import io.reactivex.rxjava3.core.Observable;

public class RxjavaTest_create {
    public static void main(String[] args){
        Observable &amp;lt;String&amp;gt; observable = Observable.create(emitter -&amp;gt;{
            emitter.onNext(&quot;Hello&quot;);
            emitter.onNext(&quot;Observable&quot;);
            emitter.onError(new Throwable());
            emitter.onNext(&quot;Create!&quot;);
            emitter.onComplete();
        });

        observable.subscribe(System.out::println, throwable -&amp;gt; System.out.println(&quot;Error!&quot;));
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;[결과]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QwroL/btqV0EonS65/0aH5DKzTVJ4VI6UJJ30INK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QwroL/btqV0EonS65/0aH5DKzTVJ4VI6UJJ30INK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QwroL/btqV0EonS65/0aH5DKzTVJ4VI6UJJ30INK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQwroL%2FbtqV0EonS65%2F0aH5DKzTVJ4VI6UJJ30INK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3. empty()&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- 아무런 데이터를 발행하지 않는 Observable을 생성하고 싶을 때 사용하는 연산자이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. 리액티브 연산자(Operators):&lt;/b&gt; 데이터 소스를 처리하는 함수&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이 리액티브 연산자를 통해서 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;데이터 소스로부터 전달받은 데이터를 가공&lt;/b&gt;&lt;/span&gt;해서 최종적인 결과 데이터를 만들어낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;예) &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;Debounce&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;,&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt; &lt;span style=&quot;color: #333333;&quot;&gt;Filter&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;, &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;Distinct&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;ElementAt&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;First&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;IgnoreElements&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Last&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Sample&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Skip&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;SkipLast&lt;span style=&quot;color: #333333;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Take&lt;span style=&quot;color: #333333;&quot;&gt;, and&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;TakeLast&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;아래 예시와 같이 필터 Opreator를 이용해서 데이터를 가공할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1612699777311&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import io.reactivex.rxjava3.core.Observable;

public class RxjavaTest {
    public static void main(String[] args){
        Observable&amp;lt;Integer&amp;gt; observable = Observable.just(1, 2, 3, 4, 5);
        observable.filter(data -&amp;gt; data &amp;gt; 3)
                  .subscribe(System.out::println);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;[결과]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGOsSf/btqVZR9hWq1/wQVXT2lBKI2yb4c4BOBfCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGOsSf/btqVZR9hWq1/wQVXT2lBKI2yb4c4BOBfCK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGOsSf/btqVZR9hWq1/wQVXT2lBKI2yb4c4BOBfCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGOsSf%2FbtqVZR9hWq1%2FwQVXT2lBKI2yb4c4BOBfCK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3. 스케쥴러(Scheduler):&lt;/b&gt; 스레드 관리자&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;리액티브 프로그래밍 자체가 비동기 프로그래밍을 위한 기법이기 때문에 스레드를 관리하는 관리자가 반드시 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;아래의 코드는 실행될 스레드를 따로 처리하지 않아서 메인 스레드에서 실행이 됨을 확인할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1612705472032&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import io.reactivex.rxjava3.core.Observable;

public class RxjavaTest {
    public static void main(String[] args) throws InterruptedException{
        Observable&amp;lt;Integer&amp;gt; observable = Observable.just(1, 2, 3, 4, 5);
        observable.filter(data -&amp;gt; data &amp;gt; 3)
                  .subscribe(data -&amp;gt; System.out.println(Thread.currentThread().getName()  
                  + &quot; : &quot; + &quot;Result: &quot; + data));

        Thread.sleep(500);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;[결과]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dgsHcr/btqWc89fN38/DHwPEdxmNTLsXeKJgWYeM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dgsHcr/btqWc89fN38/DHwPEdxmNTLsXeKJgWYeM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dgsHcr/btqWc89fN38/DHwPEdxmNTLsXeKJgWYeM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdgsHcr%2FbtqWc89fN38%2FDHwPEdxmNTLsXeKJgWYeM0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;하지만 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;스케쥴러를 사용&lt;/b&gt;&lt;/span&gt;하면 아래와 같이 다른 스레드에서 실행할 수 있도록 관리를 해줄 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1612705594315&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.schedulers.Schedulers;

public class RxjavaTest {
    public static void main(String[] args) throws InterruptedException{
        Observable&amp;lt;Integer&amp;gt; observable = Observable.just(1, 2, 3, 4, 5);
        observable.filter(data -&amp;gt; data &amp;gt; 3)
                  .subscribeOn(Schedulers.io())
                  .subscribe(data -&amp;gt; System.out.println(Thread.currentThread().getName() 
                  + &quot; : &quot; + &quot;Result: &quot; + data));

        Thread.sleep(500);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;[결과]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eis6XW/btqWjpQlqEc/GNTK923O857UxOPmrgwHGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eis6XW/btqWjpQlqEc/GNTK923O857UxOPmrgwHGk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eis6XW/btqWjpQlqEc/GNTK923O857UxOPmrgwHGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Feis6XW%2FbtqWjpQlqEc%2FGNTK923O857UxOPmrgwHGk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;[+]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1612706160151&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.schedulers.Schedulers;

public class RxjavaTest {
    public static void main(String[] args) throws InterruptedException{
        Observable&amp;lt;Integer&amp;gt; observable = Observable.just(1, 2, 3, 4, 5);
        observable.doOnNext(data -&amp;gt; System.out.println(Thread.currentThread().getName() 
        					+ &quot; : &quot; + &quot;doOnNext: &quot; + data))
                  .subscribeOn(Schedulers.io())
                  .observeOn(Schedulers.computation())
                  .filter(data -&amp;gt; data &amp;gt; 3)
                  .subscribe(data -&amp;gt; System.out.println(Thread.currentThread().getName()  
                  			+ &quot; : &quot; + &quot;Result: &quot; + data));

        Thread.sleep(500);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;[결과]&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfaIN6/btqV2Vv9KZY/ZqzqXPoulTVjlzfVGiPWR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfaIN6/btqV2Vv9KZY/ZqzqXPoulTVjlzfVGiPWR0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfaIN6/btqV2Vv9KZY/ZqzqXPoulTVjlzfVGiPWR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcfaIN6%2FbtqV2Vv9KZY%2FZqzqXPoulTVjlzfVGiPWR0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;* subscribeOn함수는 데이터의 발행 및 흐름을 관리하는 스레드를 정의한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;* observeOn함수는 데이터의 가공 및 처리를 관리하는 스레드를 정의한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;4. Subscriber:&lt;/b&gt; Observable이 발행하는 데이터를 구독하는 구독자&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;구독자가 구독하지 않으면 Observable이 발행한 데이터를 전달받을 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;따라서 subscribe함수를 호출해야 실제 데이터가 발행된다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;5. 함수형 프로그래밍:&lt;/b&gt; Rxjava에서 제공하는 연산자(Operator)함수를 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;전통적인 스레드 기반의 프로그래밍은 여러 스레드가 동시에 실행이 됐었다. 때문에 개발자가 예상하지 못한 문제가 발생하고 그 문제를 재현하는 것조차 어려운 상황이 발생했다. 리액티브 프로그래밍에서는 이러한 문제를 해결하기 위해서 부수 효과가 없는 순수함수를 지향하는 함수형 프로그래밍 기법을 도입했고, &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;함수형 프로그래밍 기법으로 작성된 함수가 바로 리액티브 연산자 함수&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;a href=&quot;https://blog.yena.io/studynote/2020/10/23/Android-RxJava(2).html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;blog.yena.io/studynote/2020/10/23/Android-RxJava(2).html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1612705229906&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;[Android] RxJava Observable 옵저버블&quot; data-og-description=&quot;지난 포스트 [Android] RxJava 시작하기에서는 반응형 프로그래밍에 대한 개념을 설명하고 명령형 프로그램과의 차이를 서술했다. 이번 포스트에서는 Observable이 어떻게 동작하는지 알아보자. 그리&quot; data-og-host=&quot;blog.yena.io&quot; data-og-source-url=&quot;https://blog.yena.io/studynote/2020/10/23/Android-RxJava(2).html&quot; data-og-url=&quot;https://blog.yena.io/studynote/2020/10/23/Android-RxJava(2).html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/H20MQ/hyJcX5gwnI/HKlPpirSRsVQwcrruZbcJ0/img.png?width=1280&amp;amp;height=630&amp;amp;face=0_0_1280_630,https://scrap.kakaocdn.net/dn/cLZlDA/hyJc01Z2KU/EgdekR12dDLmruCfIlm961/img.png?width=1280&amp;amp;height=400&amp;amp;face=0_0_1280_400,https://scrap.kakaocdn.net/dn/cKKBsv/hyJbkgIA2C/3E5eJ80UAUzrtXlJQ4rCo0/img.png?width=300&amp;amp;height=300&amp;amp;face=0_0_300_300&quot;&gt;&lt;a href=&quot;https://blog.yena.io/studynote/2020/10/23/Android-RxJava(2).html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.yena.io/studynote/2020/10/23/Android-RxJava(2).html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/H20MQ/hyJcX5gwnI/HKlPpirSRsVQwcrruZbcJ0/img.png?width=1280&amp;amp;height=630&amp;amp;face=0_0_1280_630,https://scrap.kakaocdn.net/dn/cLZlDA/hyJc01Z2KU/EgdekR12dDLmruCfIlm961/img.png?width=1280&amp;amp;height=400&amp;amp;face=0_0_1280_400,https://scrap.kakaocdn.net/dn/cKKBsv/hyJbkgIA2C/3E5eJ80UAUzrtXlJQ4rCo0/img.png?width=300&amp;amp;height=300&amp;amp;face=0_0_300_300');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;[Android] RxJava Observable 옵저버블&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;지난 포스트 [Android] RxJava 시작하기에서는 반응형 프로그래밍에 대한 개념을 설명하고 명령형 프로그램과의 차이를 서술했다. 이번 포스트에서는 Observable이 어떻게 동작하는지 알아보자. 그리&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;blog.yena.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;a href=&quot;https://medium.com/@sunminlee89/rxjava-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-1-99ddae13c1c7&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;medium.com/@sunminlee89/rxjava-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-1-99ddae13c1c7&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1612705237267&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;RxJava 프로그래밍 1&quot; data-og-description=&quot;RxJava 스터디에서 사용될 교재 &amp;lsquo;RxJava 프로그래밍&amp;rsquo;을 공부하며 정리할 내용을 포스팅할 예정이다.&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/@sunminlee89/rxjava-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-1-99ddae13c1c7&quot; data-og-url=&quot;https://medium.com/@sunminlee89/rxjava-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-1-99ddae13c1c7&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://medium.com/@sunminlee89/rxjava-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-1-99ddae13c1c7&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/@sunminlee89/rxjava-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-1-99ddae13c1c7&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;RxJava 프로그래밍 1&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;RxJava 스터디에서 사용될 교재 &amp;lsquo;RxJava 프로그래밍&amp;rsquo;을 공부하며 정리할 내용을 포스팅할 예정이다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;medium.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;a href=&quot;http://reactivex.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;reactivex.io/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1612749366189&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;ReactiveX&quot; data-og-description=&quot;CROSS-PLATFORM Available for idiomatic Java, Scala, C#, C++, Clojure, JavaScript, Python, Groovy, JRuby, and others&quot; data-og-host=&quot;reactivex.io&quot; data-og-source-url=&quot;http://reactivex.io/&quot; data-og-url=&quot;http://reactivex.io/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;http://reactivex.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;http://reactivex.io/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;ReactiveX&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;CROSS-PLATFORM Available for idiomatic Java, Scala, C#, C++, Clojure, JavaScript, Python, Groovy, JRuby, and others&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;reactivex.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;다음 포스팅에서는 RxJava를 안드로이드에 적용해서 공부할 계획이다!!&amp;nbsp;&lt;/p&gt;</description>
      <category>안드로이드</category>
      <author>hyeals</author>
      <guid isPermaLink="true">https://hyeals.tistory.com/78</guid>
      <comments>https://hyeals.tistory.com/78#entry78comment</comments>
      <pubDate>Sun, 7 Feb 2021 22:56:41 +0900</pubDate>
    </item>
    <item>
      <title>RxJava???</title>
      <link>https://hyeals.tistory.com/77</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;안드로이드 개발을 하면 RxJava라는 단어를 한 번쯤은 보게 된다. 대체 어떤 상황에서 뭘 위해 쓰는지 공부해보고 싶어 조금씩 알아가려한다!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;RxJava를 왜 사용할까?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;RxJava의 장점&lt;/b&gt;이라 하면 개발자들이 부딪힐 수 밖에 없는 문제인&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;1. 동시성의 문제&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;2. 다중 이벤트 처리 문제&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;3. 백그라운드 처리 문제&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;등의 여러 경우에서 문제를 편리하게 해결할 수 있도록 도와준다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;추가적으로 &lt;b&gt;안드로이드 개발&lt;/b&gt;의 경우 화면을 변경할 수 있는 것은 &lt;b&gt;메인 스레드 뿐&lt;/b&gt;이기 때문에 &lt;b&gt;비동기 처리&lt;/b&gt;를 해야하는 경우가 아주 빈번하다. 이때 Rx를 이용한다면 이 어려운 작업들을 쉽게 할 수 있다. 또 새로운 프로세스가 추가되거나 삭제 되어야 한다면 로직의 큰 변경 없이 간단히 수정할 수가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;(&lt;s&gt;아마 이 부분은 Rx가 선언적 프로그래밍 및 함수형 프로그래밍 기법을 사용해서 그런 것 같다!&lt;/s&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;이제 본격적으로 RxJava를 알아보자!&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;RxJava를 이해하기 위해서는 일단 &lt;b&gt;리액티브 프로그래밍&lt;/b&gt;이라는 것을 알아야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;과거의 Application은 클라이언트의 요청을 서버가 처리하고 클라이언트는 서버가 요청을 처리할 때까지 기다렸다가 처리가 끝났을 때 서버로부터 응답을 받아서 결과를 렌더링하는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt;&lt;b&gt;동기식 구조&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그러나,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;요즘에는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;Application의 규모가 커졌다.&lt;/span&gt; 당연하게도 Application은 복잡해졌고, &lt;u&gt;&lt;b&gt;비동기식 요청을 처리해야만&lt;/b&gt;&lt;/u&gt; 하는 시대가 됐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;리액티브 프로그래밍&lt;/b&gt;은 이런 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;비동기식 요청을 효과적으로 처리하기 위한 &lt;b&gt;비동기 프로그래밍을 위한 API&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;또한, &lt;b&gt;RxJava&lt;/b&gt;는 이런 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;리액티브 프로그래밍&lt;/b&gt; 방식을 구현한 &lt;b&gt;확장 라이브러&lt;span style=&quot;background-color: #f6e199;&quot;&gt;리다&lt;/span&gt;&lt;/b&gt;!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;좀 더 자세히 말하자면 RxJava는 ReactiveX(Reactive Extensions)를 JAVA로 구현한 라이브러리다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;(여기서 Reactive란 무엇일까?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;ReactiveX는 관찰가능한(Observable)스트림을 사용하는 비동기 프로그래밍을 위한 API다.)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;+ 좀 더 자세하게 알아보는 리액티브 프로그래밍(= 반응형 프로그래밍)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;리액티브 프로그래밍을 위키피디아에 검색하면 아래와 같이 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMCoKc/btqVqF8QJHq/ATLmglNkEldMOYq24dgykk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMCoKc/btqVqF8QJHq/ATLmglNkEldMOYq24dgykk/img.png&quot; data-alt=&quot;???&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMCoKc/btqVqF8QJHq/ATLmglNkEldMOYq24dgykk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMCoKc%2FbtqVqF8QJHq%2FATLmglNkEldMOYq24dgykk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;???&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이 내용이 좀 어려운 것 같다.&amp;nbsp;조금 뜻을 찾아보면 아래와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- &lt;b&gt;변경 전파 및 데이터 흐름&lt;/b&gt;: &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;데이터가 변경될 때 마다 이벤트를 발생&lt;/b&gt;&lt;/span&gt;시켜서 데이터를 계속적으로 전달하는 것(이벤트를 모니터링 하고 있는 쪽은 이벤트가 발생할 때 마다 해당 데이터를 계속적으로 전달받음)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- &lt;b&gt;명령형 프로그래밍&lt;/b&gt;: 실행할 동작을 구체적(EX. 알고리즘)으로 명시하는 프로그래밍 방식(예: Java)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- &lt;b&gt;선언적 프로그래밍 패러다임:&lt;/b&gt; 명령형 프로그래밍과 달리 단순히 목표를 선언하는 방식(예: RxJava)&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;리액티브의 개념이 적용된 예시&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;- 일반적으로 Application은 &lt;b&gt;push방식&lt;/b&gt;과 &lt;b&gt;pull방식&lt;/b&gt;으로 나뉠 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;◎ &lt;/span&gt;&lt;b&gt;push방식&lt;/b&gt;: &lt;span style=&quot;background-color: #f6e199;&quot;&gt;데이터의 변화가 발생했을 때 변경이 발생한 곳에서 데이터를 보내주는 방식&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;s&gt;☞&amp;nbsp;이게 리액티브 방식이라고 할 수 있다.&lt;/s&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. RTC(Real Time Communication)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;아파치 스톰같은 오픈소스를 이용하면 실시간 통신을 구현할 수 있는데 실시간 통신은 데이터를 직접 push해서 전달하는 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. 소켓 프로그래밍&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;채팅 프로그램에서 많이 사용한다. A라는 클라이언트에서 데이터를 보내면 이 데이터를 서버 쪽에서 받아서 B라는 클라이언트에게 직접 push해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3. DBTrigger&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;프로시저 등에서 데이터베이스의 컬럼에서 변경된 데이터에 대한 이벤트를 모니터링하고 있다가 그 이벤트가 발생했을 때 후속처리를 하는 방식&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;4. Spring의 ApplicationEvent&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;어떤 객체에서 ApplicationEvent를 모니터링 하고 있다가 이벤트가 발생하면 후속 처리를 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;5. Angular의 데이터 바인딩&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;데이터의 변경이 발생했을 경우에 view를 업데이트 해주는 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;6. 스마트폰의 push메시지&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;스마트폰의 사용자가 어떤 변경된 push메시지가 있는지 서버측에 물어보는것이 아닌, 서버 측에서 스마트폰에 변경된 push 메시지를 전송해주면 사용자가 알림을 받아서 push메시지를 확인하는 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;◎ &lt;/span&gt;&lt;b&gt;pull방식&lt;/b&gt;: 변경된 데이터가 있는지 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;요청을 보내 질의하고 변경된 데이터를 가져오는 방식&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. 클라이언트 요청&amp;amp;서버 응답 방식의 Application&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. Java와 같은 절차형 프로그래밍 언어&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;특정 메소드를 호출해서 리턴값을 반환 받는 절차&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;개념을 어느정도 정리한 것 같으니 다음 포스팅에서는 직접 코드를 구현하면서 RxJava에 대해 알아볼 예정이다!&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;a href=&quot;https://blog.yena.io/studynote/2020/10/11/Android-RxJava(1).html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;blog.yena.io/studynote/2020/10/11/Android-RxJava(1).html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1611626662066&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;[Android] RxJava 시작하기&quot; data-og-description=&quot;RxJava, RxAndroid 시작하기 안드로이드 개발을 하다보면 언젠가는 RxJava와 만나게 된다. 이미 몇 년 전부터 많은 프론트 개발자들이 사랑사용해 온 라이브러리이기 때문이다. 현재 회사 프로젝트에&quot; data-og-host=&quot;blog.yena.io&quot; data-og-source-url=&quot;https://blog.yena.io/studynote/2020/10/11/Android-RxJava(1).html&quot; data-og-url=&quot;https://blog.yena.io/studynote/2020/10/11/Android-RxJava(1).html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bGBveI/hyI2wosvYe/gBsJR6c0pJqoVubEWFApgK/img.png?width=300&amp;amp;height=300&amp;amp;face=0_0_300_300&quot;&gt;&lt;a href=&quot;https://blog.yena.io/studynote/2020/10/11/Android-RxJava(1).html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.yena.io/studynote/2020/10/11/Android-RxJava(1).html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bGBveI/hyI2wosvYe/gBsJR6c0pJqoVubEWFApgK/img.png?width=300&amp;amp;height=300&amp;amp;face=0_0_300_300');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;[Android] RxJava 시작하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;RxJava, RxAndroid 시작하기 안드로이드 개발을 하다보면 언젠가는 RxJava와 만나게 된다. 이미 몇 년 전부터 많은 프론트 개발자들이 사랑사용해 온 라이브러리이기 때문이다. 현재 회사 프로젝트에&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;blog.yena.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;+ Kevin의 알기쉬운 RxJava - 리액티브 프로그래밍이란? (youtube)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;</description>
      <category>안드로이드</category>
      <category>rxjava</category>
      <author>hyeals</author>
      <guid isPermaLink="true">https://hyeals.tistory.com/77</guid>
      <comments>https://hyeals.tistory.com/77#entry77comment</comments>
      <pubDate>Sat, 6 Feb 2021 23:02:21 +0900</pubDate>
    </item>
    <item>
      <title>얼굴인식 및 영상인식 관련(Android, ML kit, OpenCV...)</title>
      <link>https://hyeals.tistory.com/74</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;1.&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;얼굴 외곽선 눈코입 인식 &lt;span&gt;face geometry &lt;/span&gt;소스&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;1)&lt;a href=&quot;https://www.pyimagesearch.com/2017/04/17/real-time-facial-landmark-detection-opencv-python-dlib/&quot;&gt;https://www.pyimagesearch.com/2017/04/17/real-time-facial-landmark-detection-opencv-python-dlib/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1610088581301&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Real-time facial landmark detection with OpenCV, Python, and dlib - PyImageSearch&quot; data-og-description=&quot;In this tutorial, I demonstrate how to detect facial landmarks in video streams in real-time using OpenCV, Python, and dlib.&quot; data-og-host=&quot;www.pyimagesearch.com&quot; data-og-source-url=&quot;https://www.pyimagesearch.com/2017/04/17/real-time-facial-landmark-detection-opencv-python-dlib/&quot; data-og-url=&quot;https://www.pyimagesearch.com/2017/04/17/real-time-facial-landmark-detection-opencv-python-dlib/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/pJtGJ/hyIQ0JsyyN/kpNfycIcfIxnt0rVKPXiJ0/img.jpg?width=700&amp;amp;height=426&amp;amp;face=328_68_481_235&quot;&gt;&lt;a href=&quot;https://www.pyimagesearch.com/2017/04/17/real-time-facial-landmark-detection-opencv-python-dlib/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.pyimagesearch.com/2017/04/17/real-time-facial-landmark-detection-opencv-python-dlib/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/pJtGJ/hyIQ0JsyyN/kpNfycIcfIxnt0rVKPXiJ0/img.jpg?width=700&amp;amp;height=426&amp;amp;face=328_68_481_235');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;Real-time facial landmark detection with OpenCV, Python, and dlib - PyImageSearch&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;In this tutorial, I demonstrate how to detect facial landmarks in video streams in real-time using OpenCV, Python, and dlib.&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;www.pyimagesearch.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;span&gt;- python, OpenCV, dlib&lt;/span&gt;을 이용해서 얼굴 랜드 마크를 감지&lt;/p&gt;
&lt;p&gt;&lt;span&gt;-&lt;s&gt; java&lt;/s&gt;&lt;/span&gt;&lt;s&gt;및 &lt;span&gt;kotlin&lt;/span&gt;을 사용하는 것이 아니라 적절해 보이지 않음&lt;span&gt;.&lt;/span&gt;&lt;/s&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;2 )&lt;a href=&quot;https://firebase.google.com/docs/ml-kit/android/detect-faces?hl=ko#kotlin+ktx_10&quot;&gt;https://firebase.google.com/docs/ml-kit/android/detect-faces?hl=ko#kotlin+ktx_10&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1610088581922&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Android에서 ML Kit를 사용하여 얼굴 인식 &amp;nbsp;|&amp;nbsp; Firebase&quot; data-og-description=&quot;This page describes an old version of the Face Detection API, which was part of ML Kit for Firebase. Development of this API has been moved to the standalone ML Kit SDK, which you can use with or without Firebase. Learn more. See Android에서 ML Kit를 &quot; data-og-host=&quot;firebase.google.com&quot; data-og-source-url=&quot;https://firebase.google.com/docs/ml-kit/android/detect-faces?hl=ko#kotlin+ktx_10&quot; data-og-url=&quot;https://firebase.google.com/docs/ml-kit/android/detect-faces?hl=ko&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://firebase.google.com/docs/ml-kit/android/detect-faces?hl=ko#kotlin+ktx_10&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://firebase.google.com/docs/ml-kit/android/detect-faces?hl=ko#kotlin+ktx_10&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;Android에서 ML Kit를 사용하여 얼굴 인식 &amp;nbsp;|&amp;nbsp; Firebase&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;This page describes an old version of the Face Detection API, which was part of ML Kit for Firebase. Development of this API has been moved to the standalone ML Kit SDK, which you can use with or without Firebase. Learn more. See Android에서 ML Kit를&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;firebase.google.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;span&gt;- Android&lt;/span&gt;의 &lt;b&gt;&lt;span&gt;ML Kit &lt;/span&gt;라이브러리&lt;/b&gt;를 사용해서 이미지 및 동영상에 있는 얼굴 외곽선 인식 가능&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;앱을 설치한 후에 기기에 ML모델을 자동으로 다운로드하도록 구성하는 것이 좋음&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;- firebase, java or kotlin+ktx&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;- &lt;/span&gt;예제가 잘 나와있어서 구현하기에 큰 어려움이 없어 보임&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;* ML Kit: &lt;/span&gt;구글의 기기 내 머신 러닝 기술을&lt;span&gt; Android &lt;/span&gt;및&lt;span&gt; iOS&lt;/span&gt;앱에 제공하는 모바일&lt;span&gt; SDK.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;3)&lt;a href=&quot;https://medium.com/devnibbles/facial-recognition-with-android-1-4-5e043c264edc&quot;&gt;https://medium.com/devnibbles/facial-recognition-with-android-1-4-5e043c264edc&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1610088577633&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Facial Recognition with Android (1/4)&quot; data-og-description=&quot;In this series of articles I&amp;rsquo;m going to cover how you can add facial recognition (not just facial detection) to your Android app.&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/devnibbles/facial-recognition-with-android-1-4-5e043c264edc&quot; data-og-url=&quot;https://medium.com/devnibbles/facial-recognition-with-android-1-4-5e043c264edc&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b04eoI/hyISYb9Izy/2eGBy5NOm3sxxJrOTKXPs1/img.jpg?width=1200&amp;amp;height=534&amp;amp;face=573_198_871_323,https://scrap.kakaocdn.net/dn/bOwcrk/hyIQ2AvBqc/PXGGWOVKr5xNGUp2UORV01/img.jpg?width=60&amp;amp;height=26&amp;amp;face=0_0_60_26,https://scrap.kakaocdn.net/dn/gn1P9/hyISYJ0grp/ixrMJdMbZd5wb5Pwnucko1/img.jpg?width=38&amp;amp;height=59&amp;amp;face=0_13_36_52&quot;&gt;&lt;a href=&quot;https://medium.com/devnibbles/facial-recognition-with-android-1-4-5e043c264edc&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/devnibbles/facial-recognition-with-android-1-4-5e043c264edc&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b04eoI/hyISYb9Izy/2eGBy5NOm3sxxJrOTKXPs1/img.jpg?width=1200&amp;amp;height=534&amp;amp;face=573_198_871_323,https://scrap.kakaocdn.net/dn/bOwcrk/hyIQ2AvBqc/PXGGWOVKr5xNGUp2UORV01/img.jpg?width=60&amp;amp;height=26&amp;amp;face=0_0_60_26,https://scrap.kakaocdn.net/dn/gn1P9/hyISYJ0grp/ixrMJdMbZd5wb5Pwnucko1/img.jpg?width=38&amp;amp;height=59&amp;amp;face=0_13_36_52');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;Facial Recognition with Android (1/4)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;In this series of articles I&amp;rsquo;m going to cover how you can add facial recognition (not just facial detection) to your Android app.&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;medium.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;span&gt;- &lt;/span&gt;두 번째 링크를 참고해서 직접 구현한 코드 有&lt;/p&gt;
&lt;p&gt;&lt;span&gt;- &lt;/span&gt;참고하기에 좋아 보임&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;4) &lt;a href=&quot;https://machine-woong.tistory.com/115&quot;&gt;https://machine-woong.tistory.com/115&lt;/a&gt; &lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1610088576509&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;(스크랩 ) OpenCV와 NDK를 사용하여 Android에서 Face Detection(얼굴 인식)&quot; data-og-description=&quot;OpenCV 배포시 포함되어 있는 얼굴 인식 C++코드를 NDK를 이용하여 Android에서 동작하도록 수정하였습니다. 안드로이드 + &amp;nbsp;NDK 카메라 기본코드에 단순히 C++코드만 옮겨오면 되는 줄 알았는데 고려해&quot; data-og-host=&quot;machine-woong.tistory.com&quot; data-og-source-url=&quot;https://machine-woong.tistory.com/115&quot; data-og-url=&quot;https://machine-woong.tistory.com/115&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bFaJvv/hyIQSYWLVA/DzG5x7GfXP6BOj2f1eKykK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/basOv7/hyIQ4d1HrI/cOM5tHRk5XbkfVuYUW0k9k/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/caPoMQ/hyIQReFQnb/vbljKcjBB2ls6Aygt1RkF1/img.png?width=450&amp;amp;height=384&amp;amp;face=0_0_450_384&quot;&gt;&lt;a href=&quot;https://machine-woong.tistory.com/115&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://machine-woong.tistory.com/115&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bFaJvv/hyIQSYWLVA/DzG5x7GfXP6BOj2f1eKykK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/basOv7/hyIQ4d1HrI/cOM5tHRk5XbkfVuYUW0k9k/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/caPoMQ/hyIQReFQnb/vbljKcjBB2ls6Aygt1RkF1/img.png?width=450&amp;amp;height=384&amp;amp;face=0_0_450_384');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;(스크랩 ) OpenCV와 NDK를 사용하여 Android에서 Face Detection(얼굴 인식)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;OpenCV 배포시 포함되어 있는 얼굴 인식 C++코드를 NDK를 이용하여 Android에서 동작하도록 수정하였습니다. 안드로이드 + &amp;nbsp;NDK 카메라 기본코드에 단순히 C++코드만 옮겨오면 되는 줄 알았는데 고려해&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;machine-woong.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;span&gt;- Android NDK + OpenCV&lt;/span&gt;로 얼굴 &lt;span&gt;+ &lt;/span&gt;눈 인식 코드&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;5) &lt;a href=&quot;https://www.programmersought.com/article/6974348683/&quot;&gt;https://www.programmersought.com/article/6974348683/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1610088574660&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Facial Landmark Detection with OpenCV - Programmer Sought&quot; data-og-description=&quot;Summary: Using Facial Landmark Detection with OpenCV Author： Amusi Date： 2018-03-20 Note: OpenCV3.4 and support for Facemark Reprinted:https://github.com/amusi/opencv-facial-landmark-detection Directory Structure: introduction Facemark API Facemark tra&quot; data-og-host=&quot;www.programmersought.com&quot; data-og-source-url=&quot;https://www.programmersought.com/article/6974348683/&quot; data-og-url=&quot;https://www.programmersought.com/article/6974348683/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://www.programmersought.com/article/6974348683/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.programmersought.com/article/6974348683/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;Facial Landmark Detection with OpenCV - Programmer Sought&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Summary: Using Facial Landmark Detection with OpenCV Author： Amusi Date： 2018-03-20 Note: OpenCV3.4 and support for Facemark Reprinted:https://github.com/amusi/opencv-facial-landmark-detection Directory Structure: introduction Facemark API Facemark tra&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;www.programmersought.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;span&gt;- OpenCv&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;6) &lt;a href=&quot;https://github.com/justadudewhohacks/face-api.js/&quot;&gt;https://github.com/justadudewhohacks/face-api.js/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1610088574848&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;object&quot; data-og-title=&quot;justadudewhohacks/face-api.js&quot; data-og-description=&quot;JavaScript API for face detection and face recognition in the browser and nodejs with tensorflow.js - justadudewhohacks/face-api.js&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/justadudewhohacks/face-api.js/&quot; data-og-url=&quot;https://github.com/justadudewhohacks/face-api.js&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cwBmEj/hyISXqNkm4/EKSep77D0FC1L1XKUW88vK/img.jpg?width=400&amp;amp;height=400&amp;amp;face=121_121_312_329,https://scrap.kakaocdn.net/dn/cqsmVM/hyITaKq7Hg/GT0VHnDJay1WT22h1lV1Ck/img.jpg?width=709&amp;amp;height=473&amp;amp;face=50_43_652_390,https://scrap.kakaocdn.net/dn/fumCH/hyIS5WEYYA/97Wflt0eCANx3PoPY6ZaU0/img.jpg?width=709&amp;amp;height=472&amp;amp;face=49_34_659_392&quot;&gt;&lt;a href=&quot;https://github.com/justadudewhohacks/face-api.js/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/justadudewhohacks/face-api.js/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cwBmEj/hyISXqNkm4/EKSep77D0FC1L1XKUW88vK/img.jpg?width=400&amp;amp;height=400&amp;amp;face=121_121_312_329,https://scrap.kakaocdn.net/dn/cqsmVM/hyITaKq7Hg/GT0VHnDJay1WT22h1lV1Ck/img.jpg?width=709&amp;amp;height=473&amp;amp;face=50_43_652_390,https://scrap.kakaocdn.net/dn/fumCH/hyIS5WEYYA/97Wflt0eCANx3PoPY6ZaU0/img.jpg?width=709&amp;amp;height=472&amp;amp;face=49_34_659_392');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;justadudewhohacks/face-api.js&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;JavaScript API for face detection and face recognition in the browser and nodejs with tensorflow.js - justadudewhohacks/face-api.js&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- &lt;/span&gt;자바스크립트 얼굴인식 &lt;span&gt;API&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span&gt;⊚&lt;/span&gt; 참고 자료&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;MLkit&lt;/span&gt;라이브러리&lt;span&gt; + Vision API + CameraX&lt;/span&gt;를 이용해서 만든 앱&lt;span&gt; (&lt;/span&gt;얼굴 외곽선 가져오기&lt;span&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;a href=&quot;https://medium.com/hongbeomi-dev/mlkit-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC%EC%99%80-camerax%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC-vision-%EC%95%B1-%EB%A7%8C%EB%93%A4%EA%B8%B0-ad657e2e81e1&quot;&gt;https://medium.com/hongbeomi-dev/mlkit-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC%EC%99%80-camerax%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC-vision-%EC%95%B1-%EB%A7%8C%EB%93%A4%EA%B8%B0-ad657e2e81e1&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1610088572760&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;MLkit 라이브러리와 CameraX를 사용하여 Vision 앱 만들기&quot; data-og-description=&quot;구글의 mlkit 라이브러리와 cameraX를 사용하여 간단하게 vision 구현하기&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/hongbeomi-dev/mlkit-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC%EC%99%80-camerax%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC-vision-%EC%95%B1-%EB%A7%8C%EB%93%A4%EA%B8%B0-ad657e2e81e1&quot; data-og-url=&quot;https://medium.com/hongbeomi-dev/mlkit-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC%EC%99%80-camerax%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC-vision-%EC%95%B1-%EB%A7%8C%EB%93%A4%EA%B8%B0-ad657e2e81e1&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bl1gHF/hyIS6acaSc/xspKczKjG548GHHSl90TeK/img.jpg?width=1200&amp;amp;height=800&amp;amp;face=0_0_1200_800,https://scrap.kakaocdn.net/dn/wIu1v/hyIS3dtfSe/L9CvZYrT4SjeTpN13QyixK/img.jpg?width=60&amp;amp;height=40&amp;amp;face=0_0_60_40,https://scrap.kakaocdn.net/dn/boATBR/hyIS3ExnYq/NmiweSP92zcz8dzLK8MIlk/img.jpg?width=34&amp;amp;height=60&amp;amp;face=0_0_34_60&quot;&gt;&lt;a href=&quot;https://medium.com/hongbeomi-dev/mlkit-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC%EC%99%80-camerax%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC-vision-%EC%95%B1-%EB%A7%8C%EB%93%A4%EA%B8%B0-ad657e2e81e1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/hongbeomi-dev/mlkit-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC%EC%99%80-camerax%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC-vision-%EC%95%B1-%EB%A7%8C%EB%93%A4%EA%B8%B0-ad657e2e81e1&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bl1gHF/hyIS6acaSc/xspKczKjG548GHHSl90TeK/img.jpg?width=1200&amp;amp;height=800&amp;amp;face=0_0_1200_800,https://scrap.kakaocdn.net/dn/wIu1v/hyIS3dtfSe/L9CvZYrT4SjeTpN13QyixK/img.jpg?width=60&amp;amp;height=40&amp;amp;face=0_0_60_40,https://scrap.kakaocdn.net/dn/boATBR/hyIS3ExnYq/NmiweSP92zcz8dzLK8MIlk/img.jpg?width=34&amp;amp;height=60&amp;amp;face=0_0_34_60');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;MLkit 라이브러리와 CameraX를 사용하여 Vision 앱 만들기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;구글의 mlkit 라이브러리와 cameraX를 사용하여 간단하게 vision 구현하기&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;medium.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;ML Kit &lt;/span&gt;라이브러리 가이드&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;a href=&quot;https://developers.google.com/ml-kit/vision/face-detection/android&quot;&gt;https://developers.google.com/ml-kit/vision/face-detection/android&lt;/a&gt; &lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1610088569443&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Detect faces with ML Kit on Android &amp;nbsp;|&amp;nbsp; Google Developers&quot; data-og-description=&quot;You can use ML Kit to detect faces in images and video. See the ML Kit quickstart sample on GitHub for an example of this API in use. There are two ways to integrate face detection: a bundled model which is part of your app and an unbundled model that depe&quot; data-og-host=&quot;developers.google.com&quot; data-og-source-url=&quot;https://developers.google.com/ml-kit/vision/face-detection/android&quot; data-og-url=&quot;https://developers.google.com/ml-kit/vision/face-detection/android?hl=ko&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/lolra/hyIQZ4PoXe/qrRMM3ASK0uWCcMHF2dNV1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://developers.google.com/ml-kit/vision/face-detection/android&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developers.google.com/ml-kit/vision/face-detection/android&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/lolra/hyIQZ4PoXe/qrRMM3ASK0uWCcMHF2dNV1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;Detect faces with ML Kit on Android &amp;nbsp;|&amp;nbsp; Google Developers&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;You can use ML Kit to detect faces in images and video. See the ML Kit quickstart sample on GitHub for an example of this API in use. There are two ways to integrate face detection: a bundled model which is part of your app and an unbundled model that depe&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;developers.google.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;2.&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;화장품 인식&lt;span&gt;(&lt;/span&gt;사물인식&lt;span&gt;, &lt;/span&gt;영상처리&lt;span&gt;/OCR)&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;1)&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;선행 어플&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;▷ 네이버 스마트렌즈&lt;/p&gt;
&lt;p&gt;&lt;span&gt;- &lt;/span&gt;딥러닝 기반의 이미지 분석기술&lt;/p&gt;
&lt;p&gt;&lt;span&gt;- &lt;/span&gt;문서&lt;span&gt;, &lt;/span&gt;검색 쿼리&lt;span&gt;, &lt;/span&gt;이미지 &lt;span&gt;DB&lt;/span&gt;등에 &lt;span&gt;SCOPIC &lt;/span&gt;기술 접목&lt;/p&gt;
&lt;p&gt;&lt;span&gt;* SCOPIC&lt;/span&gt;기술&lt;span&gt;: &lt;/span&gt;딥러닝 기반의 이미지 분석 기술로&lt;span&gt;, &lt;/span&gt;이미지 자체의 정보와 주변 텍스트 정보를 함께 사용&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;▷ &lt;/span&gt;쓱 렌즈&lt;span&gt;(SSG.COM&lt;/span&gt;앱 &lt;span&gt;or &lt;/span&gt;신세계몰 앱에서 사용 가능&lt;span&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;- OCR &lt;/span&gt;기술을 이용한 사진에 있는 글자 인식 기능&lt;/p&gt;
&lt;p&gt;&lt;span&gt;- &lt;/span&gt;추천하는 상품종류가 없을 경우 다른 상품종류로 대체해서 검색&lt;span&gt;(&lt;/span&gt;정확도가 낮음&lt;span&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span&gt;2) &lt;/span&gt;참고 정보&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;1.&lt;a href=&quot;https://brunch.co.kr/@kakao-it/260&quot;&gt;https://brunch.co.kr/@kakao-it/260&lt;/a&gt; : CNN &lt;/span&gt;이미지 검색&lt;span&gt;(&lt;/span&gt;카카오 꽃 검색&lt;span&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1610088594838&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;꽃이름이 궁금해? 다음 앱 AI에 물어봐!&quot; data-og-description=&quot;[카카오AI리포트] 변민우, 홍은빈 | 때늦은 꽃샘추위가 지나가고 완연한 봄이 도래한 듯 전국 곳곳에서 설레는 봄꽃 축제 소식이 들려왔다. 길을 걷다 주위를 둘러보면 민들레, 철쭉 등 익숙한 꽃&quot; data-og-host=&quot;brunch.co.kr&quot; data-og-source-url=&quot;https://brunch.co.kr/@kakao-it/260&quot; data-og-url=&quot;https://brunch.co.kr/@kakao-it/260&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dAPun3/hyIQXlFOqt/xbGqbF6P06Iym8Nzy4h04k/img.png?width=1280&amp;amp;height=853&amp;amp;face=0_0_1280_853,https://scrap.kakaocdn.net/dn/iyzrP/hyIQ28loyL/CSvOweOexO8gWy5USu12m0/img.png?width=500&amp;amp;height=500&amp;amp;face=0_0_500_500,https://scrap.kakaocdn.net/dn/cXkj2J/hyIS3Li98r/N5vOkJI8iEEtEHYqQMjkI0/img.jpg?width=1280&amp;amp;height=758&amp;amp;face=0_0_1280_758&quot;&gt;&lt;a href=&quot;https://brunch.co.kr/@kakao-it/260&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://brunch.co.kr/@kakao-it/260&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dAPun3/hyIQXlFOqt/xbGqbF6P06Iym8Nzy4h04k/img.png?width=1280&amp;amp;height=853&amp;amp;face=0_0_1280_853,https://scrap.kakaocdn.net/dn/iyzrP/hyIQ28loyL/CSvOweOexO8gWy5USu12m0/img.png?width=500&amp;amp;height=500&amp;amp;face=0_0_500_500,https://scrap.kakaocdn.net/dn/cXkj2J/hyIS3Li98r/N5vOkJI8iEEtEHYqQMjkI0/img.jpg?width=1280&amp;amp;height=758&amp;amp;face=0_0_1280_758');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;꽃이름이 궁금해? 다음 앱 AI에 물어봐!&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;[카카오AI리포트] 변민우, 홍은빈 | 때늦은 꽃샘추위가 지나가고 완연한 봄이 도래한 듯 전국 곳곳에서 설레는 봄꽃 축제 소식이 들려왔다. 길을 걷다 주위를 둘러보면 민들레, 철쭉 등 익숙한 꽃&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;brunch.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;2.&lt;a href=&quot;http://koreascience.or.kr/article/JAKO201718836883408.page&quot;&gt;http://koreascience.or.kr/article/JAKO201718836883408.page&lt;/a&gt; &lt;/span&gt;&lt;span&gt;: OCR&lt;/span&gt;기반 메뉴인식 앱 관련 논문&lt;/p&gt;
&lt;figure id=&quot;og_1610088600848&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Development an Android based OCR Application for Hangul Food Menu
				-Journal of the Korea Institute of Information and Communi&quot; data-og-description=&quot;Abstract In this paper, we design and implement an Android-based Hangul food menu recognition application that recognizes characters from images captured by a smart phone. Optical Character Recognition (OCR) technology is divided into preprocessing, recogn&quot; data-og-host=&quot;koreascience.or.kr&quot; data-og-source-url=&quot;http://koreascience.or.kr/article/JAKO201718836883408.page&quot; data-og-url=&quot;http://koreascience.or.kr/article/JAKO201718836883408.page&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cHy4mu/hyIQ4d1H9W/pnbJSo4qtWAtPvDwSRmfYk/img.gif?width=250&amp;amp;height=250&amp;amp;face=0_0_250_250&quot;&gt;&lt;a href=&quot;http://koreascience.or.kr/article/JAKO201718836883408.page&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;http://koreascience.or.kr/article/JAKO201718836883408.page&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cHy4mu/hyIQ4d1H9W/pnbJSo4qtWAtPvDwSRmfYk/img.gif?width=250&amp;amp;height=250&amp;amp;face=0_0_250_250');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;Development an Android based OCR Application for Hangul Food Menu -Journal of the Korea Institute of Information and Communi&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Abstract In this paper, we design and implement an Android-based Hangul food menu recognition application that recognizes characters from images captured by a smart phone. Optical Character Recognition (OCR) technology is divided into preprocessing, recogn&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;koreascience.or.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;span&gt;&amp;rArr;&lt;/span&gt; &lt;span&gt;MSER&lt;/span&gt;기법을 이용해서 글자 추출 &lt;span&gt;&amp;rarr;&lt;/span&gt;&lt;span&gt; OCR&lt;/span&gt;무료 엔진인&lt;span&gt; Tesseract-OCR&lt;/span&gt;을 이용해서 글자 인식 &lt;span&gt;&amp;rarr; &lt;/span&gt;&lt;span&gt;음식메뉴에 대한 사전&lt;span&gt; DB&lt;/span&gt;를 이용해서 잘못된 결과 수정&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;3.&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;a href=&quot;https://junyoung-jamong.github.io/computer/vision/2019/02/07/Android-Tesseract-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0.html&quot;&gt;https://junyoung-jamong.github.io/computer/vision/2019/02/07/Android-Tesseract-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0.html&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1610088605181&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Android에서 Tesseract 사용하기 for OCR&quot; data-og-description=&quot;Python에서 Tesseract 사용하기 for OCR에서는 Python 환경에서 Tesseract 사용 방법을 알아 봤다. 이번에는 모바일 환경에서 카메라를 이용해 이미지를 촬영하고, 해당 이미지에 대해 동시에 OCR을 수행하&quot; data-og-host=&quot;junyoung-jamong.github.io&quot; data-og-source-url=&quot;https://junyoung-jamong.github.io/computer/vision/2019/02/07/Android-Tesseract-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0.html&quot; data-og-url=&quot;https://junyoung-jamong.github.io/computer/vision/2019/02/07/Android-Tesseract-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/btJ54p/hyIQU3yqDG/fRoGlKUKMZ0QE3kkugAcbK/img.png?width=1014&amp;amp;height=707&amp;amp;face=0_0_1014_707,https://scrap.kakaocdn.net/dn/brvdhP/hyIQWAhS15/KdKQdDHBfTziOlHEOagr2k/img.png?width=802&amp;amp;height=682&amp;amp;face=0_0_802_682,https://scrap.kakaocdn.net/dn/iCLrl/hyIQZcHvr9/rJvvj2xeD9cI8EmPY4A6dk/img.png?width=799&amp;amp;height=680&amp;amp;face=0_0_799_680&quot;&gt;&lt;a href=&quot;https://junyoung-jamong.github.io/computer/vision/2019/02/07/Android-Tesseract-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://junyoung-jamong.github.io/computer/vision/2019/02/07/Android-Tesseract-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/btJ54p/hyIQU3yqDG/fRoGlKUKMZ0QE3kkugAcbK/img.png?width=1014&amp;amp;height=707&amp;amp;face=0_0_1014_707,https://scrap.kakaocdn.net/dn/brvdhP/hyIQWAhS15/KdKQdDHBfTziOlHEOagr2k/img.png?width=802&amp;amp;height=682&amp;amp;face=0_0_802_682,https://scrap.kakaocdn.net/dn/iCLrl/hyIQZcHvr9/rJvvj2xeD9cI8EmPY4A6dk/img.png?width=799&amp;amp;height=680&amp;amp;face=0_0_799_680');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;Android에서 Tesseract 사용하기 for OCR&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Python에서 Tesseract 사용하기 for OCR에서는 Python 환경에서 Tesseract 사용 방법을 알아 봤다. 이번에는 모바일 환경에서 카메라를 이용해 이미지를 촬영하고, 해당 이미지에 대해 동시에 OCR을 수행하&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;junyoung-jamong.github.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;span&gt;: Android&lt;/span&gt;&lt;span&gt;에서 &lt;span&gt;Tesseract &lt;/span&gt;사용하기&lt;span&gt;. &lt;/span&gt;문자 검출 예시 코드有 &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;- OCR&lt;/span&gt;기술 요약&lt;span&gt;(&lt;a href=&quot;https://www.2e.co.kr/news/articleView.html?idxno=203023&quot;&gt;https://www.2e.co.kr/news/articleView.html?idxno=203023&lt;/a&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1610088607429&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;사진 속 문자를 읽는 기술 - OCR과 오픈소스 - 투이컨설팅&quot; data-og-description=&quot;파이썬(Python) 기반 오픈소스 OCR 모델을 만드는 것을 두 편으로 나누어서 설명한다. 첫 편에서 OCR의 개념 및 기업에서의 효용, 그리고 대표적인 OCR 오픈소스를 소개한다. 다음 편에서는 컴퓨터가 &quot; data-og-host=&quot;www.2e.co.kr&quot; data-og-source-url=&quot;https://www.2e.co.kr/news/articleView.html?idxno=203023&quot; data-og-url=&quot;http://www.2e.co.kr/news/articleView.html?idxno=203023&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/buRCnl/hyIS4XKw2N/5Y4etgkTVGzOLEKm8n57uk/img.jpg?width=1006&amp;amp;height=170&amp;amp;face=0_0_1006_170,https://scrap.kakaocdn.net/dn/LA5YT/hyIQXlFPqA/AkE0KeqvNAyIvMDROdqA40/img.jpg?width=938&amp;amp;height=546&amp;amp;face=0_0_938_546,https://scrap.kakaocdn.net/dn/bkOPO8/hyIS6gXEqA/dwHRHCE1aKmcDLOyluSXSk/img.jpg?width=960&amp;amp;height=464&amp;amp;face=0_0_960_464&quot;&gt;&lt;a href=&quot;https://www.2e.co.kr/news/articleView.html?idxno=203023&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.2e.co.kr/news/articleView.html?idxno=203023&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/buRCnl/hyIS4XKw2N/5Y4etgkTVGzOLEKm8n57uk/img.jpg?width=1006&amp;amp;height=170&amp;amp;face=0_0_1006_170,https://scrap.kakaocdn.net/dn/LA5YT/hyIQXlFPqA/AkE0KeqvNAyIvMDROdqA40/img.jpg?width=938&amp;amp;height=546&amp;amp;face=0_0_938_546,https://scrap.kakaocdn.net/dn/bkOPO8/hyIS6gXEqA/dwHRHCE1aKmcDLOyluSXSk/img.jpg?width=960&amp;amp;height=464&amp;amp;face=0_0_960_464');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;사진 속 문자를 읽는 기술 - OCR과 오픈소스 - 투이컨설팅&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;파이썬(Python) 기반 오픈소스 OCR 모델을 만드는 것을 두 편으로 나누어서 설명한다. 첫 편에서 OCR의 개념 및 기업에서의 효용, 그리고 대표적인 OCR 오픈소스를 소개한다. 다음 편에서는 컴퓨터가&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;www.2e.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;span&gt;: OpenCV&lt;/span&gt;라는 오픈소스가&lt;span&gt; OCR&lt;/span&gt;에서 이미지 전처리와 텍스트 위치 검출에 사용가능&lt;span&gt;(C, JAVA, python&lt;/span&gt;제공&lt;span&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;: Tesseract&lt;/span&gt;라는 오픈소스가 글자인식 부분에서 가장 전통적&lt;span&gt;(&lt;/span&gt;딥러닝 학습 기능이 내장되어 있음&lt;span&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;: google cloud vision, Microsoft Computer Vision&lt;/span&gt;이라는 오픈&lt;span&gt; API&lt;/span&gt;도 높은 정확도를 보임&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;</description>
      <category>머신러닝</category>
      <author>hyeals</author>
      <guid isPermaLink="true">https://hyeals.tistory.com/74</guid>
      <comments>https://hyeals.tistory.com/74#entry74comment</comments>
      <pubDate>Fri, 8 Jan 2021 15:56:06 +0900</pubDate>
    </item>
    <item>
      <title>[백준 15652번] [백트래킹] [JAVA] N과M(4)</title>
      <link>https://hyeals.tistory.com/72</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TAFR8/btqI07puTN9/yeeylacwF8C3KckmVSON50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TAFR8/btqI07puTN9/yeeylacwF8C3KckmVSON50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TAFR8/btqI07puTN9/yeeylacwF8C3KckmVSON50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTAFR8%2FbtqI07puTN9%2FyeeylacwF8C3KckmVSON50%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1600434352851&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Scanner;

public class Main {

    static int N;
    static int M;
    static boolean[] visited;
    static int[] answer;
    static StringBuilder ans = new StringBuilder();

    static void backtracking(int num){
        if(num==M){
            for(int i=0; i&amp;lt;M; i++){
                ans.append(answer[i]+&quot; &quot;);
            }
            ans.append(&quot;\n&quot;);
            return;
        }

        for(int i=1; i&amp;lt;=N; i++){
            if(!visited[i]){
                answer[num] = i;
               if(num!=0 &amp;amp;&amp;amp; answer[num] &amp;lt; answer[num-1]){
                    continue;
                }
                backtracking(num+1);
            }
        }
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        N = sc.nextInt();
        M = sc.nextInt();
        visited = new boolean[N+1];
        answer = new int[N+1];

        backtracking(0);

        System.out.println(ans);
    }
}
&lt;/code&gt;&lt;/pre&gt;</description>
      <category>백준</category>
      <author>hyeals</author>
      <guid isPermaLink="true">https://hyeals.tistory.com/72</guid>
      <comments>https://hyeals.tistory.com/72#entry72comment</comments>
      <pubDate>Fri, 18 Sep 2020 22:05:24 +0900</pubDate>
    </item>
    <item>
      <title>[백준 15651] [백트래킹] [JAVA] N과M(3)</title>
      <link>https://hyeals.tistory.com/71</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xGMKJ/btqH7aVAMah/Q2hOG6fa72bE9KfpUdOnc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xGMKJ/btqH7aVAMah/Q2hOG6fa72bE9KfpUdOnc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xGMKJ/btqH7aVAMah/Q2hOG6fa72bE9KfpUdOnc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxGMKJ%2FbtqH7aVAMah%2FQ2hOG6fa72bE9KfpUdOnc1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1599582003912&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Scanner;

public class Main {

    static int N;
    static int M;
    static int[] answer;
    static StringBuilder ans = new StringBuilder();

    static void backtracking(int num){
        if(num==M){
            for(int i=0; i&amp;lt;M; i++){
                ans.append(answer[i]+&quot; &quot;);
            }
            ans.append(&quot;\n&quot;);
            return;
        }

        for(int i=1; i&amp;lt;=N; i++){
                answer[num] = i;
                backtracking(num+1);
        }
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        N = sc.nextInt();
        M = sc.nextInt();
        answer = new int[N+1];

        backtracking(0);

        System.out.println(ans);
    }
}
&lt;/code&gt;&lt;/pre&gt;</description>
      <category>백준</category>
      <author>hyeals</author>
      <guid isPermaLink="true">https://hyeals.tistory.com/71</guid>
      <comments>https://hyeals.tistory.com/71#entry71comment</comments>
      <pubDate>Wed, 9 Sep 2020 01:19:50 +0900</pubDate>
    </item>
    <item>
      <title>[백준 15650] [백트래킹] [JAVA] N과M(2)</title>
      <link>https://hyeals.tistory.com/70</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GnyKJ/btqH3xwddOY/jrYbKkd7kLB7B1i9N4hsJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GnyKJ/btqH3xwddOY/jrYbKkd7kLB7B1i9N4hsJ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GnyKJ/btqH3xwddOY/jrYbKkd7kLB7B1i9N4hsJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGnyKJ%2FbtqH3xwddOY%2FjrYbKkd7kLB7B1i9N4hsJ0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1599535127870&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Scanner;

public class Main {

    static int N;
    static int M;
    static boolean[] visited;
    static int[] answer;
    static StringBuilder ans = new StringBuilder();

    static void backtracking(int num){
        if(num==M){
            for(int i=0; i&amp;lt;M; i++){
                ans.append(answer[i]+&quot; &quot;);
            }
            ans.append(&quot;\n&quot;);
            return;
        }

        for(int i=1; i&amp;lt;=N; i++){
            if(!visited[i]){
                visited[i] = true;
                answer[num] = i;
                if(num!=0 &amp;amp;&amp;amp; answer[num] &amp;lt; answer[num-1]){ // 15649번과의 차이: 지금 값이 앞에 있는 값보다 작을 때 다시 FOR문으로 돌아가기 
                    visited[i] = false;
                    continue;
                }
                backtracking(num+1);
                visited[i] = false;
            }
        }
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        N = sc.nextInt();
        M = sc.nextInt();
        visited = new boolean[N+1];
        answer = new int[N+1];

        backtracking(0);

        System.out.println(ans);
    }
}
&lt;/code&gt;&lt;/pre&gt;</description>
      <category>백준</category>
      <author>hyeals</author>
      <guid isPermaLink="true">https://hyeals.tistory.com/70</guid>
      <comments>https://hyeals.tistory.com/70#entry70comment</comments>
      <pubDate>Tue, 8 Sep 2020 12:26:46 +0900</pubDate>
    </item>
    <item>
      <title>[백준 15649] [백트래킹] [JAVA] N과M(1)</title>
      <link>https://hyeals.tistory.com/69</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4Z2ab/btqH699AQfB/iaoSzv8eRNMbBrAuwuL3Uk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4Z2ab/btqH699AQfB/iaoSzv8eRNMbBrAuwuL3Uk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4Z2ab/btqH699AQfB/iaoSzv8eRNMbBrAuwuL3Uk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4Z2ab%2FbtqH699AQfB%2FiaoSzv8eRNMbBrAuwuL3Uk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1599533309871&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.Scanner;

public class Main {

    static int N;
    static int M;
    static boolean[] visited;
    static int[] answer;
    static StringBuilder ans = new StringBuilder();

    static void backtracking(int num){
        if(num==M){
            for(int i=0; i&amp;lt;M; i++){
                ans.append(answer[i]+&quot; &quot;);
            }
            ans.append(&quot;\n&quot;);
            return;
        }

        for(int i=1; i&amp;lt;=N; i++){
            if(!visited[i]){
                visited[i] = true;
                answer[num] = i;
                backtracking(num+1);
                visited[i] = false;
            }
        }
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        N = sc.nextInt();
        M = sc.nextInt();
        visited = new boolean[N+1];
        answer = new int[N+1];

        backtracking(0);

        System.out.println(ans);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;- 방문했는지 체크한 이유: 중복을 허용하지 않기 때문에&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;+ 추가적으로 공부해야 할 부분: 메모리와 시간 줄일 수 있는 방법&lt;/p&gt;</description>
      <category>백준</category>
      <author>hyeals</author>
      <guid isPermaLink="true">https://hyeals.tistory.com/69</guid>
      <comments>https://hyeals.tistory.com/69#entry69comment</comments>
      <pubDate>Tue, 8 Sep 2020 11:50:10 +0900</pubDate>
    </item>
  </channel>
</rss>