2016년 12월 16일 금요일

[안드로이드] Process와 Task 차이

안드로이드의 Process

타 운영체제와 마찬가지로, 실행가능한 프로그램 데이터가 메모리로 로드되어 실행된 것을 프로세스라고 한다. 안드로이드는 리눅스 기반의 OS이므로, 리눅스의 프로세스처럼 각각 ID가 부여되며, 다른 프로세스와 철저히 격리되어 실행된다.

Process의 구등

안드로이드는 앱의 컴포넌트(엑티비티, 서비스, 리시버, 프로바이더)를 실행하는 시점에서, 그 컴포넌트가 메모리로 로드되고, 컴포넌트가 속한 앱의 프로세스가 구동된다.
Note : 앱의 프로세스가 새로 구동될 때마다, 시작점은 Application의 onCreate()메서드이다.

Process 변경

컴포넌트는 기본적으로 앱의 프로세스에 속하지만, 소속 프로세스를 변경할 수도 있다.
메니페스트 파일에서 컴포넌트를 선언할 때, android:process 필드를 지정하면, 이 컴포넌트는 앱의 프로세스와는 별개로, 다른 독립된 프로세스에서 실행된다.
Note : 별도의 프로세스에서 동작하더라도, Application의 onCreate()메서드는 호출된다.(왜그럴까......??)

안드로이드의 Task

앱을 실행하게 되면, 그 앱은 필요한 컴포넌트들을 호출하게 된다. 각 앱마다 현재 사용하고 있는 컴포넌트들을 그룹화하여 관리하는 것이 Task이다. 여기서의 컴포넌트는 해당 앱에 속한 컴포넌트 일수도 있고, 다른 앱에 속한 컴포넌트 일수도 있다.

컴포넌트 교차 생성

안드로이드의 독특한 특징으로, 다른 앱에 속한 컴포넌트를 호출하여 사용할 수 있다. 이렇게 호출된 컴포넌트는 현재 실행되고 있는 앱의 Task에 속하게 된다. 하지만, 호출된 컴포넌트가 메모리에 로드되면, 그 컴포넌트의 원래 프로세스가 구동되며, 컴포넌트가 실행되면서 필요한 권한설정은 원래 앱이 획득한 권한설정을 따르게 된다.
  • ex) 메모앱에서 기본 카메라의 엑티비티를 호출하는 경우
    • 기본 카메라의 엑티비티는 메모앱의 Task로 묶이게 된다.
    • 메모앱이 기본 카메라 엑티비티를 호출하는 시점에, 기본 카메라 앱의 프로세스가 구동된다. 즉, 메모앱의 프로세스와 기본 카메라 앱의 프로세스가 동시에 실행중인 상황이 된다.
    • 기본 카메라 엑티비티가 사용하고자 하는 권한(카메라 접근, 외부저장소 저장 등)은 메모앱의 권한설정이 아닌, 기본 카메라 앱의 권한설정을 따르게 된다. 따라서, 메모앱은 사진관련 권한이 없어도, 기본 카메라 앱에 권한이 있으면 문제없이 이용할 수 있고 반대로, 메모앱이 사진관련 권한이 있어도, 기본 카메라 앱에 권한이 없으면 기능을 이용할 수 없다.

엑티비티 스택

Task는 엑티비티의 순서를 관리하기 위해 별도로 스택을 유지하여 엑티비티를 저장한다. 즉, Task가 지워지면, 엑티비티의 순서도 지워지게 된다.

Task 변경

다른 컴포넌트들에 비해, 엑티비티는 메니페스트에서 <activity>태그의 android:launchMode 필드를 주거나, 엑티비티를 실행할 인텐트에 플래그 값을 추가하여 Task를 변경할 수 있다.(변경이라고는 해도 Task간 이동은 불가능하다.)

2016년 12월 13일 화요일

[안드로이드] Task의 종료시점 확인하기

안드로이드 Task의 종료시점 확인하기

배경

