* 통합구현:

- 송/수신 모듈과 중계 모듈 간의 연계를 구현하는 것.

- 송/수신 방식이나 시스템 아키텍처 구성, 송/수신 모듈 구현 방법 등에 따라 다르므로 사용자의 요구사항과 구축 환경에 적합한 방식 설계

 

* 구성요소:

- 송신 시스템과 모듈

- 수신 시스템과 모듈

- 중계 시스템

- 연계 데이터

- 네트워크

 

* 연계 매커니즘: 응용 소프트웨어와 연계 대상 모듈 간의 데이터 연계시 요구사항을 고려한 연계방법과 주기를 설계하기 위한 매커니즘.

 

* 연계 매커니즘 수행 절차:

- 연계 데이터 생성 및 추출

- 코드 매핑 및 데이터 변환

- 인터페이스 테이블 또는 파일 생성

- 연계 서버 또는 송신 어댑터

-> 실패시 로그 기록

 

* 로그 기록: 송/수신 시스템에서 수행되는 모든 과정에 관한 결과 및 오류에 대한 정보를 로그 테이블이나 파일에 기록하는 과정

 

* 연계 방식:

- 직접연계

  • DB 링크(DB Link)
  • DB 연결(DB Connection)
  • API/Open API
  • JDBC
  • 하이퍼 링크

- 간접연계

  • 연계 솔루션(EAI)
  • Web Service/ESB
  • 소켓(Socket)

 

* 연계 모듈 구현 환경 구성 및 개발:

- EAI(Enterprise Application Integration)방식은 기업에서 운영되는 이기종간의 정보전달, 연계, 통합을 갖능하게 해주는 솔루션. 각 비즈니스간 통합 및 연계성을 증대시켜 시스템간의 확장성 향상.

 

- ESB(Enterprise Service Bus)방식은 서로 다른 플랫폼 및 애플리케이션들을 하나의 시스템으로 관리 운영할 수 있도록 서비스 중심의 통합을 지향하는 아키텍처 또는 기술. ESB는 버스를 중심으로 각각 프로토콜이 호환 가능하도록 애플리케이션간의 통합을 느슨한 결합 방식으로 지원하는 방식.

 

* EAI/ESB 방식 연계 모듈 환경 및 구축 절차:

- 연계 DB 또는 계정 생성

- 연계를 위한 테이블 생성

- 연계 응용 프로그램 구현

 

* 웹서비스 방식: 네트워크에 분산된 정보를 서비스 형태로 개방하여 표준화된 방식으로 공유하는 기술로써 서비스 지향 하키텍처 개념을 실현하는 대표적인 기술.

 

* 웹서비스 방식의 유형:

- SOAP 방식

- UDDI 방식

- WSDL 방식

 

SOAP(Simple Object Access Protocol)은 일반적으로 널리 알려진 HTTP, HTTPS, SMTP 등을 사용하여 XML 기반의 메시지를 네트워크 상태에서 교환하는 프로토콜.

 

UDDI(Universal Description ,Discovery and Integration)는 웹 서비스를 등록하고 검색하기 위한 저장소로 웹 서비스를 공개적으로 접근, 검색이 가능하도록 공개된 레지스트리.

 

WSDL(Web Services Description Language)은 웹 서비스가 제공하는 서비스에 대한 정보를 기술한 파일로 XML로 기술

 

REST 프로토콜: HTTP메소드(POST, GET, PUT, DELETE)를 통해 자원에 대한 생성, 조회, 갱신, 삭제 명령을 적용하는 프로토콜. SOAP 대체가능 

 

- RESTful 웹 서비스란 REST(Representational State Transfer, 2000년, Roy Fielding) 기반의 웹 서비스를 의미하며 HTTP의 기본 기능만으로 원격 정보에 접근하는 웹 응용 기술.

 

* 데이터 모델:

- 현실 세계의 정보들을 컴퓨터에 표현하기 위해 단순화, 추상화 하여 체계적으로 표현한 개념적 모형.

- 데이터 모델은 데이터, 데이터의 관계, 데이터의 의미 및 일관성, 제약조건 등을 기술하기 위한 개념적 도구들의 모임.

- 데이터베이스 설계 과정에서 데이터의 구조(Schema)를 논리적으로  표현하기 위해 지능적 도구로 사용.

 

* 데이터 모델에 표시해야할 요소:

- 구조 Structure : 논리적으로 표현된 개체 타입들 간의 관계로서 데이터 구조 및 정적 성질 표현

- 연산 Operation: 데이터베이스에 저장된 실제 데이터를 처리하는 작업에 대한 명세로서 데이터베이스를 조작하는 기본 도구

- 제약 조건 Constraint: 데이터베이스에 저장될 수 있는 실제 데이터의 논리적인 제약조건

 

