728x90
728x90

참고 : 유투브 — 센치한 개발자

목표 : Handler 와 Runnable 를 이용하여 카운트 다운을 만들어 보자.

  • xml 파일에는 id 만 추가해주자.

  • 1에서 5까지 1초마다 한 번씩 카운트가 증가한다.
  • line 19 : count 가 int 형이므로 count 뒤에 [+ “” ] 를 덧붙여주었다.
  • line 36에서 post() 를 하면 line17 이 실행된다. 처음 count 변수를 0으로 초기화했으므로 run() 이 실행되면 1이 되면서 count가 5가 될 때까지 1초에 1씩 증가한다.

빌드를 해 보면 1에서 5까지 증가하고 멈춘 것을 확인할 수 있다.

 

 

참고)

<Process>

: 실행중인 프로그램의 객체. Android에서 앱을 실행하면 하나의 Process가 실행되고 MainActivity의 코드와 데이터를 메모리에 올린다.

<Thread>

: Process 안에서 코드를 실행시키는 객체. 하나의 Process 안에 여러개의 Thread가 있을 수 있다. (Multi Thread => 효율성 향상)

Process가 처음 시작되고 Thread를 처음 가지게 되는데, 이를 MainThread(UI Thread) 라고 한다. 이 위에서 작업량이 많아지면 ANR(Application Not Responding) 에러가 발생한다. 이를 위해 Worker Thread를 사용해야 한다.(멀티 스레드)

<Runnable>
: Thread 가 실행(run)해야하는 코드

<Handler>

: Worker Thread 에서 Main Thread 로 메세지를 전달하는 역할. post 를 통해 전달된 runnable 객체는 해당 handler 가 연결된 Thread 에서 실행된다.

참고 — https://brunch.co.kr/@mystoryg/84 , https://developer88.tistory.com/72

728x90
728x90

참고 : 유투브 — 센치한 개발자

  • Firebase : 클라우드. 웹과 모바일 개발에 필요한 기능을 제공해주는 BaaS(Backend as a Service).

[1. Firebase 셋팅하기]

  • 콘솔로 이동 > 프로젝트 생성

  • 안드로보이 클릭

  • 패키지 이름은 아래 화면과 같이 AndroidManifest.xml에서 가져온다. (line 3)

  • 다운 받은 파일을 지정된 위치에 복사+붙여넣기 한다.

  • 앱 수준의 bundle gradle — 위 쪽 파일 / 프로젝트 수준의 bundle gradle — 아래 쪽 파일

classpath 'com.google.gms:google-services:4.3.3'

를 종속성에 추가한다. (line 12)

  • line 47, 52,53 을 추가하고 Sync Now 를 클릭한다.

  • line 49~52 추가

  • line 26~28 추가
  • Sync Now 클릭

  • real time mode -> 셀카 촬영 모드에서 바로(실시간으로) 얼굴을 인식할 때 쓰면 좋을것이다.
  • 우리는 사진으로 얼굴을 인식할 예정이므로 위의 ‘high accuracy’ 를 쓸것이다.

 

 

[2. Face Detector 구성]

액티비티 파일을 생성하고 이와 연결할 xml 파일도 생성한다.

  • 예제 코드를 복사하여 사용할 클래스(액티비티) 를 새로 생성한다.

  • 액티비티와 연결할 xml 파일도 하나 생성한다.

  • scaleType : 이미지가 정해진 레이어보다 커서 넘쳤을 때 어떻게 해결할건지를 정의한다.
  • adjustViewBounds : 이미지의 종횡비가 깨지는 것을 허용할 것인지 아닌지 정한다. 값이 true 이면 허용하지 않을 것이라는 의미이다. (비율을 유지할 것)
  • 기본 이미지 위에 다른 이미지들을 겹쳐서 올리는 것이므로 RelativeLayout 을 사용한다.

  • 코드를 긁어서 붙여넣기한 후 class 를 import 한다. (alt + enter)

 

 

[3. Face Detector 실행]

머신러닝을 실행하려면 fire base 에게 Image 를 던져줘야한다.

참고 : https://firebase.google.com/docs/ml-kit/android/detect-faces

  • line 34 : FirebaseVisionImage 객체를 만든다.
  • line 36,37 : FirebaseVisionFaceDetector의 인스턴스를 가져온다.
  • line 39~56 : 이미지를 detectInImage 메소드에 전달한다.

[4. 감지된 얼굴에서 데이터 정보 얻기]

  • line 51~81 : 에 복사한 코드를 추가해준다.

 

 

[5. 이미지 리소스 파일을 코드로 가져오기]

  • line 31~36 : fire base 설정한 부분. 이 fire base 에게 bit map 사진을 던져주면 분석을 한다.
  • bitmap 사진을 던져보자. => 어디에?

  • res 아래에 drawable-xxhdpi 디렉토리를 새로 만들어서 다운받은 이미지 파일 네개를 넣어준다.
  • Context : 앱의 기능들을 자유롭게 사용하기 위한 매개체. 전역 변수로 선언해준다.
  • faces 인 이유 : 이미지에 얼굴이 여러개인 경우 For 문을 돌면서 찾기 위해 => 그 찾는 정보를 보기 위해 Log 를 찍어보자. => json 에 얼굴 정보들이 들어있다.
  • Landmark — 얼굴의 눈,코,입,볼 등의 정보
  • 이렇게 얻어온 Landmark 의 좌표에 멍 사진과 고양이 수염 사진을 넣으면 된다.

