안드로이드 스튜디오 커맨드 빌드 Command Build

반응형
728x170

안드로이드 스튜디오는 일반적인 AVD를 사용한 빌드뿐 아니라

 

gradle을 사용하여 커맨드로 빌드를 할 수 있다

 

https://developer.android.com/studio/build/building-cmdline

 

명령줄에서 앱 빌드  |  Android 개발자  |  Android Developers

Gradle 래퍼 명령줄 도구를 이용하여 Android 프로젝트에서 사용할 수 있는 모든 빌드 작업의 실행 방법을 알아보세요.

developer.android.com

 

하지만 초보자들이 이 문서를 보고 그대로 커맨드를 넣을 경우

 

작동하지 않기 때문에 이 블로그를 쓴다


1. 안드로이드 스튜디오에서 터미널창 열기

 

먼저 터미널 창을 열어야한다

 

안드로이드 스튜디오 하단을 보면 Terminal이 있는데 이를 클릭한다

 

터미널 창을 클릭

 

터미널을 열었을 경우 현재 위치가 현재 열고 있는 프로젝트의 최상위에 있는지 확인한다

 

제일 끝에 프로젝트 이름이 있을 경우 OK!

현재 위치가 현재 프로젝트의 최상위 루트인지 확인한다


2. 현재 프로젝트의 빌드 이름 확인

300x250

안드로이드 스튜디오의 왼쪽 밑을 확인하면

 

"Build Variants" 라는 것이 있다. 이를 클릭하면 다음과 같은 창이 뜬다

 

여기 app의 오른쪽에 적혀있는 stagingBeta라는 것이 빌드 이름이다

 

이건 프로젝트마다 다 다르니 기억해놓는다

 


3. 터미널에서 gradlew 를 사용해서 커맨드 빌드를 한다

 

다음과 같이 입력한다

 

./grdlew assembleStagingBeta

 

즉, assemble을 위에서 확인한 빌드 이름에 붙여줘야 한다

 

그리고 엔터를 누르면

 

이렇게 뜨면서 알아서 빌드가 시작된다 (개인 정보가 있어서 많이 잘랐습니다 ㅠ)

 

이렇게 하면 커맨드 빌드를 하여 Lint error 같은 것들을 확인할 수 있다!

"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."

반응형

댓글()

스마트 워치 GTR4 / GTS4 발매!! 전작과 뭐가 달라졌을까?

반응형
728x170

2년만에 amazfit에서 새로운 스마트워치를 발매했습니다.

 

과연 어떠한 점이 달라졌을까요?

 

하나씩 분석해보겠습니다.


1. 운동 서포트 능력

 

이 부분은 크게 바뀐건 없는거 같습니다.

 

방수 등급 부분도 전작과 동일하고

 

전작 역시 150 가지 정도의 운동을 측정할 수 있었으니까요

 

자동 운동 감지 기능도 거의 동일합니다.

 

전작 같은 경우에도 비슷한 종류의 운동을 자동으로 감지해주는 기능이 있었고

 

(사실 일반인은 걷기랑 달리기 이외에는 거의 사용하지 않는 기능이라고 봐야....)

 

대신 이제 근력 운동에 대해 좀 더 자세한 데이터를 보여줍니다

 

이 부분은 확실히 헬창들에게 더 좋은거 같네요

 

갤럭시 워치와 애플워치가 건강쪽으로 좀 더 힘을 넣는다면

 

amazfit의 스마트 워치는 확실히 운동쪽에 좀 더 힘을 싣는 방향으로 가는거 같습니다

 

더 정확해진 GPS

 

일단 설명만 보면 시중에 판매하는 GPS 전용 기기의 99% 만큼의 정확도를 자랑한다고 합니다

 

또한 전작에서는 5개의 GPS를 이용해서 위치를 인식했다면

 

이번에는 6개의 GPS를 사용해서 위치를 인식한다고 합니다.

 