* 데이터 모델의 종류:

- 개념적 데이터 모델

- 논리적 데이터 모델

- 물리적 데이터 모델

 

* 데이터 모델링 속성:

- Entity 개체: 관리 대상이 되는 실체. 개념이나 정보 단위 같은 현실 세계의 대상체

- Attribute 속성: 관리할 정보의 구체적 항목. 데이터베이스를 구성하는 가장 작은 논리적 단위

- Relationship 관계: 개체 간의 대응 관계. 개체와 개체 사이의 논리적인 연결

 

* 논리 데이터 모델링: 데이터베이스 설계 프로세스의 기초 설계 단계. 개념 모델로부터 업무 영역의 업무 데이터 및 규칙을 구체적으로 표현한 모델

 

* 논리 데이터 모델링 특성:

- 정규화

- 포용성

- 완전성

- 독립성

 

* 개체-관계(E-R) 모델:

- 현실 세계의 데이터와 그 관계를 사람이 이해할 수 있는 형태로 표현하기 위한 모델.

- 모든 이해당사자와 의사소통의 보조 자료로 활용.

- 요구사항으로부터 얻어낸 정보들을 개체, 속성, 관계로 기술한 모델.

 

* 정규화(Normalization): 관계형 데이터베이스의 설계에서 중복을 최소화하여 데이터를 구조화하는 프로세스

 

* 이상현상(Abnomaly): 데이터의 중복성으로 인해 릴레이션을 조작할 때 발생하는 비합리적 현상.

- 삽입이상: 정보 저장시 해당 정보의 불필요한 세부정보를 입력해야하는 경우

- 삭제이상: 정보 삭제시 원치 않는 다른 정보가 같이 삭제되는 경우

- 갱신이상: 중복 데이터 중에서 특정 부분만 수정되어 중복된 값이 모순을 일으키는 경우

 

*정규화의 단계

- 1정규형(1NF): 원자값으로 구성

- 2정규형(2NF): 부분 함수 종속 제거

- 3정규형(3NF): 이행함수 종속 제거

- 보이스-코드 정규형(BCNF): 결정자 함수이면서 후보키가 아닌 것 제거

- 4정규형(4NF): 다치 종속성 제거

- 5정규형(5NF): 조인 종속성 제거

 

 

https://github.blog/2022-06-08-sunsetting-atom/

 

Sunsetting Atom | The GitHub Blog

We are archiving Atom and all projects under the Atom organization for an official sunset on December 15, 2022.

github.blog

 

편집기 아톰이 서비스를 종료한다는 기사를 오늘 접하게 되었습니다.

 

제가 방금 파이썬을 공부하려고 아톰에서 헬로 월드 프린트를 시도하고 있었던 참이었어요.

 

원래 만남이 있으면 이별이 있다고 하는데, 이별이 좀 빠르네요~

 


아톰이 사라져도 지금 필요한건..

 

아톰으로 파이썬 실행하기!!!

 

 

아톰을 받으셨는데 아무리 ctrl+shift+b를 눌러도 실행이 안되시나요?

 

패키지를 받아야 하는데 script 검색을 아무리 해봐도 찾지 못하셨나요?

 

 

저는 그랬습니다..

 

이젠 사라질 아톰에서 파이썬을 실행시키는 방법!!

 

아래 링크를 클릭해주세요!

 

https://github.com/atom-community/atom-script

 

GitHub - atom-community/atom-script: Run ( scripts | selections | source ) in Atom

:runner: Run ( scripts | selections | source ) in Atom - GitHub - atom-community/atom-script: Run ( scripts | selections | source ) in Atom

github.com

 

링크에 설명되어있듯이 두가지 방법이 있습니다.

 

1. 깃헙에서 script 패키지를 다운로드 - C:\Users\[사용자]\.atom\packages 폴더에 넣는다. 끝!

2. apm으로 받는다.

 

첫번째는 아주 간단하죠!

저는 두번째 방법으로 했기때문에 조금 더 자세히 설명드려볼게요.

 

apm으로 script 패키지 설치하는 방법:

 

1. 아톰 - apm 폴더의 경로를 찾습니다.

 

대부분 하단 경로일거라 생각합니다. [사용자]는 컴퓨터에 맞게 수정해주세요!

 

C:\Users\[사용자]\.atom\.apm

 

 

2. apm 폴더 안에서 cmd를 실행시킵니다.

폴더 상단의 파일탭 - 명령프롬프트 실행

 

 

3.  apm install script 입력 엔터. 

기다립니다. 인스톨이 끝나고 done이 찍히면 끝!

 

 

22년 12월 15일까지 사용하면 됩니다. ^^ ..

 

소프트웨어 생명주기

 

