[Android] 안드로이드 이슈 정리

앱 개발 도중 기억하고 싶은 이슈를 적는 곳

목차

안드로이드 용어 정리
안드로이드 생애주기
Java와 Kotlin이 다른점
정적 변수 및 메서드 사용하기
함수 리턴형 숨기기
Gradle 꿀팁

안드로이드 용어 정리

어렴풋이 알고 있었던 안드로이드의 용어들을 정리한다.

  • Activity (액티비티)

    • 애플리케이션 구성요소 중 “화면” 을 제공하는 단어
    • 주로 화면에 보이는 UI와 상호작용할 수 있는 화면을 제공한다.
  • Interface (인터페이스)

    • 함수들의 묶음을 정의해두기 위해 만든 개념
    • 내부의 함수들은 다른 Class에서 정의한다.
  • boilerplate code(보일러 플레이트 코드)

    • 표준 문안이라는 뜻의 단어

    • 꼭 필요하지만 반복적이고 중복이 많아 코드가 길어져 불편하다.

    • 최소한의 변경으로 재사용할 수 있는 것

    • 적은 수정만으로 여러 곳에 활용 가능한 코드, 문구

    • 각종 문서에서 반복적으로 인용되는 문서의 한 부분

  • Annotation (애노테이션)

    • 메타데이터 클래스
    • @를 붙여 다른 클래스나 메소드, 필드, 다른 애노테이션과 결합되어 사용
    • 추가적인 정보를 제공하는 대안이 됨
    • 애노테이션을 활용하면 코드가 컴파일시간에 생성되므로
      보일러 플레이트 코드를 줄일 수 있다.
  • DAO (Data Access Object)
    • Database 의 data 에 접근을 하기 위한 객체
    • DB에 접근을 하기위한 로직과, 비즈니스 로직을 분리하기 위해서 사용함
  • DTO (Data Transfer Object)
    • (Value Object 와 같음) 계층간 데이터 교환을 위한 Java Beans 를 말함
    • 로직을 갖고 있지 않는 순수한 데이터 객체이며 속성과 그 속성에 접근하기위한 클래스
    • 주로 getter, setter 이 적힌 클래스

안드로이드 생애주기

어렴풋이 알고 있었던 안드로이드의 생애주기를 정리한다.

  • 안드로이드 시스템은 어느 특정한 main() 함수가 없다.
  • Activity 를 초기화하고, 여기에 있는 콜백 함수들이 호출되게 한다.
    • 맨 처음 앱을 누르면 Manifest 에 MAIN 으로 지정된 Activity 내의 onCreate() 함수가 실행된다.

Lifecycle에 따른 기본적인 기능만 정리한다.

  1. onCreate()

    • Activity 를 처음 실행할 때 딱 한번만 호출된다.
    • 딱 한번만 발생하는 로직을 담아야 하므로 변수초기화, 클래스 인스턴스화 등의 작업을 한다.
  2. onStart()

    • onCreate()가 실행된 이후에 호출된다.
    • Activity 가 Foreground에 나오기 전에 수행되므로 UI를 관리하는 코드를 작성한다.
  3. onRestart()

    • onStart()와는 달리 앱이 실행될때는 실행되지 않는다.
    • onStop() -> onRestart() 일때만 실행된다.
  4. onResume()

    • onStart()가 수행된 이후에 호출된다.
    • Activity에 포커스가 맞춰져있는동안 onResume()의 상태가 유지된다.
    • 앱이 포커스를 되찾으면 onPause()를 거쳐 onResume()이 다시 수행될 수 있다.
    • 대부분의 자주 사용하는 메소드(새로고침 후에 사용되는)를 적는다.
  5. onPause()

    • Activity의 포커스가 다른곳으로 이동하면 호출된다.
    • 앱을 종료하는것 뿐만아니라 일시적인 포커스 이동에도 수행된다.
    • 메모리나 배터리 소모를 일으키는 자원을 해제하는 로직을 구현한다.
    • onResume()이 했던 작업들을 저장하거나 멈추게 한다.
    • Activity가 다시 재개되면 onResume()이 다시 수행된다.
  6. onStop()

    • onPause() 이후 단계로 액티비티가 활동을 중지한 상태이다.
    • 대부분의 자원을 해제해야한다.
    • 이후에 Activity가 재개되면 onRestart()를 통해 onStart()를 실행한다.
  7. onDestroy()

    • 앱이 종료되는 최종단계로 모든 리소스를 해제한다.