(지금 당장은 아니고 OTA 업데이트를 통해 지원할 계획이라고 함)

 

이 외에 한 두 가지 더 있긴한데

 

중요한 정보가 아니라 생략하겠습니다.


2. 디자인

GTS4의 경우에는 조금 바뀌었습니다!

 

GTS4의 옆면 디자인
GTS4의 정면 디자인

 

가장 크게 바뀐 점이라고 하면 크라운 부분에 이제는 amazfit의 로고가 들어가네요

 

GTS4의 디스플레이 정보

디스플레이는 거의 똑같은 거를 사용한거 같습니다.

크기, PPI, 화면 비율 전부 전작이랑 동일하거나 비슷합니다.

 

제일 큰 GRS4의 디자인 면에서 제일 크게 바뀐 점은 사각형의 형태인거 같습니다.

 

GTS4와 GTS3의 디자인 차이

이제는 애플워치와는 꽤 다른 형태를 하는 디자인을 갖게 되었습니다.

 

뭔가 좀 더 고급스러워졌으면서 살짝 호불호가 갈릴 수 있는 디자인으로 변경되었네요

 

이제 슬슬 amafit의 GTS라는 폼펙터를 갖춘 느낌이 나서 저는 개인적으로 더 좋은거 같습니다.

 

(어디가서 짭플 워치라는 말은 이제 피할 수 있겠네요 ㅋㅋ)

 


GTR4는 꽤 많이 바뀌었습니다.

300x250

 

GTR4는 갤럭시 워치4나 액티브2 처럼 캐주얼한 느낌이 있었는데

 

이제는 클래식한 느낌의 시계가 됐습니다.

 

GTR4의 디자인

전작대비 크라운이 커졌고 아래쪽의 물리 버튼도 갤럭시 워치4 처럼 슬림한 버튼으로 바뀌었네요


워치 페이스 또한 많이 늘어났습니다.

 

전작에서 인기가 있었던 애니메이션 워치 페이스가 30개로 늘어났고

 

원하는 사진을 넣어 워치페이스를 만들 수 있게 되었습니다.

GTS4의 워치 페이스 정보

 

GTR4는 좀 더 많은 200개의 워치 페이스를 지원합니다.

(하지만 애니메이션 워치 페이스는 동일함)

 

GTR4의 워치 페이스


3. 측정 기능

바이오 트래커 4.0이 출시되었으며

 

전작 대비 33% 더 많은 데이터를 수집하고 더 정확하다고 합니다.

 

특히 운동중 측정하는 심박수 측정이 매우 정확해졌다고 하네요

 

바이오 트래커 4.0

또한 기존에는 심박수, 산소 포화농도만 24시간 측정할 수 있었지만

 

이제는 호흡수까지 지속적으로 측정할 수 있게 되었습니다.

 


4. OS 업데이트

제일 기대되면서 제일 실망한 부분입니다 ㅠㅠ

 

솔직히 1번쯤은 늦더라도 전작꺼까지 업데이트 해줄거라 생각했는데 바로 버려지는군요 ㅠ

 

전작에 대한 OS 업데이트는 없다고 합니다. 

(직접 물어봤음)

하지만, 디자인이 바뀌거나 편의성이 조금 더 좋아지는거 외에 크게 변한건 없는거 같습니다.

 


5. 배터리 타임

배터리 타임은 오히려 전작보다 줄었습니다.

 

일단 메이커 스펙만 봐도 줄어든 것을 확인할 수 있습니다.

 

GTS4의 배터리 타임

 

GTS3의 배터리 타임

 

아마 동일한 배터리를 사용했는데 추가된 센서 및 기능은 많아지니 배터리 타임이 더 줄어든거 같네요

 

저는 amazfit을 고르는 이유중 가장 큰 이유가 배터리 타임이라고 생각했는데

 

이 부분은 조금 아쉽네요 ㅠ

 