* 소프트웨어 생명주기: 소프트웨어를 개발하기 위한 설계, 운용, 유지보수 등의 과정을 각 단계별로 나눈 것.

 

생명주기 모형의 종류:

- 폭포수 모형

- 프로토타입 모형

- 나선형 모형

- 애자일 모형

 


요구사항 확인

 

* 요구사항: 문제의 해결 또는 목적 달성을 위해 고객의 요구사항, 혹은 표준이나 명세를 충족시키기 위해 시스템이 가져야하는 서비스 혹은 제약사항.

 

* 요구사항 분류:

- 기능적 요구사항: 

 특성: 기능성, 완전성, 일관성

 ex) 온라인 쇼핑을 구현했을 경우 장바구니에서 아이템 삭제가 가능해야함

 

- 비기능적 요구사항: 

 특성: 신뢰성, 사용성, 효율성, 유지보수성, 이식성

 ex) 시스템은 하루 24시간 가동되어야함

 

- 사용자 요구사항: 사용자 관점에서 본 시스템이 제공해야할 요구사항

- 시스템 요구사항: 소프트웨어 요구사항. 개발자 관점에서 본 시스템 전체가 제공해야할 요구사항

 

 

* 요구사항 개발 프로세스:

요구사항 도출 Elication - 분석 Analysis - 명세 Specification - 확인 Validation

 

* 요구사항 분석 기법:

- 요구사항 분류

- 개념 모델링

- 요구사항 할당

- 요구사항 협상

- 정형 분석

 

* 요구사항 분석: 개발 대상에 대한 사용자의 요구사항을 이해하고 문서화 하는 활동

 

* 구조적 분석 기법: 자료의 흐름, 처리를 바탕으로 요구사항을 분석 하는 방법. 하향식 방법을 통해 시스템을 세분화 할 수 있다.

 

* 구조적 분석 기법 도구:

 - 자료흐름도(DFD)

 - 자료 사전(DD)

 - 소단위 명세서(Mini-Spec.)

 - 개체 관계도(ERD)

 - 상태 전이도(STD)

 - 제어 명세서

 

* 요구사항 분석용 CASE(자동화 도구)

: 요구사항을 자동으로 분석하고 요구사항 분석 명세서를 기술하도록 개발된 도구

 

*요구사항 분석용 CASE

 - ASDT

 - SREM = RSL/REVS

 - PSL/PSA

 - TAGS

 

* HIPO (Hierarchy Input Process Output)

: 시스템 실행 과정인 입력, 처리, 출력의 기능을 표현한 것으로 시스템의 분석,설계, 문서화에 사용되는 기법

 

* UML (Unified Modeling Language)

: 시스템 개발 과정에서 시스템 개발자와 고객, 협업 개발자들 등 상호간의 의사소통이 원할히 이뤄지도록 표준화한 대표적인 객체지향 모델링 언어.

 

*  UML의 구성요소

- Things 사물

- Relationships 관계

- Diagram 다이어그램

 

* UML - 다이어그램 : 사물과 관계를 도형으로 표현한 것.

- Structural Diagram (구조적 다이어그램): 정적 모델링에서 주로 사용.

종류:

  • Calss Diagram 클래스 다이어그램
  • Object Diagram 객체 다이어그램
  • Component Diagram 컴포넌트 다이어그램
  • Deplyment Diagram 배치 다이어그램
  • Composite Structure Diagram 복합체 구조 다이어그램
  • Package Diagram 패키지 다이어그램

- Behavioral Diagram (행위 다이어그램): 동적 모델링에서 주로 사용.

종류:

  • Use Case Diagram 유스케이스 다이어그램
  • Sequence Diagram 시퀀스 다이어그램
  • Communication Diagram 커뮤니케이션 다이어그램
  • State Diagram 상태 다이어그램
  • Activity Diagram 활동 다이어그램
  • Interaction Overview Diagram 상호작용 개요 다이어그램
  • Timing Diagram 타이밍 다이어그램

 

* 비용산정 모델: 소프트웨어 규모 파악을 통한 투입 자원과 소요 시간을 통해 실행 가능한 계획을 수립하기 위해 비용을 산정하는 모델

 

* 비용산정 모델 분류:

- 하향식 산정방법: 전문가 판단, 델파이 기법

- 상향식 산정방법: LoC, Man Month, COCOMO 모형, Putnam 모형, FP(Function Point)모형

 

* COCOMO 모형의 소프트웨어 개발 유형

 - Organic Mode 조직형: 5만(50KDSI) 라인 이하의 소프트웨어 개발 유형

 - Semi-Detached Mode 반분리형: 30만(300KDSI) 라인 이하의 소프트웨어 개발 유형

 - Embedded Mode 내장형: 30만(300KDSI)라인 이상의 소프트웨어 개발 유형

 