Activity 수행 예시
  1. 앱을 실행했을때
    • onCrate() -> onStart() -> onResume()
  2. Activity 1에서 Activity 2를 생성했을때
    • Activity 1 : onPause() -> onStop()
    • Activity 2 : onCreate() -> onStart() -> onResume()
  3. Activity 2를 종료하고 1로 돌아왔을때
    • onRestart() -> onStart() -> onResume()
  4. 홈키를 눌러서 백그라운드로 전환됐을 때
    • onPause() -> onStop()
  5. 다시 돌아왔을 때
    • onRestart() -> onStart() -> onResume()
  6. 앱을 종료할 때
    • onPause() -> onStop() -> onDestroy()

5. Java와 Kotlin이 다른점

  • 상속
    • 생성자가 있는 class를 상속했을때는 무조건 생성자를 받아야 한다.
    • Extends
      • 부모 클래스에서 선언/정의를 모두 하고 자식은 그대로 사용만 할수 있게 상속하는 명령어
      • 코틀린에선 Extends나 Implements나 콜론으로 통일함
    • Implements
      • 부모 클래스에서 선언만 하며 정의는 자식 클래스에서 오버라이드하도록 상속시키는 명령어
      • 코틀린에선 Extends나 Implements나 콜론으로 통일함
    • Abstract
      • extends로 사용하지만 abstract로 선언된 클래스는 interface도 가질 수 있음
    • Super / this
      • super은 상위 클래스에서 멤버변수/메소드를 가져옴
      • this는 현재 클래스에서 멤버변수/메소드를 가져옴
  • Java에서 생성자 사용하는 방법

    1
    2
    3
    4
    5
    6
    public class testClass {
    String example;
    testClass(String example2){
    this.example = example2;
    }
    }
    • 생성자를 따로 만들어서 내부변수를 this로 선언해서 매개변수를 받아야 한다.
  • Kotlin에서 생성자 사용하는 방법

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    class testClass(var example: String){
    println("매개변수 : $example")
    }

    // 부를때
    class testClass2(example2 : String) : testClass(example2) {
    println("example2 를 매개변수로 testClass를 상속받음")
    }

    ------------------------------------------------------------------------

    class testClass(num : Int){
    var example : String = ""
    constructor(example2 : String, num : Int) : this(num){
    // 기본 생성자를 상속받아야 한다.
    this.example = example2
    }
    }
    • 생성자는 (var example: String) 이고, 따로 변수 선언없이 바로 사용 가능하다.
    • constructor() 함수를 사용하면 추가적으로 매개변수를 받아서 사용할 수 있다.
    • 인터페이스는 class로 상속받을경우 내부에 있는 모든 함수를 override 해야 한다.
1
2
3
4
5
6
7
8
9
10
11
12
//Dagger2 + constructor 예시