안드로이드는 OS에 의해 프로세스가 강제종료 되는 시점을 알 수 없다. Application 클래스의 onTerminate()메서드조차 가상머신에서만 동작하고 실제 디바이스에서는 동작하지 않는다고 문서에 명시되어 있다.(실제로도 동작하지 않는 것을 확인했다.)
스크린샷 2016-12-01 오전 10.52.37.png

Task?

안드로이드 프로세스와 태스크의 차이

안드로이드에는 Task라는 개념이 있다. Task는 어떤 앱이 실행되면서, 관련 컴포넌트(엑티비티, 서비스, 리시버, 프로바이더)를 묶어놓은 그룹의 개념으로, 프로세스와는 약간 다르다. 그렇지만, 일반적인 앱이라면 하나의 앱을 실행할 때, 하나의 프로세스가 생기며, 그 프로세스에서 실행되는 모든 컴포넌트들은 하나의 Task로 묶이게 된다. 사용자가 확인할 수 있는 최근에 실행된 앱 보기에 나오는 하나의 단위가 바로 Task 이다.
스크린샷 2016-12-01 오전 11.05.02.png

Task 종료시점 알기

OS가 프로세스를 강제종료 시키는 시점은 알 수 없지만, Task가 종료되는 시점은 알 수 있다. 즉, 사용자가 최근에 실행된 앱 보기 화면에서 태스크를 지웠을 때의 시점을 감지할 수 있는 것이다. 한개의 프로세스와 한개의 Task로 구성되어 있는 앱이라면, 이 방법을 통해 사용자가 앱을 강제종료 시키는 시점 정도는 핸들링 할 수 있다.(이것은 프로세스가 종료되는 것과는 엄밀히 다르다. 그러므로, 프로세스의 종료시점과 혼동하여 사용하면 부작용을 초래할 수 있다.)
Service 클래스에는 Task가 종료되었을 때 콜백을 받는 onTaskRemoved()메서드가 존재한다. 이 메서드를 이용해, Task의 종료시점을 잡을 수 있다.

적용방법

1.Manifest에 서비스를 등록한다. 이 때, android:stopWithTask 속성을 반드시 false로 설정해야 한다. true로 설정하면 onTaskRemoved()메서드가 호출되지 않는다.
<application
    ...>
    ...
    <service android:name=".TestService"
                android:stopWithTask="false" />
    ...
</application>
2.Manifest에 선언한 Service를 선언하고, onTaskRemoved()메서드를 오버라이드하고 필요한 내용을 구현한다.
Note : super.onTaskRemoved()를 호출하게 되면, Task가 종료되는 시점에서 프로세스는 재시작된다.(Task는 안보이고 프로세스만 살아있는 형태) Task가 종료되는 시점에서 서비스도 같이 종료시키려면 stopSelf() 메서드를 호출해준다.
public class TestService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    
    @Override
    public void onTaskRemoved(Intent rootIntent) {
        Logger.logWarn("onTaskRemoved - " + rootIntent);
        // 여기에 필요한 코드를 추가한다.,
        
        stopSelf();
    }
}
3.해당 Service를 앱의 시작점에서 시작한다.일반적으로 앱의 시작점은 Application의 onCreate()나 스플래쉬 엑티비티의 onCreate() 메서드일 것이다. Manifest에 등록된 리시버가 없다면, 두가지 방법은 차이가 없지만, 외부 액션을 받는 리시버가 등록되어 있다면, 그 외부액션을 받았을 때 Application의 onCreate()가 실행되기 때문에, 오동작할 우려가 있으므로, 그럴때는 가급적 엑티비티의 onCreate()에서 시작하도록 한다.
public class SplashActivity extends Activity {
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        startService(new Intent(this, TestService.class));
    }
    ...
}

2016년 12월 12일 월요일

[안드로이드] 안드로이드의 특징과 역사

안드로이드

  • 구글의 주도하에 여러 회사들이 Open Handset Aliance 컨소시엄으로 진행하고 있는 모바일 OS
  • 2008년 모바일 첫 장비가 출시된 이후, 현재 모바일, TV, wearable, Auto 등으로 범위가 확장되고 있다.