* Putnam(푸트남) 모형:

소프트웨어 생명 주기의 전 과정 동안에 사용될 노력의 분포를 예상.

Rayleigh-Norden 곡선의 노력 분포도를 기초로 함.

 

* 비용 산정 자동화 추정 도구

- SLIM: Rayleigh-Norden 곡선과 Putnam 예측 모델을 기초로 개발된 자동화 추정 도구

- ESTIMACS: FP모형을 기초로 개발된 자동화 추정 도구

 

 

* 프로젝트 일정 계획: 프로젝트의 프로세스를 이루는 소작업을 파악하고 예측된 노력을 각 소작업에 분배하여 순서와 일정 정리.

- PERT (Program Evaluation and Review Technique, 프로그램 평가 및 검토 기술)

: 전체 작업의 상호 관계를 표시하는 네트워크

- CPM (Critical Path Method, 임계 경로 기법)

: 프로젝트 완성에 필요한 작업을 나열, 필요한 소요기간을 예측하는데 사용하는 기법.

- 간트 차트 / Time-Line 차트

: 프로젝트의 작업 시작, 종료에 대한 작업일정을 막대 도표로 표시하는 프로젝트 일정표.

 


 

현행 시스템 분석

 

* 현행 시스템 파악: 현행 시스템이 어떤 하위 시스템으로 구성되어있고, 제공 기능 및 연계 정보는 무엇이며 어떤 기술 요소를 사용하는지 파악하는 활동.

 

* 현행 시스템 파악 절차:

1. 구성/ 기능/ 인터페이스 파악 - 시스템 구성 현황, 시스템 기능, 시스템 인터페이스 파악

2. 아키텍처 및 소프트웨어 구성 파악  - 아키텍처, 소프트웨어 구성 파악

3. 하드웨어 및 네트워크 구성 파악 - 시스템 하드웨어 현황, 네트워크 구성 파악

 

* 개발 기술 환경 파악

- OS (Operation System) 운영체제: 컴퓨터 시스템이 제공하는 하드웨어, 소프트웨어를 효율적으로 관리하며 편리하게 사용할 수 있도록 지원하는 소프트웨어.

고려사항:

  • 품질측면 : 신뢰도, 성능
  • 지원측면 : 기술지원, 주변 기기, 구축비용

- DBMS (Data Base Management System) 데이터베이스 관리 시스템: 사용자가 데이터베이스를 생성, 저장, 관리 기능을 도와주는 응용 프로그램.

고려사항:

  • 품질측면 : 가용성, 성능, 상호 호환성
  • 지원측면 : 기술지원, 주변 기기, 구축비용

- Middleware 미들웨어: 분산 컴퓨팅 환경에서 응용 프로그램과 프로그램이 운영되는 환경 간 통신을 제어해주는 소프트웨어. 대표적인 미들웨어로 WAS가 있다.

고려사항:

  • 성능 측면: 가용성, 성능

   * WAS (Web Application Server) 웹 애플리케이션 서버:  서버 계층에서 app이 동작할 수 있도록 환경 제공. 다른 이기종 시스템과의 애플리케이션 연동을 지원하는 서버.

 

- Open Source 오픈소스: 누구나 제한없이 사용할 수 있도록 소스를 공개한 소프트웨어.

  • 라이선스의 종류, 사용자 수, 기술의 지속 가능성

 

 

안드로이드 마테리얼 데이트 픽커 오류.

 

앱에서 달력으로 기간을 선택해오는 머티리얼.. 마테리얼... 머테리얼... 그 라이브러리를 적용했을때 볼 수 있는 오류다.

 

java.lang.IllegalArgumentException: com.google.android.material.datepicker.MaterialDatePicker requires a value for the com.cyd.selllaundryadmin:attr/colorSurface attribute to be set in your app theme. You can either set the attribute in your theme or update your theme to inherit from Theme.MaterialComponents (or a descendant).

 

적혀있듯이 테마를 넣어달라고 한다. 테마는 필수 ~!

다른 액티비티에는 적용을 시켜뒀는데 새로운 액티비티 생성 후, 적용을 시켜주지 않아서 오류가났다.

 

 

해결책은 간단하다. 

maifest - 해당 액티비티에 적용시킬 테마를 명시해주면 끝.

 

 

자세히 설명해보자면

 

1. 달력에 적용시켜줄 테마 생성

 

res < values < themes < themes.xml 

 

xml 파일에서 달력에 적용시킬 커스텀 테마를 작성해준다.

