kotlin + Android - Intent~Network Programming

HoJeong Im·2022년 9월 2일
0
post-thumbnail
post-custom-banner

Review

  • 회사마다 고유 프로세스 & CI/CD가 있고 정리가 필요합니다.

  • 개발 산출물을 올리는 Android의 경우는 프로젝트 단위로 올리지만...

  • RecyclerView 이용률이 정말 높습니다.

    • 약간만 개발을 해보면 => 코드가 외워집니다

    • Fragment도 유명

  • intent부터 어려워합니다. => 원론적인 이야기

  • 개발자들마다 성향 차이가 정말 많다

    • 팀에 들어가서 개발을 lead, 기술 추구하고 싶다면 => 아키텍처, 전체적인 구조에 집중하는 것이 맞다

    • 계속 그 수준에서만 놀게 될 수 있습니다.

    • 아키텍처를 파악하지 않으면 한계가 존재한다

  • 명시적 intent : 내부적으로 사용

  • 암시적 intent : 외부적으로 사용

    • ex) 구글 기본 앱 => 자기 activity에 intent가 달려있다

Activity Intent 동작 방식

  • 구글링을 통해서 또는 기본 앱은 소스가 open되어 있어요

    • 안드로이드 앱에서 social login을 제공하고 싶다면 핸드폰에 있는 네이버, 카카오를 활용합니다.

    • 카카오, 네이버 개발자 사이트 참고

  • 명시적 intent : class 명 => 오타가 나면 컴파일 에러가 발생합니다.

    • class명이라 중복될 일도 없음
  • 암시적 intent : action, category, data 정보 등을 제공합니다.

    • action 문자열은 컴파일러가 체크할 수 없어 => 문자열이라

    • Error => Runtime Error가 나서 intent 정보 잘못되었다고 에러 발생

  • 실행할 activity가 없을 때, 1개일 때, 여러 개일 때 시스템이 어떻게 처리하는가?

    • 없을 때 : intent를 시작한 곳에 오류가 발생

    • 1개일 때 : 문제없이 실행합니다.

    • n개일 때 : 사용자 선택으로 하나만 실행합니다.

    • ex) 갤러리 앱의 UI 스타일을 따라가는게 좋지 않을 수도..

  • 그만큼 이용이 된다는 것은, 경쟁력을 가진다

    • 구글 지도의 activity intent 정보와 동일 정보를 카카오에서 지정해버리면?

    • 클릭했을 때, 구글/네이버/카카오 지도를 선택해서 보게 하는 예시

  • n개일 때, 사용자 선택으로 하나만 실행합니다.

    • 만약 다 실행된다면, 사용자 악성 앱일 수도? => 유저 선택

    • 시스템 다이얼로그 창이 뜬 경우를 볼 수 있습니다.

  • 인텐트로 실행할 Activity가 없을 수도 있는 상황을 고려

val intent = Intent("ACTION_HELLO")