6. 가격

 

일단 한국에 정발이 되진 않았지만

 

미국 가격만 보면 전작과 거의 비슷할거라 생각합니다.

 

200 달러면 거의 25만원 이상일건데...

 

가격이 조금 아쉽긴하네요 ㅠ

 

사실 이 가격이면 갤럭시 워치 사지.... 라고 생각하는 사람들이 많아서

 

참 애매한 가격인거 같습니다.

 


7. 총평

 

큰 변화는 없는거 같습니다.

 

굳이 찾자면 디자인 변화, 새로운 OS 적용 정도네요

 

2년만에 새로운 제품이 나와서 많이 기대 했는데 

 

AP도 동일한 AP를 사용한거 같고

 

배터리 타임은 오히려 줄었고

 

OS도 구글OS나 애플워치OS 처럼 유저들이 앱을 만들고 발전 시킬 수 있는 형태면 더 좋을건데

 

amazfit에서 제공하는 기능만 사용할 수 있고....

 

물론 이 점은 전작도 동일하지만요 ㅎㅎ

 

디스플레이도 동일한거 같고

 

그래도 실제로 나온 것을 봐야 좀 더 정확히 알 수 있을거 같습니다!

 

감사합니다!

"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."

반응형

댓글()

VPN으로 로아하기 100% 되는 방법(2022년 4월 테스트 완료)

반응형
728x170

로스트 아크(스마게)의 경우 해외 유저의 출입을 막기 위해 다분한 노력을 하고 있습니다.

 

보통 국산 게임이나 다른 회사의 게임의 경우 해외 ip를 차단하더라도 

 

유명 회사의 VPN을 쓰면 접속 가능한 경우가 대부분입니다.

 

하지만, 로아의 경우

 

Express VPN, SurfShark VPN, Nord VPN 등 여러 유명 VPN 회사들의 IP까지 차단하고 있습니다.

 

그래서 인터넷을 보면 이러한 유명 VPN을 사용해도 접속하지 못하는 경우가 있습니다.

 

그렇기 때문에 반대로 무료 VPN의 경우 접속 가능한 경우가 생깁니다.

 

하지만.... 무료 VPN은 진짜 위험하죠

 

서버 관리자가 여러분들이 어느 사이트에 접속중인지 다 알 수 있고

 

여러 보안상 위험도 있고...

 

심하면 범죄에 연루될 가능성도 있죠

 

여기서 안전하게 100% 방법으로 로아를 접속할 수 있는 방법은 2개입니다.


1. 유명하지 않은 유료 VPN 사용

 

아직 로스트아크(스마게)에서 차단하지 않은 유료 VPN 회사를 찾는겁니다.

 

하지만.... 이 방법은 시간이 지나면 들킬 가능성이 있습니다.

 

또한 스마게는 해외 유저에 대해 정책 위반으로 생각하기 때문에

 

[일시 정지] 같은게 아니라 [영구 정지]를 바로 때려버립니다.

 

그래서 100% 접속할 수 있을지 몰라도 안전하지 않은 방법이며 시간과 돈도 꽤 많이 들어갑니다.

 


2. 한국에 있는 공유기를 VPN 서버로 만들기

 

제일 좋은 방법입니다.

 

하지만, 제일 큰 단점은 한국에 누군가 지인이 있어야합니다.

 

즉, 가족 or 친구의 공유기가 필요합니다.

 

한국에서는 대부분 [IPTIME]이라는 공유기를 많이 사용하기 때문에

 

이 브랜드를 이용하여 설정하는 방법을 알려주겠습니다.

 

공유기를 이용해 VPN 서버를 구축하기 위해서, 먼저 공유기 설정에 들어가 주어야 합니다.

우선 검색 메뉴를 이용해서 'cmd' 또는 '명령 프롬프트'를 검색하여 명령 프롬프트를 켜 주세요.