<style name="MaterialCustomRoot" parent="Theme.MaterialComponents.Light">
    <item name="windowNoTitle">true</item>
    <item name="windowActionBar">false</item>
    <item name="android:statusBarColor">@color/white</item>
    <item name="android:windowLightStatusBar">true</item>
    
    <item name="colorPrimary">@color/main_red</item>
    <item name="materialCalendarStyle">@style/Widget.MaterialComponents.MaterialCalendar</item>
    <item name="materialCalendarFullscreenTheme">@style/ThemeOverlay.MaterialComponents.MaterialCalendar.Fullscreen</item>
    <item name="materialCalendarTheme">@style/ThemeOverlay.MaterialComponents.MaterialCalendar</item>
</style>

 

 

2. manifest에 명시

 

데이트픽커를 적용한 액티비티에 위에서 작성한 테마를 적어준다.

 

<activity android:name=".Main.MyActivity"
    android:theme="@style/MaterialCustomRoot"
    />

 

 

 

오늘은 힘든 일요일이었으니 쉽고빠른 자동로그인을 해봅시다.

준비물은 로그인이 가능한 환경입니다...

서버와 로그인 api, 유저 데이터가 존재함을 바탕으로 SharedPreference 사용 방법만을 적었습니다.

java 언어를 기반으로 작성되었습니다.

 


0. SharedPreferences 간단 설명

 

안드로이드에서 사용 가능한 데이터베이스 관리 시스템(DBMS) 중 하나입니다. 

key - value 형태로 관리가 가능해서 간단한 데이터를 저장할 때 주로 쓰입니다. 전 자동로그인 할 때 가장 자주  사용하고 있습니다. 

 

더 자세한 내용을 알고싶다면 하단 링크를 참조해주세요.

 

https://developer.android.com/reference/android/content/SharedPreferences

 

SharedPreferences  |  Android Developers

 

developer.android.com

 

핵심 명령어

https://www.tutorialspoint.com/android/android_shared_preferences.htm

 

Android - Shared Preferences

Android - Shared Preferences Android provides many ways of storing data of an application. One of this way is called Shared Preferences. Shared Preferences allow you to save and retrieve data in the form of key,value pair. In order to use shared preference

www.tutorialspoint.com

 

설명 및 사용예제

https://www.geeksforgeeks.org/shared-preferences-in-android-with-examples/

 

Shared Preferences in Android with Example - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

 

 

 


 

1. SharedPreferences를 위한 클래스 생성

 

SharedPreferences를 손쉽게 사용하도록 도와줄 클래스를 만들어줍니다.

public class SharedPreferencesManager {
    
}

 

그리고 SharedPreferences를 불러오기 위해 매번 사용해야하는 코드를 편리하게 사용할 수 있도록 메소드로 만들어줍니다.

 

private static final String PREFERENCES_NAME = "my_preferences";

public static SharedPreferences getPreferences(Context mContext){
    return mContext.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE);
}

 

왜 고작 한줄의 코드를 메소드로 빼두냐면, SharedPreferences는 불러오는 이름에 따라 저장할 수 있는 값이 달라집니다. 키 - 값 형태로 관리를 한다고 했으니, 다른 이름으로 getSharedPreferences 메소드를 사용하면 또 다른 값이 저장이 되겠죠?

따라서 저는 getPreferences라는 메소드로 자동로그인을 할 데이터만 저장할 예정이라 따로 만들었습니다. 

 

그리고 MODE_PRIVATE는 현재 사용하는 앱에서만 접근을 허락하도록 지정해놓은 것입니다. 여기에 관련된 자세한 항목은 상단 링크를 읽어보시면 더 자세히 알 수 있습니다.

 

이걸로 기본 준비는 끝났습니다.

 

 


 

2. 저장, 불러올 데이터 메소드 생성

 

로그인 정보를 저장, 불러오는 메소드를 만들어줍니다.

로그인의 가장 기본적인 데이터 email, password를 예시로 적었습니다.

필요한 정보를 저장해두면 됩니다!

 

public static void setLoginInfo(Context context, String email, String password){
    SharedPreferences prefs = getPreferences(context);
    SharedPreferences.Editor editor = prefs.edit();
    editor.putString("email", email);
    editor.putString("password", password);

    editor.apply();
}

public static Map<String, String> getLoginInfo(Context context){
    SharedPreferences prefs = getPreferences(context);
    Map<String, String> LoginInfo = new HashMap<>();
    String email = prefs.getString("email", "");
    String password = prefs.getString("password", "");
        
    LoginInfo.put("email", email);
    LoginInfo.put("password", password);

    return LoginInfo;
}

 

해당 값이 null일 수 있으므로 defaultValue또한 공백문자로 처리했습니다. 이렇게 해두면 nullPointException 에러를 막을 수 있습니다. 

 

 


 

3. 사용과 활용

 

 