try {
	startActivity(intent)
}
catch(e: Exception) {
	Toast.makeTest(this, "no app...", Toast.LENGTH_SHORT).show()
}
  • 여러 개라면 사용자가 선택하는 대로 하나만 실행
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("geo:37.7749,127.4194))

startActivity(intent)
  • 특정 앱의 Activity를 실행하고 싶다면 해당 앱의 패키지명을 지정
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("geo:37.7749,127.4194))
intent.setPackage("com.google.android.apps.maps")
startActivity(intent)

Activity의 state

  • LifeCycle : Activity가 생성되어 소멸하기까지의 과정

  • 실전에서 그만큼 성능이 중요시되는 부분

  • Activity 상태는 3가지로 구분!

  • setContentView : 화면출력 함수가 아님 => 화면 버퍼출력 함수

  • 일반적으로는 view를 최초의 한 번만 출력하고, 데이터만 교체합니다.

    • start, Resume은 동일한 뷰를 반복 출력하기 때문에 문제가 생깁니다.

    • 출력 내용이 다 다르다면? 여러번 호출해도 에러나지 X

    • 무조건 맨 마지막 명령이 나옵니다. => 기본 화면 위에 view를 올리는 것

  • 테마 설정으로 투명하게 Activity를 띄워서 밑의 이벤트를 안 가게 할 수도 있습니다.

  • 화면이 나오고 있는데 시스템이 죽지는 않은 경우 => 메모리가 부족해서

    • 시스템에서 우선순위가 낮은 것들부터 KILL(비활성화 상태가 오래된 경우)

    • 활성 상태는 우선순위가 높음

    • 모든 함수를 다 쓰라는 게 아닌, 적절하게 생명주기 함수를 사용하라는 것

  • 과도한 네트워크 트래픽을 발생시키는 앱 = 악성 앱으로 평가받는 경우가 많음

액티비티의 상태 저장

  • 액티비티가 종료되면 객체가 소멸하므로 액티비티의 데이터는 모두 사라집니다

  • 상태를 저장한다는 것은 액티비티가 종료되어 메모리의 데이터가 사라지더라도

    • 다시 실행할 때 사용자가 저장한 데이터로 액티비티의 상태를 복원하겠다는 의미
  • 화면을 회전하면 액티비티가 종료되었다가 나옵니다. 따라서 액티비티의 데이터는 초기화됩니다.

  • 개발자 편하자고 User-friendly를 포기한다?

  • 여러가지를 하나의 앱에 돌아올 수 있음 => 무엇이 되돌아온 건지 requestCode를 지정할 수 있습니다

저장소에 데이터 보관하기

  • 클라이언트 Device에서 백엔드 데이터를 direct로 취급을 한다?

  • 방화벽 설정을 해서 특정 IP에서만 들어올 수 있게 해줌

  • 데이터 영속화 = 여기서 로컬을 얘기하는 것

  • 누군가의 도움받지 않고 화면을 출력하는 것 = 프론트

  • 프로세스가 종료되어도 데이터가 유실되면 X => 영속화

  1. File Read/Write
  • 로컬에다가 => 파일이 삭제될 일이 없어

  • 쉽게 생각할 수 있는 데이터 영속화 주제

  • 문자열, 숫자, boolean 값이라면 쓰지 말자 => 훨씬 더 쉬운 게 있음

  • image 때문에 로컬에 읽고 쓰는 것은 많이 빈번합니다

  1. SharedPreference : 클래스 명 => map이라고 생각하자
  • Map(key, value) : file(xml) 파일

  • 이미지는 직접 handling, 문자열, 숫자 값은 put으로 저장 끝

  1. Database (로컬)
  • 테이블 만들고, insert,update,delete 시켜 영속화하는 것
  • 클라이언트 side에 저장을 많이 하지만, 로컬 Device에 저장을 한다는 것은 server-side에 업로드할 필요가 없는 데이터를 저장한다.

    • 앱 설정이 대표적인 예
  • sharedPreference는 구조화가 안 되어 건 바이 건

  • 로컬 데이터베이스를 쓰는 이유는 대량의 데이터를 구조화하기 위해서 사용합니다.

  • 네트워킹이 안 되었을 때, 어떻게 움직일까? 테스트는 무조건 필수

    • ex) WIFI 달라붙는 사이에, 네트워킹 안 되었을 때 => 비행기 모드로 하고 앱이 어떻게 반응하는지 테스트
  • 대부분의 비즈니스 데이터는 서버 데이터 => 로컬에 다 저장을 함

    • 네트워크 트래픽이 과도해질 수 있어서

    • 또한, 엘리베이터에서 실행하면 화면이 안 보일때 => 사용자는 안 된다는 불편함을 느낌

  • 이미지도 데이터 => 서버에서 쓰지만, 로컬에다가 다 캐싱을 합니다.

  • DB가 제일 걷어내기 힘들다.

  • SQLite : 프론트 쪽 데이터베이스 => 경량 DB 목적

    • 가전제품, 펌웨어에 들어갔었음

    • 몇몇의 한계가 존재합니다.

  • 구글에서 ORM 제공할 수 없다 => 모바일 쪽에서 => performance가 나오지 않음

SQLite

  • 질의문 작성하기

    • SQLite를 사용하려면 SQLiteDatabase라는 API 이용

    • SQLiteDatabase객체는 OpenOrCreateDatabase() 함수를 호출해서 얻습니다.

val db = openOrCreateDatabase("testdb", Context.MODE_PRIVATE, null)
  • SQLiteDatabase 객체에 정의된 다음 함수를 이용하면 질의문을 실행

db.execSQL(~~~)
  • 동기면 select, insert의 returnType이 같을 수 없음

  • 비동기면 함수가 하나여도 상관이 없습니다.

  • JDBC의 ResultSet과 완전히 동일한 Cursor

    • JDBC는 컬럼명의 데이터를 뽑을 수 있지만, SQLite는 그건 안 됨

데이터베이스 관리하기

  • SQLiteOpenHelper 클래스를 이용하면 데이터베이스 프로그램을 좀 더 구조적으로 작성할 수 있습니다.

  • SQLiteOpenHelper는 추상 클래스이므로 이를 상속받아 하위 클래스를 작성

    • DBMS를 위한 것

      • table create
    • onCreate() : App이 설치된 후 SQLiteOpenHelper 클래스가 이용되는 순간 한 번 호출합니다.

    • onUpgrade() : 생성자에 지정한 DB 버전 정보가 변경될 때마다 호출됩니다.

  • 데이터베이스 관리적인 부분을 SQLiteOpenHelper 클래스를 통해 추상화 시켜 다른 쪽에서 신경쓰지 않게 하자는 목적

class DBHelper(context: context): SQLiteOpenHelper(context, "testdb", null, 1) {
	
    override fun onCreate(db: SQLiteDatabase?) {
    
    }

	override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
    
    }
}
val db = SQLiteDatabase = DBHelper(this).writableDatabase
  • 안드로이드 앱에서 파일을 다룰 때는 대부분 java.io 패키지에서 제공하는 클래스를 이용

    • File: 파일 및 디렉터리를 지칭하는 클래스
    • FileInputStream / FileOutputStream: 파일에서 바이트 스트림으로 데이터를 읽거나 쓰는 클래스
    • FileReader / FileWriter: 파일에서 문자열 스트림으로 데이터를 읽거나 쓰는 클래스입니다.

  • 내장과 외장이 구분이 된다.

  • 핸드폰을 USB로 연결해서 보면 외장 메모리 밖에 안 보입니다. - 내장 메모리는 우리가 볼 수 없습니다.

  • 외장 메모리는 앱별 저장소, 공용 저장소가 존재합니다.

    • 카메라가 공용 저장소를 사용하는 대표적인 앱입니다.
    • 내장 메모리는 공개 자체가 안 되고, 외장 메모리는 공개하면 외부에서 접근이 가능해집니다.

    내장, 외장 메모리의 파일 이용하기

  • App의 패키지명으로 디렉토리를 만들어 주는데, 이 디렉터리가 바로 App의 내장 메모리 공간

  • 파일을 내장 메모리에 저장하려면 java.io의 File 클래스를 이용

  • Environment.getExternalStorageState() 함수러 외장 메모리를 사용할 수 잇는지부터 확인

  • 내장 메모리는 어차피 자기 밖에 이용안함

    • 외장은 다름 => 매니페스트 설정

    • 자기 정보를 노출하는 것은 민감할 수 있음 => 퍼미션 보호되어 있는 정보를 이용한다? => 에러가 발생합니다.