위치 정보 빼오기

  • png 파일을 ImageView 로 직접 가져와서 써도 되지만 이러면 사진을 추가할 때마다 xml 파일을 변경해야하는 불편함이 있다. 또한 멍 사진과 고양이 수염 사진 뿐 아니라 추후에 더 많은 사진들을 추가할 것을 대비하여 이미지 뷰를 가상으로 만들어 이용하는 방법으로 코딩해보자.
  • line 5 : 스티커(이미지)는 사진 위에 겹치게 보일 예정이므로 부모인 RelativeLayout에 이름을 지정하여 붙일 예정이다.

  • line 13 : RelativeLayout 위에 스티커를 붙일 것이므로 findViewById로 가져온다. (final 로 선언 한 이유 : 본인은 오류가 final 을 안 붙여도 오류가 나지 않았으나 강의에서는 범위로 인해(중괄호 바깥에 선언을 해서) 오류가 발생했음. 이를 해결하기 위해 값이 변하지 않고 그대로라는 뜻의 final 을 써줘야함.)
  • line 39 : 초기화
  • line 81,85,89 : 가상이미지를 통해 스티커를 붙였다. (imageCL 은 imageLC로 고쳐야함. 오타임.) => 이제 붙인 스티커를 위에서 getPosition으로 받은 좌표 위로 옮기면 된다.
  • 디스플레이 사이즈와 불러온 이미지 사이즈의 포인트 위치가 안드로이드 해상도 문제로 인해 조금씩 틀어진다. => 계산식이 필요하다.

  • 위에서 말했다시피, 스크린상의 좌표 (실제 좌표) 와 getPosition() 으로 얻어온 좌표와 사진 위치(R.drawable.sentilab) 사이의 계산식이 필요하다.
  • 필요한 계산 식 : point * 랜드마크 좌표 / 비트맵(얼굴 사진)

  • line 98 : imageLE의 크기를 바꾸자 => imageLE 가 속해있는 부모를 써야하므로 RelativeLayout 을 쓴 것이다.
  • -100 이유 : x,y에 face detector가 알려주는 점이랑 이미지랑 위치가 안 맞다.

 

 

최종 결과

 

728x90
728x90

 

참고 : 유투브 — 센치한 개발자

참고 : 아래 사이트

firebase.google.com/docs/database

 

  • NoSQL 은 json 형태를 기반으로 한다.

 

[1. 기본 설정하기]

implementation 'com.google.firebase:firebase-database:19.1.0'

를 앱 수준의 build.gradle 에 종속성을 추가한다.

  • 콘솔로 이동한 후 좌측의 Database 를 클릭한다.
  • 베타 버전인 Cloud Firestore 대신 Realtime database 만들기를 클릭한다.

  • read, write 를 모두 true 로 하고 사용설정을 클릭한다.

  • 안드로이드에서 저 프로젝트에 접근해서 json 데이터를 쌓을 것이며 이 데이터가 채팅 내용이다.

 

 

[2. 액티비티, xml 파일 생성]

  • Empty Activity 를 생성하면 xml 파일도 동시에 생성된다.

  • xml 파일을 위와 같이 수정해준다.

  • AndroidManifest.xml 파일도 수정해준다. (이전 액티비티 삭제)

 

 