이제 SharedPreference를 어디서든 부를 수 있게 되었습니다.

따라서 사용자가 로그인 화면의 행동을 모두 끝마쳤을때.

즉, 유효한 데이터로 서버와 통신을 마치고 메인 화면으로 넘어갈 때

SharedPreferencesManager.setLoginInfo(this, email ,password);

이렇게 데이터를 저장해줍니다.

 

 

그 후, 한번 유효한 데이터로 로그인을 했던 사용자가 앱을 종료하고 다시 실행했을 때 SharedPreference에서 데이터를 가져옵시다.

Map<String, String> loginInfo = SharedPreferencesManager.getLoginInfo(this);
if (!loginInfo.isEmpty()){
    String email    = loginInfo.get("email");
    String password = loginInfo.get("password");
    }

 

이렇게 데이터를 가져오고 서버에 로그인 리퀘스트를 해주면 자동로그인이 완성됩니다.

만약 로그인 데이터가 잘못되었다면 로그인화면으로 넘겨야겠죠!

 

 

+ 이 외에도 아이디만 저장하기 기능도 SharedPreference를 활용할 수 있습니다. 보통 로그인 화면에서 체크박스로 확인하니, 로그인 할 때 해당 체크박스를 bool로 저장해두면 됩니다.

 


4. 삭제

 

가장 중요한부분!!!

바로 데이터 삭제입니다. 로그아웃을 했는데 다시 로그인이 되면 큰일나므로...

 

로그아웃, 회원탈퇴 시 꼭! 반드시!! sharedPreference를 삭제해야합니다.

삭제 코드는 다음과 같습니다.

 

public static void clearPreferences(Context context){
    SharedPreferences prefs = getPreferences(context);
    SharedPreferences.Editor editor = prefs.edit();
    editor.clear();
    editor.apply();
}

 

이제 로그아웃시 해당 메소드를 호출하면 됩니다.

 


 

SharedPreferences 전문입니다.

 

public class SharedPreferencesManager {

    private static final String PREFERENCES_NAME = "my_preferences";

    public static SharedPreferences getPreferences(Context mContext){
        return mContext.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE);
    }
    
    public static void clearPreferences(Context context){
        SharedPreferences prefs = getPreferences(context);
        SharedPreferences.Editor editor = prefs.edit();
        editor.clear();
        editor.apply();
    }

    public static void setLoginInfo(Context context, String email, String password){
        SharedPreferences prefs = getPreferences(context);
        SharedPreferences.Editor editor = prefs.edit();
        editor.putString("email", email);
        editor.putString("password", password);

        editor.apply();
    }

    public static Map<String, String> getLoginInfo(Context context){
        SharedPreferences prefs = getPreferences(context);
        Map<String, String> LoginInfo = new HashMap<>();
        String email = prefs.getString("email", "");
        String password = prefs.getString("password", "");
        
        LoginInfo.put("email", email);
        LoginInfo.put("password", password);

        return LoginInfo;
    }
    
}

 

 

+ apply와 commit의 차이점!

commit()은 동기, apply()는 비동기 처리 됩니다.

오늘 라이브러리 Gson을 사용하다가 마주한 에러.

 

com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 331

 

다른 곳에서 사용한 Gson parsing 코드를 그대로 복사붙여넣기했는데 특정 activity에서만 에러가 떠서 여기저기 뜯어보다가 알게됐다.

 

gson.fromjson(); 이 부분에서 터지는데, 결론적으로는 받아온 json의 값이 내가 준비해둔 class와 달라서. 

 

원인을 찾아내면 해결책은 생각보다 간단하다.

 

1. 서버에서 Class를 수정한다.

2. 클라이언트에서 Class를 수정한다.

 

내 경우에는 1번이 정답이었다. JSONObject를 갖고있는 JSONArray를 넘겨주고 있었는데, 받아온 배열 중 JSONObject가 아닌 스트링을 보내고 있어서 자꾸 에러가 터졌다.

안녕하세요.

안드로이드 스튜디오 java언어로 QR코드 스캐너를 만들 일이 있었는데 제대로 정리를 하기 위해 글을 써봅니다.

 

1. 준비

 

저는 ml kit의 바코드 스캐닝을 받아와서 써야하기 때문에 앱 모듈의 그레이들에 필요한 요소들을 추가해줍니다.

 

디버그용과 릴리즈용, 출시된 앱에 따라 추가해야하는 코드가 다르니 꼭 확인 후 추가해주세요.

 

https://developers.google.com/ml-kit/vision/barcode-scanning/android

 

Scan Barcodes with ML Kit on Android  |  Google Developers

Scan Barcodes with ML Kit on Android You can use ML Kit to recognize and decode barcodes. There are two ways to integrate barcode scanning: by bundling the model as part of your app, or by using an unbundled model that depends on Google Play Services. If y