<manifest ...>
  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  <application
    android:requestLegacyExternalStorage="true">
  </application>
</manifest>
  • 앱별 저장소 이용

    • 외장 메모리 공간 = 앱별 저장소 + 공용 저장소

    • 앱별 저장소는 개별 앱에 할당된 공간

    • 앱별 저장소의 파일을 외부 앱에서 접근하게 하려면 파일 프로바이더로 공개해야 합니다.

      • ex) 우리 앱에서 카메라 앱을 연동해, 카메라 앱에서 사진 찍고 갤러리 앱에 저장하지 않는 것
    • 외장 메모리의 앱별 저장소 위치는 getExteranlFileDir를 이용

  • 프로젝트의 res/xml 디렉토리에 xml 파일을 만들고 이 파일에서 외부 앱에 공개할 경로를 지정

공유된 preference에 보관하기

  • 플랫폼 API에서 제공하는 클래스로, 데이터를 key-value 형태로 저장

  • 영속적으로 저장할 데이터가 있지만, 많지도 않고 구조화가 필요 없음

    • 대표적 예) 앱 설정(~할 거냐, 말 거냐, dialog-> 글 입력받는 설정, 알림 설정정)

        1. UI구성을 해주어야 함 => RecyclerView
        • 항목에 layer.xml을 3~4개 만들어주어야 함
        1. 카카오톡 설정 화면 같은 경우 => 화면이 몇 장이 나오든
        • UI도 중요하지 않으면 => Event도 안 중요해짐

          • 설정과 관련된 xml 파일만 만들면... (설정 화면은 거의 입력이 많지 않음)

          • Fragment에서 이 xml파일 설정을 한줄만 하는 것으로 작성할 수 있음

  • SharedPreferences를 사용하는 방법

  • 카카오톡 => 로그인 지속 기법을 이용해

    • 설정 데이터가 있는지 파악하는 것입니다.

    • 보안 : 서버에서 인증받은 토큰

    • 설정 저장말고 추가 이벤트 처리가 필요함

  • 설정화면 구성 시, Activity를 직접 작성하는 일이 거의 없음

  • manifest에 설정이 되어 있어 => 우클릭 해서 설정을 실행시킬 수 있습니다.