명령 프롬프트에서 'ipconfig'이라는 명령어를 입력하고 엔터키를 누르면, 현재 컴퓨터에 할당된 내부 IP 정보들이 쭉 나오게 됩니다.

여기서 우리가 주목해 주셔야 할 것은 저 '기본 게이트웨이'에 쓰여져 있는 항목인데, 저 기본 게이트웨이의 주소를 잘 기억해 두세요.

아까 명령 프롬프트에 나왔던 기본 게이트웨이 주소를 인터넷 주소창에 치고 접속해 봅시다.

그럼 위 사진처럼 공유기 모델명과 함께 설정 페이지가 나오게 됩니다. 여기서 맨 왼쪽에 있는 '관리도구'를 눌러주세요.

그런 다음, 왼쪽의 사이드 메뉴에서 [고급 설정] - [특수기능] - [VPN 서버설정]을 차례대로 클릭해 주세요.

여기서 먼저, 위쪽의 '동작 모드' 란에서는 [실행]에, '암호화(MPPE)' 란에서는 [암호화 사용함]에 체크를 해 주시고, 최종적으로 밑의 [적용]을 눌러 마무리해주시기 바랍니다.

이제 VPN 서버 접속을 위한 계정을 만들 차례입니다.

VPN 접속 계정VPN 접속 암호를 임의로 설정해 주시고, 할당될 IP 주소는 일반적인 경우에는 4번째 칸만 임의대로 채워주시고 나머지 칸들은 그냥 그대로 놔두시면 됩니다. (4번째 칸은 2~254까지 설정 가능)

참고로 4번째 칸의 주소를 설정할 때, 되도록 200번대 이후로 설정해 두시는 것을 추천해 드립니다. 너무 앞번대의 주소로 설정하게 되면 다른 앞번대의 주소를 할당받아 연결된 기기들과 충돌이 일어날 수도 있기 때문입니다.

최종적으로 목록에 생성했던 계정이 표시된다면, 이렇게 VPN 서버 구축은 완료되었습니다.

그런데 아직 여기서 끝난 것이 아닙니다.

뒤에서도 다루게 되겠지만 공유기의 외부 IP 주소를 입력하여 VPN 서버에 접속을 하게 되는데, 숫자투성이인 IP 주소는 영 익숙치 않죠.

그래서 DDNS 기능을 이용해, 익숙치 않은 IP 주소 대신 도메인 주소를 이용하여 외부에서 공유기에 접속할 수 있도록 해보겠습니다.

DDNS 도메인 설정하기

관리 도구의 왼쪽 사이드 메뉴에서 [고급 설정] - [특수기능] - [DDNS 설정]을 차례대로 클릭해 보도록 하겠습니다.

혹시 공유기 설정 화면에 접속하는 법을 찾고 계시다면 윗부분를 참조하세요.

그런 다음, 윗부분에서 원하는 호스트 이름과 등록에 필요한 사용자 ID, 사용자 암호를 채워주시고, [추가]를 눌러 마무리해주세요.

호스트 이름은 '(name).iptime.org'의 형식으로 써주셔야 하며, 사용자 ID는 자주 사용하는 이메일 주소를 입력해 주세요. 나중에 잊어버린 암호를 찾을 때 도움이 됩니다.

추가를 완료하고 아래의 목록에서 [갱신] 버튼을 눌러 등록한 호스트의 접속상태가 '정상 등록'으로 표시되는 것을 보셨다면, DDNS 설정까지 성공적으로 끝난 것입니다. 수고하셨습니다!

300x250

3. VPN에 접속하기

 

먼저 윈도우키를 누르고 VPN을 검색해줍니다.

 

이제 VPN 연결 추가를 선택합니다.

 

VPN 공급자 : 기본

연결 이름 : 자유롭게 작성

서버 이름 또는 주소 : 자신의 공인 IP나 DDNS 주소 입력

VPN 종류 : 설정한 VPN 종류 선택