특징

  • 운영체제 커널은 리눅스 커널을 기반으로 한다. 오픈소스이기 때문에 여러 제조사에서 커널을 변경하여 배포하기도 한다.
  • 공식 개발언어는 자바를 이용하며, 추가적으로 C를 이용해 개발할 수 있는 NDK를 지원한다.
  • OpenGL, SQLite 등 검증된 주요 라이브러리를 모두 포함하고 있다.
  • 플랫폼에 내장된 빌트인 애플리케이션과 일반 사용자가 만든 프로그램이 동일한 레벨로 취급된다.
  • 다양한 제조사, 다양한 기기에 이용되다 보니 파편화 이슈가 심하다.

아키텍쳐

안드로이드_아키텍쳐.PNG
  1. 리눅스 커널을 이용하여 하드웨어 등 저수준 관리 기능을 담당한다.
  2. 라이브러리들과 런타임 머신이 커널위의 계층에 존재한다.
    • 라이브러리 : OpenGL, SQLite, WEBKit 등
    • 런타임 : Dalvic, JAVA 코어 라이브러리, ART(5.0 이후)
  3. 안드로이드에서 자바 라이브러리 형태로 제공하는 API를 프레임워크 계층에 구현했다.
  4. 빌트인 프로그램 및 사용자가 만든 프로그램이 응용프로그램 계층에 존재한다.

안드로이드 History

  • 네이밍규칙 : 알파벳 순서의 디저트 이름

2.1~2.3

  • 버전명
    • 2.1 : 이클레어 (API 7)
    • 2.2 : 프로요 (API 8)
    • 2.3 : 진저브레드 (API 9~10)
  • 주요 특징
    • WallPapersd카드에 앱 설치, 플래시 지원, NFC 지원xhdpi 해상도 지원
    • 태블릿을 지원하기 직전 OS
    • 지금은 사용하는 사람이 없다.(간혹 중소업체의 IoT 디바이스에서 사용)

3.0~3.2

  • 버전명 : 허니컴 (API 11~13)
  • 주요 특징
    • FragmentActionBar등 태블릿 전용 UI 지원, 시스템 Clipboard 지원
    • 드래그 & 드롭 기능 지원
    • Animator 지원(더 유연한 애니메이션 가능)
    • 유일하게 휴대폰과 태블릿으로 쪼개진 버전. (버림받았다.)
    • 지금은 사용하는 사람이 없다.

4.0~4.04

  • 버전명 : 아이스크림 샌드위치 (API 14~15)
  • 주요 특징
    • 휴대폰 & 태블릿 통합 API 제공 - 휴대폰에서도 ActionBar, Fragment 등 3.0에서 추가된 기능 이용가능
    • 안드로이드 OS중 하위 버전과 가장 많은 차이를 보인 OS
    • WifiDirect 지원, 온도계, 습도계 센서 추가, GridLayout 추가
    • 하드웨어 가속 지원(화면 렌더링에 그래픽카드를 이용)

4.1~4.3

  • 버전명 : 젤리빈 (API 16~18)
  • 주요 특징
    • 현재 (${today}) 기준으로 시즌 off된 휴대폰의 최소 버전이다.
    • 4.1(API 16)
      • 메모리 관리방식
      • Camera, Audio 라이브러리 개선
      • Android Beam 지원
      • Notification 스타일 변경
    • 4.2(API 17)
      • DayDream 추가
      • Second Display 지원
      • 잠금화면 위젯
      • 멀티 유저(다중 계정)
      • RTL layout,
    • 4.3(API 18)
      • Bluetooth Low Energy(BLE) 지원
      • Wi-Fi Scan only Mode 추가(WiFi로 유저의 위치정보를 받기 위해)
      • Multimedia 라이브러리 개선
      • OpenGL 3.0 지원, Mipmap 지원, optical bound layout 추가
      • 주소록 API 추가(Contacts Provider)