developers.google.com

 

그리고 jetpack의 카메라X를 쓸 예정이라 그것도 들고와서 추가해줍시다.

 

https://developer.android.com/jetpack/androidx/releases/camera

 

CameraX  |  Android 개발자  |  Android Developers

CameraX CameraX가 Jetpack에 추가되어 앱에 카메라 기능을 더 쉽게 추가할 수 있습니다. 라이브러리는 다양한 호환성 수정사항과 해결 방법을 제공하여 많은 기기에서 개발자 환경을 일관되게 유지하

developer.android.com

 

하지만 !!!!!!

21.12.04 날짜를 기준으로 공식 문서에 있는 최신 카메라X를 적용시 sdk 31버전과 충돌이 있는 것 같아요.

그래서 다음과 같은 에러가 발생합니다.

 

java.lang.NoSuchMethodError: No static method getOrCreateInstance

 

이럴 경우 카메라X의 이전 버전을 들고와서 적용해줍니다.

 

def camerax_version = "1.0.1"
// CameraX core library using camera2 implementation
implementation "androidx.camera:camera-camera2:$camerax_version"
// CameraX Lifecycle Library
implementation "androidx.camera:camera-lifecycle:$camerax_version"
// CameraX View class
implementation "androidx.camera:camera-view:1.0.0-alpha27"

 

추가가 끝났다면 카메라 사용을 위한 퍼미션 체크를 해주세요.

카메라 퍼미션은 다루지 않겠습니다.

 

2. xml

카메라를 보여줄 화면을 만들어줍니다.

카메라X의 프리뷰를 xml에 예쁘게 넣어봅시다.

 

<androidx.camera.view.PreviewView
    android:id="@+id/camerax_preview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:importantForAccessibility="no"
    />

 

 

3. 카메라 뷰 바인딩

 

카메라X 세팅을 해주고 이미지를 분석할 수 있는 준비를 해줍시다.

이미지를 분석하기 위해서는 executor와 analyzer가 필요합니다. 

 

imageAnalysis.setAnalyzer(cameraExecutor, myImageAnalyzer);

(분석시키기 위해 cameraExecutor와 analyzer를 넣어줘야하는 모습)

 

 

 

executor는 ExecutorService 외에도 터프하게

 

Executor executor = Executors.newSingleThreadExecutor(); 

 

초기화 해서 사용 가능합니다. 저는 ExecutorService를 사용했습니다.

 

public class MainActivity extends AppCompatActivity {

    private PreviewView mPreviewView;
    private ListenableFuture cameraProviderFuture;
    private ExecutorService cameraExecutor;

    private MyImageAnalyzer myImageAnalyzer;

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

        init();
    }

    private void init(){
        mPreviewView = findViewById(R.id.camerax_preview);

        cameraExecutor = Executors.newSingleThreadExecutor();
        cameraProviderFuture = ProcessCameraProvider.getInstance(this);
        myImageAnalyzer = new MyImageAnalyzer(this.getSupportFragmentManager());

        cameraProviderFuture.addListener(new Runnable() {
            @Override
            public void run() {
                try {
                    ProcessCameraProvider processCameraProvider = (ProcessCameraProvider) cameraProviderFuture.get();
                    bindPreview(processCameraProvider);
                } catch (ExecutionException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, ContextCompat.getMainExecutor(this));


    }

    private void bindPreview(ProcessCameraProvider processCameraProvider) {
        Preview preview = new Preview.Builder().build();
        CameraSelector cameraSelector = new CameraSelector.Builder()
                .requireLensFacing(CameraSelector.LENS_FACING_BACK)
                .build();

        ImageCapture imageCapture =new ImageCapture.Builder().build();
        ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
                .setTargetRotation(Surface.ROTATION_270)
                .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                .build();
        preview.setSurfaceProvider(mPreviewView.getSurfaceProvider());

        imageAnalysis.setAnalyzer(cameraExecutor, myImageAnalyzer);

        processCameraProvider.unbindAll();
        processCameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture, imageAnalysis);

    }

 

 

이제 카메라 준비가 끝났습니다.

카메라로 가져온 이미지에서 정보를 가져오는 스캐닝 작업을 해주기 전에!!

 

 

내부 클래스로 analyzer를 만들어줍니다.

공식에서 적어준걸 가져옵시다.

 

https://developers.google.com/ml-kit/vision/barcode-scanning/android#java

 

Scan Barcodes with ML Kit on Android  |  Google Developers

Scan Barcodes with ML Kit on Android You can use ML Kit to recognize and decode barcodes. There are two ways to integrate barcode scanning: by bundling the model as part of your app, or by using an unbundled model that depends on Google Play Services. If y

developers.google.com

 

public class MyImageAnalyzer implements ImageAnalysis.Analyzer{
    private FragmentManager fragmentManager;

    public MyImageAnalyzer(FragmentManager fragmentManager) {
        this.fragmentManager = fragmentManager;
    }

    @Override
    public void analyze(@NonNull ImageProxy image) {
        scanBarcode(image);
    }
}

 

 

4. 바코드 스캐닝

 

analyzer 에서 던져주는 ImageProxy를 분석하는 코드입니다.

 

private void scanBarcode(ImageProxy image) {

    //input image
    @SuppressLint("UnsafeOptInUsageError") Image image1 = image.getImage();
    InputImage inputImage = InputImage.fromMediaImage(image1, image.getImageInfo().getRotationDegrees());

    BarcodeScannerOptions options =
            new BarcodeScannerOptions.Builder()
                    .setBarcodeFormats(
                            Barcode.FORMAT_QR_CODE,
                            Barcode.FORMAT_AZTEC)
                    .build();

    //Get an instance of BarcodeScanner
    BarcodeScanner scanner = BarcodeScanning.getClient(options);

    //process the image
    Task<List<Barcode>> result = scanner.process(inputImage)
            .addOnSuccessListener(new OnSuccessListener<List<Barcode>>() {
                @Override
                public void onSuccess(List<Barcode> barcodes) {
                    readerBarcodeData(barcodes);
                    Log.d("cameraSuccess::", barcodes.toString());
                }
            })
            .addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception e) {
                    // Task failed with an exception
                    // ...
                    Log.d("cameraFail::", e.toString());
                }
            })
            .addOnCompleteListener(new OnCompleteListener<List<Barcode>>() {
                @Override
                public void onComplete(@NonNull Task<List<Barcode>> task) {
                    image.close();
                }
            });
}

 