class MainInteractor
@Inject internal constructor(
private val questionRepoHelper: QuestionRepo,
private val optionsRepoHelper: OptionsRepo,
preferenceHelper: PreferenceHelper,
apiHelper: ApiHelper
) : BaseInteractor(
preferenceHelper = preferenceHelper,
apiHelper = apiHelper
), MainMVPInteractor {
  • BaseInteractor 을 상속받기위해 인자인 preferenceHelper, apiHelper 를 생성자로 받아야함
  • MainMVPInteractor 는 interface 이므로 그냥 상속
  • questionRepoHelper 는 클래스 내부에서 사용하기 위한 객체이므로 선언
  • optionRepoHelper 는 클래스 내부에서 사용하기 위한 객체이므로 선언
  • Java에서는 매개변수자리에 … 을 사용하면 varargs, 가변인자가 된다.

정적 변수 및 메서드 사용하기

  • 정적 변수를 사용하면 [클래스명].[함수명]혹은 [클래스명].[상수명]
    등으로 활용 가능하다.

  • 사용처

    • 액티비티/프래그먼트의 인텐트 Extra로 사용하는 키
    • 로그 출력을 위한 태그(Tag) 이름 정의
    • 뷰 내부에서 사용하는 고정된 길이 값 (너비, 높이 등)
    • 각종 유틸리티 클래스 내 메서드
  • 사용법

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    /* 
    * object(오브젝트) 기본 정의
    */

    object Foo1 {
    val BAR1 = "bar1"
    }


    /*
    * companion object를 이용한 정의
    */

    class Foo2 {
    companion object {
    const val BAR2 = "bar2"
    fun baz() {
    // Do something
    }
    }
    }

    ------------------------------------------------------------

    /*
    * Main Activity에서 object 호출
    */

    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // object 정의된 BAR1 호출
    val str = Foo1.BAR1

    // Foo.baz() 함수 호출
    Foo2.baz()
    }
    • 코틀린에서는 object를 이용해서 클래스를 정의함과 동시에
      객체를 생성할 수 있다
      • Foo1라는 이름을 가진 객체를 생성한 싱글턴 패턴으로 봐도 무방하다
    • companion object 를 이용하면 class 내부에 선언된 private property에
      접근 가능하다
    • 익명 클래스를 구현할때도 object를 이용한다.
      • 익명 클래스 설명은 익명클래스 사용방법 참조
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        /*
        * 익명 클래스 구현
        */

        interface ClickListener {
        fun onClick()
        }

        fun main(args: Array) {
        setClickAction(object : ClickListener {
        override fun onClick() {
        println("clicked!!!")
        }
        })
        }

        fun setClickAction(clickListener: ClickListener) {
        clickListener.onClick()
        }

Gradle 꿀팁

  • Project 영역 gradle 에서 ext 를 선언하면 gradle 내에서 편하게 쓸 수 있다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    // Project 영역

    ext {
    // Sdk and tools
    minSdkVersion = 19
    targetSdkVersion = 29
    compileSdkVersion = 29
    buildToolsVersion = "29.0.2"

    // App dependencies
    kotlinVersion = kotlinVersion
    constraintLayoutVersion = "1.1.3"
    appCompatVersion = "1.1.0"
    }

    --------------------------------------------------------
    // Module 영역

    dependencies {
    // kotlin
    implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"

    // android support libraries
    implementation "androidx.appcompat:appcompat:$rootProject.ext.appCompatVersion"
    implementation "androidx.constraintlayout:constraintlayout:$rootProject.ext.constraintLayoutVersion"

    // dependency injection
    implementation "com.google.dagger:dagger:$rootProject.ext.daggerVersion"
    implementation "com.google.dagger:dagger-android-support:$rootProject.ext.daggerVersion"
    kapt "com.google.dagger:dagger-compiler:$rootProject.ext.daggerVersion"
    }
  • Project 영역 내 android - buildType 에 통신관련 내용을 적으면 안전하게 build 할수 있다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    android {
    buildTypes {
    debug {
    buildConfigField("String", "BASE_URL", "\"http://www.mocky.io/v2\"")
    buildConfigField("String", "API_KEY", "\"ABCXYZ123TEST\"")
    }
    release {
    minifyEnabled true
    proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    buildConfigField("String", "BASE_URL", "\"http://www.mocky.io/v2\"")
    buildConfigField("String", "API_KEY", "\"ABCXYZ123TEST\"")
    }
    }
    }

함수 리턴형 숨기기

코틀린에서는 함수가 return 할때 간단하게 쓸 수 있는 방법이 있다.

1
2
3
4
override fun toString(): String
{
return content
}
1
override fun toString(): String = content
공유하기