들어가며

지난 시간까지 데이터를 수집하고 Tensorflow Lite 모델을 만드는 과정까지 진행해보았다. 이번에는 이 모델 파일을 Android에 삽입해서 실제 구동까지 진행해보도록 하겠다.

TFlite 모델에 메타데이터 추가하기

이 부분 때문에 필자는 몇 시간동안 삽질을 했다. 이전 장에서 만든 .tflite 파일을 그대로 안드로이드에 사용하게 되면 에러가 발생한다:(. 구글링을 하고 stack overflow에 업로드하는 등 여러 노력을 통해서 솔루션을 찾아냈다. 에러의 내용은 tflite모델에 NormalizationOptions이 추가되어 있어야 한다는 뜻이었다. 이는 메타 데이터의 일종인데 이를 삽입하기 위해선 추가적인 작업이 필요했다.

addMetaData.ipynb
0.01MB

위 코드를 사용하면 필요한 메타 데이터를 추가 할 수 있다. 코드를 보면 아래의 부분을 볼 수 있는데 여기에 자신이 메타데이터를 추가할 tflite 파일과 label.txt의 경로를 지정한 후 그대로 실행시켜주면 된다.

Android Studio Demo APP에 삽입하기

자 이제 마지막 단계이다. github.com/tensorflow/examples/tree/master/lite/examples/object_detection/android이 링크에 들어가게 되면 Android에서 Object Detection 모델을 실행할 수 있는 코드를 다운로드할 수 있다. Readme의 지침을 잘 따라서 모델을 Asset 디렉터리에 삽입하게 되면 비로소 모델을 실행시킬 수 있을 것이다.

 

마무리

예전 코드를 참조해서 그런지 필자는 중간에 여러번 에러가 발생해서 굉장히 힘들었다... 이 글을 본 사람들은 부디 필자처럼 삽질을 하지 않았으면 좋겠다. ㅎㅎ 지금까지 안드로이드에서 동작하는 Object Detection 애플리케이션을 만드는 과정이었다.

Reference

1. www.tensorflow.org/lite/convert/metadata

 

TensorFlow Lite 모델에 메타 데이터 추가

TensorFlow Lite 메타 데이터는 모델 설명에 대한 표준을 제공합니다. 메타 데이터는 모델이 수행하는 작업과 입력 / 출력 정보에 대한 중요한 지식 소스입니다. 메타 데이터는 TensorFlow Lite 호스팅 모

www.tensorflow.org

2. github.com/tensorflow/examples/tree/master/lite/examples/object_detection/android

 

tensorflow/examples

TensorFlow examples. Contribute to tensorflow/examples development by creating an account on GitHub.

github.com

 

들어가며

파이썬, 자바등의 많은 프로젝트에서는 이식성을 위한 코드의 집합인 패키지, 모듈이 있다. 당연히 안드로이드에도 이를 지원하는 AAR(Android Archive)가 존재한다. 공식 사이트에도 설명이 되어있지만 갱신되지 않거나 모호한 부분이 있어 차근차근 모듈을 만들고 테스트하는 방법에 대해서 알아보도록 하자.

안드로이드의 모듈은 코드뿐만 아니라 이미지, 텍스트 등의 데이터를 포함해서 부르기 때문에 여기선 라이브러리와 동일한 의미로 언급한다.

 

1. 새로운 모듈 만들기

우선 기존의 프로젝트에서 아래의 경로를 통해 새로운 모듈을 만든다.

New Module을 클릭하면 여러가지 타입이 나오는데 간단한 AAR을 만들기 위해서 Android Library를 선택하고 next를 클릭한다.

다음에는 모듈이름과 패키지명, Minimum SDK를 설정할 수 있다. 패키지명은 지금은 중요하지 않지만 추후에 배포를 할 시에는 중요하다. 지금은 기본설정으로 진행해보자.

새로 생성을 하면 Project 패널에 모듈명으로 폴더가 생성되어 있으며 내부에는 기존 app과 같은 구조로 표현되어있다.

ToastID와 관련된  build.gradle 파일을 살펴보면 기존의 app build.gradle과 매우 유사하다, 하지만 plugins에 'com.android.application'대신 'com.android.library'라고 되어 있는데 이는 ToastID디렉토리를 라이브러리로 사용하겠다는 뜻이다. 그리고 라이브러리에는 applicationID가 없지만 app에는 있다. 이는 라이브러리에서는 applicationID를 사용할 수 없기 때문이다.

Android 공식 사이트에는 새로운 모듈을 만들었을 때 gradle.build설정을 따로 해야한다고 하지만 현재는 자동으로 라이브러리를위한 gradle.build를 만들기 때문에 신경쓰지 않아도 된다. (패치했으면 document는 업데이트 해줬으면 좋겠다...)

https://developer.android.com/studio/projects/android-library
 

Android 라이브러리 만들기  |  Android 개발자  |  Android Developers

Android 라이브러리를 생성하는 방법을 알아보세요.

developer.android.com

build.gradle(ToastID)
build.gradle(app)

간단한 테스트를 하기 위해서 ToastID클래스와 아이디를 토스트하는 메서드를  작성해보았다.

자 그럼 모듈을 기존의 app에 연결하여 어플리케이션을 빌드해보자

 

2. 로컬 모듈 연결하기

build.gradle(app)에 들어가서 모듈과의 연결을 설정할 수 있다. 아는 사람도 많겠지만 dependencies에서 외부 저장소 라이브러리를 가져오거나 지금 할 것처럼 프로젝트 내부의 모듈을 연결 할 수 있다. 프로젝트 내부 연결을 위해선 implementation project(':모듈명')를 dependencies에 추가하면된다.

추가후 Sync Now를 클릭해서 동기화 해주면 기존의 app 내부의 MainActivity에서 ToastID모듈 내부의 toast 메서드를 참조할 수 있는것을 볼 수 있다. 이제 모듈을 마음껏 테스트해보고 필요시 배포를 할 수 있다.

 

마치며

자바에 대해서 어느정도 지식이 있는 사람은 "그냥 JAR을 디렉토리에 옮겨서 import하면 쉬운데 build.gradle을 어렵게 설정하면서까지 해야하는거지?"라고 생각할 수도 있다. 물론 이 방법도 가능하다. 그러나 눈치챈 사람도 있겠지만 AAR은 코드 뿐만 아니라 drawable,layout 등의 안드로이드에 특화된 데이터까지 모듈화가 가능한게 큰 장점이다. 이를 잘 사용해서 프로젝트 협업을 잘 하거나 안드로이드 개발자들을 위한 오픈소스를 쉽게 사용하도록 제공해보도록 하자.

들어가며

안드로이드의 가장 기본적인 알림을 사용해보자. 아마 프로젝트 하다가 어떻게 쓰는지 궁금한 사람들이 검색을 했을 테니 최대한 간결하게 코드를 통해 설명하겠다. 코드를 세세하게 찾아보고 싶은 사람은 android developers의 문서를 참조하기 바란다.

 

사용방법

1. Notification Channel만들기

각 어플리케이션에서 Notification알림을 실행하려면 우선 채널을 만들어야한다. 

아래 코드를 복사해서 MainActivity에 추가하고 onCreate에서 해당 함수를 호출해주자

*채널명과 설명은 본인 어플리케이션에 맞게 설정해주자

private void createNotificationChannel() {
        // Create the NotificationChannel, but only on API 26+ because
        // the NotificationChannel class is new and not in the support library
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            CharSequence name = "공지사항 채널";
            String description = "공지사항 채널";
            int importance = NotificationManager.IMPORTANCE_DEFAULT;
            NotificationChannel channel = new NotificationChannel("공지사항 채널", name, importance);
            channel.setDescription(description);
            // Register the channel with the system; you can't change the importance
            // or other notification behaviors after this
            NotificationManager notificationManager = getSystemService(NotificationManager.class);
            notificationManager.createNotificationChannel(channel);
        }
    }