4.4

  • 버전명 : 킷캣 (API 19, 20)
  • 주요 특징
    • Print Framework추가(클라우드 프린팅 가능)
    • 오디오 터널링 지원
    • Storage Access Framework 추가(저장소 접근 방법 변경)
    • reusable bitmap, Animator pause 추가
    • Immersive Full Screen(전체화면 상태인데 사용자의 터치동작에 따라 상태바가 보여짐)

5.0~5.1

  • 버전명 : 롤리팝 (API 21, 22)
  • 주요 특징
    • 달빅 가상머신을 ART 런타임 으로 대체
    • 64비트 지원
    • 머티리얼 디자인
    • Heads-Up 알림(기존의 작업을 방해하지 않고 다이얼로그 처럼 사용자의 액션을 받는 노티피케이션)
    • 알림 기능 개선(잠금상태에서 알림 받을 수 있음)
    • 카메라 성능 개선
    • Chromium 엔진을 이용하도록 WebView변경
    • 다중 SIM카드 지원
    • 아파치 HTTP 클래스 지원 중단

6.0

  • 버전명 : 마시멜로 (API 23)
  • 주요 특징
    • Runtime 퍼미션(앱을 실행할 때 필요한 퍼미션을 요청)
    • 배터리 절약 모드(Doze, App Standby 모드) - Doze모드에서 알람, 비동기 네트워크 처리 등이 제한되므로 신경써야함
    • 텍스트 선택 UI변경
    • 지문인식 지원
    • 앱링크
    • 구글 드라이브에 자동으로 백업 - 하위 버전에서는 수동으로 구현해야 함
    • 블루투스 스타일러스 펜 지원
    • 4K 디스플레이 모드 추가

7.0

  • 버전명 : 누가 (API 24)
  • 주요 특징
    • 향상된 Doze모드 - Doze 동작이 2단계로 변경
    • 백그라운드 최적화
      • CONNECTIVITY_CHANGE 액션을 메니페스트에 등록하여 사용불가(앱 내에서 등록 및 사용은 가능)
      • ACTION_NEW_PICTUREACTION_NEW_VIDEO 사용불가
    • 설정에서 스크린 크기 변경 가능 - 모든 크기의 스크린 사이즈에서 제대로 UI가 구성되는지 확인할 필요 있음
    • 멀티윈도우 지원
    • JIT/AOT 동시 지원 컴파일러 사용
    • Vulkan API 사용가능
    • Quick Setting 영역의 타일 API 사용가능

2016년 11월 9일 수요일

[자바] Effective Java 4장 - 클래스와 인터페이스2

클래스와 인터페이스2

6. 추상클래스 대신 인터페이스를 사용한다.

  • 인터페이스의 필요성 : 자바는 다중상속이 불가능한 대신, 인터페이스를 이용하여 구현해야 할 메서드를 규정할 수 있다. 인터페이스는 다중 구현이 가능하다.
  • 인터페이스의 장점
    • 메인 자료형을 보조할 서브 자료형으로 이용가능하다.(상속관계에 상관없이 인터페이스를 추가할 수 있으므로)
    • 상속에 얽매이지 않는 자료형을 구현할 수 있도록 한다.
    • 추상클래스보다는 타입결합이 약하기 때문에 의존성 주입 관계에 적절하다.
  • 인터페이스 사용시 주의점
    • 인터페이스에서 정의되는 모든 접근권한은 public이기 때문에, API로써 한번 공개되면 수정이 거의 불가능하다.
  • 추상 골격 구현 : 제공하고자 하는 인터페이스와, 그 인터페이스의 핵심 기능을 미리 구현한 추상클래스를 제공하는 방법으로, 개발자는 그 추상클래스에 부족한 부분만 채움으로써 완전한 기능을 하는 클래스를 구현할 수 있다.
  • 자바 8버전부터는 인터페이스에 default 메서드를 이용하면 메서드 구현부를 제공할 수 있다.