BarcodeScannerOptions 에서 옵션을 다르게 선택하면 QR코드가 아니라 바코드를 읽어낼 수 있습니다.

지금은 QR코드만 스캔할 수 있도록 옵션을 설정해두었습니다.

 

이렇게 성공적으로 바코드 스캔까지 마쳤으면 바코드가 담고있는 정보를 가져와 정제를 해줍니다.

 

//get information barcode
private void readerBarcodeData(List<Barcode> barcodes) {
    for (Barcode barcode: barcodes) {
        Rect bounds = barcode.getBoundingBox();
        Point[] corners = barcode.getCornerPoints();

        String rawValue = barcode.getRawValue();

        int valueType = barcode.getValueType();

        // See API reference for complete list of supported types
        switch (valueType) {
            case Barcode.TYPE_WIFI:
                Toast.makeText(this, "wifi", Toast.LENGTH_SHORT).show();

                String ssid = barcode.getWifi().getSsid();
                String password = barcode.getWifi().getPassword();
                int type = barcode.getWifi().getEncryptionType();

                cameraExecutor.shutdownNow();

                break;
            case Barcode.TYPE_URL:
                Toast.makeText(this, "url", Toast.LENGTH_SHORT).show();
                String title = barcode.getUrl().getTitle();
                String url = barcode.getUrl().getUrl();

                cameraExecutor.shutdownNow();

                break;
        }
    }
}

 

바코드가 담고있는 정보의 타입에 따라 어떻게 다룰것인지 나눠줍니다.

url을 받아왔으면 intent로 넘겨줄 수 있겠네요!

 

 

이렇게 끝!

일 줄 알았겠지만 현재 사용중인 액티비티가 꺼질때 백그라운드에서 카메라가 돌지 않도록 꺼줍시다.

꺼주지 않으면... 혼나요.

 

private void closeCamera(){
    if (cameraProviderFuture != null && cameraExecutor != null){
        cameraProviderFuture.cancel(true);
        cameraProviderFuture = null;
        cameraExecutor.shutdown();
        cameraExecutor = null;
    }
}

 

저는 그냥 null을 박아버렸습니다.

사실 더 좋은 방법이 있지 않을까 싶은데 없애주는 게 마음이 편해요.

카메라 꺼주는 메소드를 만들어서

 

@Override
protected void onPause() {
    super.onPause();
    closeCamera();
}

@Override
protected void onDestroy() {
    super.onDestroy();
    closeCamera();
}

 

이렇게 붙여줍니다.

onPause에서 카메라를 없앴으니 onResume에서는 다시 켜줘야겠죠!!

 

코드 전문은 깃헙을 참조해주세요.

 

https://github.com/jmnl225/QRcodeScanner

 

GitHub - jmnl225/QRcodeScanner

Contribute to jmnl225/QRcodeScanner development by creating an account on GitHub.

github.com

 

+ Recent posts