2. 새로운 Notification을 만들고 이를 NotificationManager에 추가해주자

URLData.activity는 호출을 위한 액티비티 Context를 추가해주면된다.(ex MainActivity.this)

플래그를 설정해주고 PendingIntent를 호출하자.

builder를 만들 때 setContentIntent에서 이를 추가하고 Notification을 위한 다른 정보를 추가해주자(제목, 내용 등)

마지막으로 액티비티에서 NotificationManagerCompat를 호출해주고 notify로 builder로 만든 Notification을 추가해주면 끝이다.

Intent intent = new Intent(URLData.activity, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(URLData.activity, 0, intent, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(URLData.activity, "공지사항 채널")
                                    .setSmallIcon(R.drawable.app_icon)
                                    .setContentTitle(urlDataList.get(index).urlName)
                                    .setContentText("새로운 공지사항이 등록되었습니다!!")
                                    .setPriority(NotificationCompat.PRIORITY_DEFAULT)
                                    .setContentIntent(pendingIntent)
                                    .setAutoCancel(true);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(URLData.activity);
notificationManager.notify('1', builder.build());

들어가며

안드로이드 코드를 작성하다보면 view를 다룰 때 꼭 한번 context를 parameter로 요청하는 경우가 있다.

그냥 단어만 알고있던 이것에 대해서 한 번 알아보고 어떤 쓸모가 있는지 알아보고 다른 인스턴스에 접근하는 방법을 탐구해보자. ( 인스턴스 접근방법을 알고 싶다면 맨 아래 문단을 참고하기 바랍니다. )

Context의 정의

출처: https://developer.android.com/reference/android/content/Context

위는 Android Developers에 게시된 문서의 정의부분이다. 읽어보니 안드로이드의 시스템 요소와 자원에 접근하기 위한 추상 클래스라고 한다. 문서를 조금더 찾아보니 Activity, Application, Service의 base class로 사용된다고 한다. 이를 알고 나니 기본적인 시스템 추상클래스라는 느낌을 알겠다.

용례

  • 어플리케이션의 resource 획득
  • 새로운 activity 시작
  • view 생성
  • system service 획득

사용 예시에는 위와 같은 경우가 있는데 이는 getResource(), startActivity() 등의 함수를 어느정도 다루어봤다면 당연히 알 것이다. 이 정도로 끝났다면 나는 이번 포스팅을 작성하지 않았을 것이다. 생각해보니 이를 이용하면 CustomView를 만들때 해당 뷰가 속한 액티비티의 함수를 CustomView에서 자유롭게 호출할 수 있을것 같았다.

다른 액티비티에서 변수, 함수 호출

아래는 내가 만든 CustomButton이다. 우선 생성자를 호출할 때 뷰는 모든 Context를 인자로 받아야하는데 이를 MainActivity클래스로 캐스팅하여 변수로 저장했다.

그 다음 버튼을 클릭할 때 startForegroundService를 호출하도록 실험해봤는데.... 된다..... MainActivity는 싱글톤 클래스고 Context를 MainActivity으로 캐스팅해서 안 될줄 알았는데 된다....

다른 액티비티나 커스텀 뷰에서 메인 액티비티의 변수나 함수에 접근하는데 stack overflow에 서칭도 해보고 고민을 많이 했는데 너무 간단하게 된다.... 아무튼 오늘 좋은 지식을 하나 얻었다.

 

+ Recent posts