미리 공유한 키 : 설정한 암호 입력 (다른 VPN종류 사용시 설정이 달라집니다.)

사용자 이름 : IPTIME에서 설정한 계정 입력 (다른 VPN종류 사용시 설정이 달라집니다.)

암호 : IPTIME에서 설정한 계정 암호 입력 (다른 VPN종류 사용시 설정이 달라집니다.)

 

이제 저장을 누르고 연결버튼을 눌러봅시다.

 


4. VPN 접속 시 에러가 발생할 때

 

VPN에 접속할 때 아래와 같이 에러가 발생할 가능성이 있습니다.

 

 

이런 에러가 발생할 경우 아래와 같이 따라하면됩니다.

 

제어판에 들어갑니다.

 

 

"네트워크 상태 및 작업 보기"에 들어갑니다.

 

"어댑터 설정 변경"에 들어갑니다.

 

"어댑터 설정 변경"에 들어가면 아까 VPN 설정으로 만들어진 VPN 연결 어댑터가 만들어져 있습니다.

 

이를 "우클릭 -> 속성"으로 들어갑니다.

 

 

"보안" 탭에서 VPN 종류를 "PPTP"로 설정하고 "확인"을 클릭합니다

 

그리고나서 다음의 경로로 접속을 해주세요.


C:\Users\daehyun\AppData\Roaming\Microsoft\Network\Connections\Pbk

 

접속하신 후 rasphone notepad(메모장)으로 열어주세요.

 

(메모장으로 여는 방법)

 

시작을 누르신 후, notepad를 타이핑하시고 엔터를 쳐주세요!

 

엔터를 누르신 후, 메모장이 열리면 그곳으로 rasphone를 드래드&드롭 하면됩니다.

 

 

메모장으로 열으셨으면 DataEncryption=8을 찾아,

DataEncryption=256으로 바꾸면됩니다.

 

 

수정한 내용을 저장한 후

 

다시 VPN에 접속하면 잘 될겁니다!

 


주의사항

접속하는 컴퓨터(클라이언트)가 IPv6나 transix 방식의 접속을 하고 있다면

 

자신이 IPv6이나 transix 방식을 사용하고 있는지 알아보려면

 

아래의 두 가지 방법으로 알아볼 수 있습니다.

 

1. cmd의 ipconfig 커맨드로 IPv6에 IP가 할당되어있는지 확인 = IPv6 방식 사용중

 

2. 인터넷 회사에 직접 문의 = IPv6인지 trasix 방식을 사용중인지 가르쳐줌

 

위와 같은 방식으로 인터넷을 접속중이라면 제가 가르쳐드린 방법으로는 접속할 수 없습니다 ㅠㅠ

"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."

반응형

댓글()

[초급]안드로이드 DataStore 사용방법 A to Z

반응형
728x170

이전에 안드로이드에서 사용했던 

 

PreferenceDataStore는 API29부터 deprecated되어있다

 

그 이후 비슷한 SharedPreferen라는 것이 있는데 얘보다 더 좋은 놈이 나왔다

 

그게 바로

 

DataStore이다!!


1. 기존의 SharedPreference와 비교했을 때 장단점

 

SharedPreference와 DataStore 비교

가장 큰 차이점은 다음과 같다

 

DataStore는 Flow를 통해 데이터를 collect하여 받을 수 있다!

 

이는 상당히 큰 장점이다

 

그 이유는 어떠한 데이터를 DataStore를 통해 넣었고

 

특정 위치에서 해당 데이터를 collect 하고 있었다면

 

데이터를 저장한 순간 인지할 수 있기 때문이다!

300x250

2. 사용방법

 

https://developer.android.com/jetpack/androidx/releases/datastore?hl=ko 

 

DataStore  |  Android 개발자  |  Android Developers

컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. DataStore 비동기적이고 일관된 트랜잭션 방식으로 데이터를 저장하여 SharedPreferences의 취약점을 극복하세요.