Network Programming

  • 스마트폰 정보 구하기

    • 전화 상태 변화 감지하기 : PhoneStateListener

      • 스마트폰의 상태를 파악하는 방법은 PhoneStateListener, TelephonyCallback을 이용하는 방법

      • 비즈니스 벤더에서 이용할 가치가 있는 것이 있고, 아닌 것이 존재합니다.

  • callState : 전화 대기 상태

    • 전화 걸려오는 상황이 User 입장에서 가장 중요한 상태입니다

    • setLocation : 위치 이용하는 것

    • 스마트폰의 GPS 정보 이용

      • 위, 경도로 잡아낼 수 있음
  • 하나의 기지국이 관리하는 영역을 cell이라고 합니다.

    • 다른 cell로 이동했다 => 그 때마다 사용 => third party에서는 의미 x

      • 더 정확한 방법이 있음
  • TelephonyManager : getLine1Number : 스마트폰의 전화번호

    • getNetworkCountryIso: 네트워크 제공 국가
  • ConnectivityManager : 네트워크 접속 정보

    • 데이터 통신을 위한 네트워크 상태 정보(현재 네트워킹 가능하냐, 불가능하냐)

    • 가능하다면? WIFI인지 이통사 네트워크인지 확인이 가능합니다.

    • 디바이스의 일시적인 문제로 서비스를 띄울 수 없습니다와 같은 문구 출력이 이 정보를 활용해서 가능합니다.

  • NetworkRequest 객체에 네트워크 타입을 설정한 후 객체를 requestNetwork 함수의 두 번째 매개변수로 지정

HTTP 통신하기

  • 안드로이드 앱은 네트워크 통신을 할 때 기본으로 HTTPS 보안 프로토콜을 사용

  • 만약 일반 HTTPS 프로토콜로 통신하려면 특정 도메인만 허용하도록 선언

<uses-permission android:name="android.permission.INTERNET" />

Retrofit library

  • Retrofit : HTTP 통신을 간편하게 만들어 주는 lib

  • 네트워크 통신 정보만 주면 그대로 네트워크 프로그래밍을 대신 구현

  • 동작 방식

  1. 통신용 함수를 선언한 인터페이스를 작성합니다.
  2. Retrofit에 인터페이스를 전달합니다.
  3. Retrofit이 통신용 서비스 객체를 반환합니다.
  4. 서비스의 통신용 함수를 호출한 후 Call 객체를 반환합니다.
  5. Call 객체의 enqueue 함수를 호출하여 네트워크 통신을 수행합니다.
  • annotation을 활용합니다.

  • 라이브러리 선언

    • Retrofit은 JSON이나 XML 데이터를 모델(VO 클래스) 객체로 변환

    • JSON, XML을 파싱하는 라이브러리가 필요

    • 파싱 lib에 맞는 converter lib가 필요

  • 니네가 원하는 JSON Parser를 하나 설정해서 사용하자

  • 모델 클래스 선언

    • 모델 클래스의 property에 데이터가 자동으로 저장되는 기본 규칙은 데이터의 키와 프로퍼티 이름을 매칭

    • 만약 키와 프로퍼티 이름이 다를 때는 @SerializedName이라는 annotation으로 명시

  • 서비스 인터페이스 정의

    • @GET은 서버와 연동할 때 GET 방식으로 해달라는 의미

    • @Query는 서버에 전달되는 데이터

    • @Url은 요청 URL

  • Retrofit 초기화 => 인터페이스 타입의 서비스 객체 얻기

  • 인터페이스의 함수를 호출하면 네트워크 통신을 시도

Glide lib

  • 이미지 처리하기, 이미지 핸들링에 가장 유리

  • 네트워크 상의 이미지 다운로드에 가장 핵심

Glide.with(this)
	.load(R.drawable.seoul)
    .into(binding.resultView)

참고!

  • ktx가 추가된 lib는 java 라이브러리를 kotlin으로 전환시킨 것
profile
꾸준함이 제일 빠른 길이었다
post-custom-banner

0개의 댓글