7.인터페이스는 자료형을 정의할 때만 사용한다.

  • 인터페이스를 사용하는 목적 : 해당 클래스의 객체가 어떤 일을 수행하는지를 클라이언트에게 알리기 위한 목적
  • 잘못된 인터페이스 사용의 예
    • 상수 인터페이스 - 인터페이스 내부에 static final 필드만 존재하는 인터페이스

8.태그 달린 클래스 대신 클래스 상속을 활용한다.

  • 태그 달린 클래스? : 하나의 클래스가 2가지 이상의 기능으로 동작할 때, 어떤 기능으로 동작할지를 필드값으로 구분하는 클래스
  • 태그 달린 클래스의 단점
    • 여러 기능이 혼합되어 있어서 코드 가독성이 떨어진다.
    • 여러 기능을 위해 많은 필드가 존재하기 때문에, 한 객체가 자신의 기능에 불필요한 필드를 가지므로 메모리 낭비다.
    • 새로운 기능을 추가하려면 소스파일을 수정해야 한다.
  • 클래스 상속을 통해 기능단위로 클래스를 분리하면 태그 클래스의 모든 단점을 제거할 수 있다.

9.전략을 표현하고 싶을 때는 함수 객체를 사용한다.

  • 자바에서는 함수포인터의 역할을 객체가 대신한다.
    • 필요한 메서드를 정의한 인터페이스를 준비하고, 그 인터페이스를 구현한 객체를 전달
  • 전략 패턴 : 어떤 기능을 구현할 때, 중요한 메인 로직을 상황에 따라 변경할 수 있도록 함수(메서드)를 전달받아 그 함수에게 메인 로직을 위임하는 패턴
  • ex : 배열의 정렬방법을 compare라는 메서드에 위임
Arrays.sort(stringArray, new Comparator<String>() {
    @Override
    public int compare(String s1, String s2) {
        return s1.length() - s2.length();
    }
});

10.중첩 클래스는 가능하면 static으로 선언한다.

  • 외부 클래스에 종속되는 중첩 클래스가 아니라면 static으로 선언해야 한다.
  • non-static 중첩 클래스는 외부 클래스의 참조를 유지해야 하기 때문에, 성능&공간 측면에서 static 중첩 클래스보다 안좋다.
  • ex 외부클래스 참조 예시
class A {
    class B {
        public void test() {
            // A.this 문법으로 외부 클래스의 객체를 참조
            A.this.print();
        }
    }
    
    void print() {
        System.out.println("class A");
    }
}

2016년 11월 7일 월요일

[자바] Effective Java 4장 - 클래스와 인터페이스1

클래스와 인터페이스1

1. 클래스와 멤버의 접근권한은 최소화하라

  • 정보은닉 : 필요한 정보 외의 모든 구현 세부사항을 다른 모듈에서 접근하지 못하도록 감추는 것
  • 정보은닉은 왜 중요한가?
    • 모듈간 의존성이 낮아진다. -> 재사용, 리팩토링이 쉽다.
    • 효율적인 성능튜닝을 할 수 있다. -> 모듈별로 모니터링하기 쉽다.
  • 클래스에서의 정보은닉 : 불필요한 멤버필드 & 메서드를 접근권한을 통해 감추는 것
    • private : 최상위 레벨 클래스 내부에서만 접근 가능.
    • package-private(default) : 같은 패키지 내의 아무 클래스나 접근 가능. 자바에서는 명시적으로 접근권한을 설정하지 않으면 기본적으로 이 권한이 주어진다.
    • protected : 해당 클래스 및 그 하위 클래스에서만 접근 가능
    • public : 어디에서든 접근 가능
  • 멤버필드는 절대로 public 권한으로 선언하면 안된다.
  • 꼭 공개가 필요한 멤버필드는 public static final 을 이용해 공개하려는 변수를 상수로 선언하는 것을 고려해본다. (단, 기본타입에 한해서... 참조타입은 상수이지만 값을 변경할 수 있다.)