[3. 데이터 베이스에 쓰기]

  • line 18~20을 복사 붙여넣기 한다.
  • 위 링크 하단의 다음 단계>데이터 읽기 및 쓰기를 클릭한다. (링크 — https://firebase.google.com/docs/database/android/read-and-write)
  • line 18 : 데이터 베이스를 선언하고 할당(생성)했다.
  • line 19 : ny-face 데이터 베이스 밑에 “message” 가 없으니 “message”를 만든다.
  • line 21 : message 밑에 “Hello World” 라는 내용이 들어간다.

  • message 가 올라간 것을 확인할 수 있다.

 

 

[4. DTO 생성]

채팅 데이터를 주고 받는 DTO(Data Transfer Object) 부터 만들어보자.

  • ChatData 을 생성한다.

 

 

[5. 어댑터 생성]

이제 ChatData 를 가져다가 값을 셋팅하는 Recycler의 어댑터가 필요하다.

  • 위와 같이 코드를 타이핑한다.

 

 

[6. xml 파일 생성]

  • 루트 LinearLayout이 vertical이므로 그 아래 weight 를 1로 다 가져간 RecyclerView의 height 는 0dp 이고, 그 아래 LinearLayout은 horizontal 이므로 weight를 1로 다 가져간 EditText의 width는 0dp 이다.
  • onBindViewHodler에서 받아온 닉네임을 비교하여 메세지를 정렬한다. (상대 방의 메세지는 왼쪽에 나의 메세지는 오른쪽에)

 

[7. add 함수 생성]

  • line 104 : 뉴스 앱을 만들 때에는 매번 실행할 때마다 새로운 데이터로 갱신됐는데, 채팅 앱은 메세지가 1건씩 추가될 때마다 뒤에 덧붙여야 하므로 add 하는 로직이 필요하다.
  • line 105 : 데이터가 삽입되는 것의 변화를 위해 notifyItemInserted를 사용해야 한다.
  • line 105 : add 를 하면 채팅 데이터 배열의 크기가 늘어나므로 그 사이즈를 활용해야 한다.

 

[8. 채팅 정보 셋팅]

  • setValue를 하여 데이터를 넣을 때 ChatData Class 자체를 넣을 예정이다.
  • line 47~50 : 이렇게 클래스를 넣기 시작하면 주의해야할 점이 있다. 우리가 처음에 “Hello World” 라는 스트링형을 데이터 베이스에 넣었기 때문에 에러가 난다. 그러므로 클래스를 넣기 전에 이미 올라가 있는 스트링 데이터를 지워야한다.

이제 리사이클러뷰의 어댑터에 가져온 채팅 데이터를 셋팅해야한다.

  • line 51 : dataSnapshot = 채팅 데이터를 담고 있는 변수
  • line 52 : 우리는 두번째 getValue() 를 쓸 것이고 괄호 안에 들어갈 클래스는 ChatData 클래스 이다.
  • getValue(ChatData.class) : 또 다른 형태의 클래스를 넣은 적이 있다면 이때 오류가 난다.

  • line 57 : 클래스 형 변환 필수!

 

 

[9. 전송 버튼 눌렀을 때 전송되게 하기]

  • 채팅 내용을 입력한 후 전송 버튼을 눌렀을 때에 서버로 채팅 내용을 보내야 한다.
  • line 32,33 : 변수 선언
  • line 43,44 : xml 컴포넌트와 매칭
  • line 46 : 버튼을 눌렀을 때 Button_send, EditText_chat 의 정보를 읽어서 서버로 보내야하므로 클릭 리스너 생성
  • line 51 : 빈 칸은 서버로 보내지 않도록 null check.

 

[10. 중간 점검 & 오류 해결]

  • line60~63 : 리사이클러 뷰 셋팅
  • line 64 : 리스트 선언
  • line 66~67 : 어댑터 셋팅
  • line 69,70 : 데이터 베이스 접속 후 데이터 정보 가져옴
  • line 72~75 : 채팅 데이터에 최초 데이터를 넣음

  • line 76~80 : 내가 보낸 메세지면 오른쪽에(END), 상대방이 보낸 메세지면 왼쪽에(START) 배치한다.

그러나 이렇게 실행을 하면 오류가 발생한다.

  • 데이터는 들어갔으나 앱은 실행되지 않았다.

로그화면

  • 이유 : 데이터가 정상처럼 보이지만 구조가 맞지 않았다.

에러를 해결해보자.

  • 초기 데이터 문제일 수도 있으므로 line 72~75를 주석처리했다.

  • 데이터도 삭제하고 다시 빌드해보았다.

그러나 앱은 실행되지 않았다.

로그를 살펴보자.

오브젝트를 변환할 수 없다고 뜬다.

  • line 71의 path 를 지우고 line 84,85를 주석처리 한 다음 Line 82와 같이 로그를 찍어보자.

  • 들어간 데이터가 한 묶음이 아닌 따로 들어가서 (두 줄로 나옴) 오류가 나는 것으로 예상한다.

다시 해결해보자.

  • Serialzable 을 지우고, setValue() 전에 push()를 해준다.

  • 값이 정상적으로 짝을 이루어 들어간 것을 확인할 수 있다.

  • 로그 값도 짝이 지어져 있는 것을 볼 수 있다.

  • 주석 처리한 것을 풀고 다시 확인해보자.
  • 추가로 nick1 에 대해서 닉네임과 채팅 내용을 모두 오른쪽 정렬 해 주자.

  • line 78,82 를 추가해준다.

결과

 

 

 

 

 

[11. 새로운 단말기 빌드]

두번째 채팅방 접속자를 만들기 위해 새로운 단말기로 빌드해보자.

성공

 

 

 

추가)

  • 지금 만든 앱은 새로운 접속자가 있을 때 마다 nick1,nick2,,, 이런 식으로 직접 바꿔줘야한다.
  • 그러나 랜덤 채팅 혹은 정해진 사용자만을 원할 때는 저번에 배운 로그인 화면을 이용한다던가 firebase의 authentication 의 로그인 기능을 이용할 수도 있다.
  • 현재는 가장 처음에 read, write 를 true 로 해주어 아무나 접속이 가능하지만, 이를 false 로 바꾸면 그게 불가능하다.

 

 

 

728x90

+ Recent posts