developer.android.com

 

일단 사용을 하기 위해선 depenedency 정의가 필요하다

dependencies{

    // Preferences Data Store
    implementation "androidx.datastore:datastore-preferences:1.0.0-alpha07"
    implementation "androidx.datastore:datastore-core:1.0.0-alpha07"

    // Preferences Data Store를 사용하기 위해선 Coroutine이 필요함
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
}

먼저 DataStore를 사용하기 위한 depenedency 와 코루틴을 사용하기 위한 depenedency 가 필요하다

 

그럼 이제 사용해보겠다

 

<layout 정의>

 

먼저 레이아웃은 그림과 같이 대충 정의한다 (참고로 main_activity.xml이다)

 

main_activity.xml

1. EditText에 데이터를 입력한다

2. save 버튼을 통해 dataStore에 입력한 값을 저장한다

3. "READ TEXT", "READ INT"를 통해 데이터를 읽어온다

4. 읽어온 데이터는 TextView에 출력한다

 

그 다음으로는 MainActivity를 정의한다

 

 

<MainActivty.kt>

 

MainActivity의 전체 코드는 제일 아래에 적어놓겠다

 

먼저 전역 변수로 DataStore를 컨트롤할 dataStore라는 인스턴트

 

dataStore의 이름은 보다시피 "settings"로 했다

 

DataStore를 저장하거나 읽어올 객체를 만든다 = stringKey, numberKey

class MainActivity : AppCompatActivity() {

    private val dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")
    private val stringKey = stringPreferencesKey("textKey")
    private val numberKey = intPreferencesKey("numberKey")

 

다음으로 

 

저장 버튼에 대한 정의를 한다

 

정규식을 사용하여 입력한 값이 String 형태인지 아니면 Int 형태인지 확인한다

 

(정규식이 뭔지 모른다면?? 아래 링크 참조)

https://mmol.tistory.com/272

 

코틀린 안드로이드 정규식(Regex) 활용하기 -기본부터 심화

안드로이드에서 정규식은 주로 회원가입 같이 입력한 값이 특정한 양식을 따르는지 확인할 때 주로 사용됩니다. 1. 기본 개념 및 양식 ^ : 문자열의 시작을 의미. $ : 문자열의 끝을 의미.  . : 문

mmol.tistory.com

 

이렇게 따로 나누어서 저장하는 이유는 Int인지 String인지에 따라 사용해야하는 함수가 다르기 때문이다

 

(Int는 setInt로 String은 setText로 내가 커스텀한 함수를 사용해서 저장할거기 때문)

 

DataStore의 저장은 비동기로 이루어지기 때문에 여기서 Coroutine을 사용해야한다

binding.save.setOnClickListener {
            val data = binding.editText.text.toString()
            val regex = Regex("-?\\d+(\\.\\d+)?")

            if (data.isNotEmpty()) {
                CoroutineScope(Dispatchers.Main).launch {
                    if (regex.matches(data)){
                        // 숫자일 경우
                        Log.d("MainActivity", "숫자 저장")
                        setInt(data.toString().toInt())
                    }
                    else {
                        // 문자일 경우
                        Log.d("MainActivity", "문자열 저장")
                        setText(data.toString())
                    }
                }
            } else {
                Toast.makeText(this, "무언가를 입력하세요", Toast.LENGTH_SHORT).show()
            }
        }
        
private suspend fun setText(text: String) {
    this.dataStore.edit { preferences ->
        preferences[stringKey] = text
    }
}

private suspend fun setInt(number: Int) {
    this.dataStore.edit { preferences ->
        preferences[numberKey] = number
    }
}

 

다음으로 저장한 데이터를 꺼내본다

 

여기서 catch를 사용한 이유는 혹시 위에서 찾으려고 하는 dataStore의 이름 "settings"가 없다면

 

바로 에러를 띄우기 때문이다

 

그렇기 때문에 값을 저장하지 않고 데이터를 읽으려고 하면 에러가 발생하기 때문에 catch를 사용했다

 

그리고 map 함수를 사용해서 혹시 해당 preference에 아무 값이 없다면 즉, null이라면 ""을 넣어주게 했다

 

정상적으로 불러왔다면 textData에는 저장한 String 데이터가 Flow 형태로 들어있을 것이다.

 

그렇기 때문에 textData를 collect해서 해당 값을 사용할 수 있게된다

 

Int 부분도 동일하다

 

binding.readText.setOnClickListener {
        val textData: Flow<String> = this.dataStore.data
            .catch { exception ->
                if (exception is IOException) {
                    emit(emptyPreferences())
                } else {
                    throw exception
                }
            }
            .map { preferences ->
                preferences[stringKey] ?: ""
            }
        CoroutineScope(Dispatchers.Main).launch {
            textData.collect {
                binding.textView.text = it
            }
        }
    }