2. 클래스 안에는 public 필드를 두지 말고 접근자 메서드를 사용한다.

  • pulbic 멤버필드는 정보은닉의 이점을 누릴 수 없다.
  • 멤버필드를 private / protected로 변경하고, public gettersetter 접근 메서드를 이용하면 정보은닉의 이점을 100% 누릴 수 있다.
  • package-private / private 중첩 클래스의 멤버필드는 경우에 따라서 public으로 선언하여 코드가독성을 높이기도 한다.
    • 이 중첩클래스들은 바깥의 클래스만 접근이 가능하기 때문에, 정보은닉을 어기는 사례가 아님.

3. 변경 가능성을 최소화한다.

  • 변경 불가능(immutable) 클래스 : 객체를 수정할 수 없는 클래스(ex String 클래스)
  • 변경 불가능 클래스의 이점
    • 설계&구현이 쉽다.
    • 오류 가능성이 적다.
    • 멀티 쓰레드에서 동시성 접근에 대한 걱정을 안해도 된다.
  • 변경 불가능 클래스의 단점
    • 값마다 객체를 새로 생성해야 한다.
  • 변경 불가능 클래스 만드는 방법
1. 객체 상태를 변경하는 setter 메서드를 제공하지 않는다.
2. 상속 받을 수 없도록 한다. class를 선언할 때 final 키워드를 이용하면 상속금지 클래스가 된다.
3. 모든 필드를 final로 선언한다.
4. 모든 필드를 private으로 선언한다.
5. 변경 가능 필드를 제공해야 한다면, 복사본을 만들엉 제공한다.

4. 상속하는 대신 구성한다.

  • 상속 : 클래스를 재사용하기 위해 해당 클래스의 자식 클래스로 구현하는 방법. 부모 클래스로 부터 private 이외의 필드, 메서드를 물려받을 수 있다.
  • 상속의 단점
    • 부모 클래스가 변경되면, 그 여파가 자식클래스까지 미친다.
class A {
    protected int age;
    public int getAge() {
        return age;
    }
}

class B extends A {
    @Override
    public int getAge() {
        age += 5;
        return getAge();
    }
}
  • 구성 : 물려받고자 하는 클래스의 기능을 이용하기 위해 새로운 클래스 내부에 해당 클래스를 private 필드로 선언하고, 이용하고자 하는 메서드를 호출하여 결과를 반환하도록 래핑(Wrapping)하는 방법
  • 구성의 단점
    • callback 구현방식과 함께 사용하기에는 적합하지 않다.
class A {
    private int age;
    public int getAge() {
        return age;
    }
}

class B {
    private A a;
    public getAge() {
        return a.getAge() + 5;
    }
}
  • 즉, 상속이 꼭 맞는 경우가 아니라면 구성 방법을 고려한다.

5. 상속을 위한 설계와 문서를 갖추거나, 그럴 수 없으면 상속을 금지한다.

  • 일반적으로 상속 가능 클래스를 설계하는 것 보다, 구성 방법을 고려하거나, 가능하다면 변경 불가능 클래스로 만들어 상속을 금지하는 것이 훨씬 쉽다.
  • 상속 클래스를 작성하려면 적절한 개수의 protected 멤버를 유지한다.
    • protected 멤버가 너무 많으면 관리하기 힘들다.
    • protected 멤버가 너무 적으면 상속하는 의미가 별로 없는 클래스가 된다.
  • 상속을 허용하는 클래스를 작성할 때의 주의사항
1. 생성자에서 재정의 가능 메서드를 호출하면 안된다. 상속관계에서 부모클래스의 생성자가 자식클래스의 생성자보다 먼저 불리기 때문에, 재정의 가능 메서드의 값이 하위 클래스 생성자에 의존하게 되면 문제가 생긴다.
2. Cloneable, Serializable 인터페이스를 구현하는 클래스라면, clone(), readObject() 메서드도 생성자와 같은 역할을 하므로, 위의 규칙을 지켜야 한다.
3.  상속 가능한(public / protected) 메서드가 내부적으로 어떻게 동작하는지 문서화해야 한다. 자식클래스가 그 메서드를 재정의할 때, 그 문서를 보고 부모 메서드의 행동을 가늠하여 구현되기 때문이다.