hyeals study
구글 TTS API를 안드로이드에서 써보기!(2??) 본문
지난 포스팅에서 구글 TTS API를 안드로이드에 써보는 걸 시도해봤는데 여기에 RxJava를 이용해서 리액티브한 요소를 한 번 집어넣어보면 어떨까해서 소소한 2탄을 준비했다. ㅎㅎ
목표는 EditText의 입력을 RxTextView를 이용해서 Observable로 만들어서 입력에 대한 변화를 관찰하게 만든다. 그 다음 이걸 Disposable과 함께 사용해서 좀 더 리액티브하게, 간단한 코드로 사용할 수 있도록 하는 것이다!
*RxTextView는 EditText를 Observable로 만들어준다.(RxBinding라이브러리에 포함되어 있다.)
2021/02/10 - [안드로이드] - 구글 TTS API를 안드로이드에서 써보기!
일단 gradle에 아래와 같이 라이브러리들을 추가해줘야한다.
//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'
그리고 activity_main.xml에 TextView를 추가해줘야 한다.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<EditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:inputType="textPersonName" />
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:textAppearance="@style/TextAppearance.AppCompat.Large"></TextView>
<Button
android:id="@+id/button"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:text="음성 출력" />
</LinearLayout>
요정도 추가해주고 저번 MainActivity.java코드를 아래와 같이 조금 수정해준다.
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 -> result_text.setText("INPUT: " + 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, "id1");
}
@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("TTS", "This Language is not supported");
}else{
speak_out.setEnabled(true);
speakOut();
}
}else{
Log.e("TTS", "Initialization Failed!");
}
}
}
이렇게 하면 resultText에 EditText에 입력한 문자열?이 결과로 출력된다. 입력값이 변화함에 따라 함께 계속 바뀐다!
이런 방식은 UI이벤트가 Rxjava로 인해 data stream형태로 출력되는것을 나타낸다!
아마 더 복잡한 내용을 다룰 수 있을 것 같다. (공부하면 할수록 헷갈리는 부분이 많아서 책 한 권사서 정리하는것도 나쁘지 않을 것 같다 ㅠ)
* Disposable을 선언한 이유: 메모리 누수를 방지하기 위해서 Destroy부분에서 꼭 .dispose()를 이용해서 구독을 끝내야 한다.
아래는 실행화면이다.
'안드로이드' 카테고리의 다른 글
구글 TTS API를 안드로이드에서 써보기! (1) | 2021.02.10 |
---|---|
Rxjava를 안드로이드에 적용시켜보기! (0) | 2021.02.08 |
RxJava 사용해보기 (0) | 2021.02.07 |
RxJava??? (0) | 2021.02.06 |
웹툰 바로가기 앱 (0) | 2020.05.24 |