    binding.readInt.setOnClickListener {
        val intData: Flow<Int> = this.dataStore.data
            .catch { exception ->
                if (exception is IOException) {
                    emit(emptyPreferences())
                } else {
                    throw exception
                }
            }
            .map { preferences ->
                preferences[numberKey] ?: 0
            }
        CoroutineScope(Dispatchers.Main).launch {
            intData.collect {
                binding.textView.text = it.toString()
            }
        }
    }
}

 

<결과>

 

String 데이터를 저장하고 불러오기
Int 데이터를 저장하고 불러오기


3. MainActivity의 전체 코드

import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.*
import androidx.datastore.preferences.preferencesDataStore
import com.example.selftest.databinding.ActivityMainBinding
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import java.io.IOException

class MainActivity : AppCompatActivity() {

    private val dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")
    private val stringKey = stringPreferencesKey("textKey")
    private val numberKey = intPreferencesKey("numberKey")
    private val booleanKey = booleanPreferencesKey("booleanKey")

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.save.setOnClickListener {
            val data = binding.editText.text.toString()
            val regex = Regex("-?\\d+(\\.\\d+)?")

            if (data.isNotEmpty()) {
                CoroutineScope(Dispatchers.Main).launch {
                    if (regex.matches(data)) {
                        // 숫자일 경우
                        Log.d("MainActivity", "숫자 저장")
                        setInt(data.toString().toInt())
                    } else {
                        // 문자일 경우
                        Log.d("MainActivity", "문자열 저장")
                        setText(data.toString())
                    }
                }
            } else {
                Toast.makeText(this, "무언가를 입력하세요", Toast.LENGTH_SHORT).show()
            }
        }

        binding.readText.setOnClickListener {
            val textData: Flow<String> = this.dataStore.data
                .catch { exception ->
                    if (exception is IOException) {
                        emit(emptyPreferences())
                    } else {
                        throw exception
                    }
                }
                .map { preferences ->
                    preferences[stringKey] ?: ""
                }
            CoroutineScope(Dispatchers.Main).launch {
                textData.collect {
                    binding.textView.text = it
                }
            }
        }

        binding.readInt.setOnClickListener {
            val intData: Flow<Int> = this.dataStore.data
                .catch { exception ->
                    if (exception is IOException) {
                        emit(emptyPreferences())
                    } else {
                        throw exception
                    }
                }
                .map { preferences ->
                    preferences[numberKey] ?: 0
                }
            CoroutineScope(Dispatchers.Main).launch {
                intData.collect {
                    binding.textView.text = it.toString()
                }
            }
        }
    }

    private suspend fun setText(text: String) {
        this.dataStore.edit { preferences ->
            preferences[stringKey] = text
        }
    }

    private suspend fun setInt(number: Int) {
        this.dataStore.edit { preferences ->
            preferences[numberKey] = number
        }
    }
}

이상입니다!

"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."

반응형

댓글()