반응형

이번 포스팅은 App Architecture 가이드 두 번째 포스팅입니다.

예제를 통해 좀 더 자세히 알아보도록 하겠습니다.


사용자 인터페이스 시작

UI는 fragment UserProfileFragment와 관련 레이아웃 파일 user_profile_layout.xml로 구성됩니다.

UI를 만들려면 데이터 모델에 다음 데이터 요소가 있어야 합니다.

▶ 사용자 ID: 사용자의 식별자입니다. fragment 인수를 사용하여 이 정보를 fragment에 전달하는 것이 좋습니다. Android OS에서 프로세스를 제거해도 이 정보가 유지되므로, 앱을 다시 시작할 때 ID를 사용할 수 있습니다.

▶ 사용자 개체: 사용자에 관한 세부정보를 보유하는 데이터 클래스입니다.

이 정보를 유지하기 위해 ViewModel 아키텍처 구성요소를 기반으로 하는 UserProfileViewModel을 사용합니다.

ViewModel 개체는 fragment나 activity 같은 특정 UI 구성요소에 대한 데이터를 제공하고 Model과 커뮤니케이션하기 위한 데이터 처리 비즈니스 로직을 포함합니다. 예를 들어 ViewModel은 데이터를 로드하기 위해 다른 구성요소를 호출하고 사용자 요청을 전달하여 데이터를 수정할 수 있습니다. ViewModel은 UI 구성요소에 관해 알지 못하므로 구성 변경(예: 기기 회전 시 activity 재생성)의 영향을 받지 않습니다.

지금까지 다음 파일을 정의했습니다.

▶ user_profile.xml: 화면의 UI 레이아웃 정의

▶ UserProfileFragment: 데이터를 표시하는 UI 컨트롤러

▶ UserProfileViewModelUserProfileFragment에서 볼 수 있도록 데이터를 준비하고 사용자 상호작용에 반응하는 클래스

다음 소스 코드는 이러한 파일의 시작 콘텐츠를 보여줍니다. 

편의를 위해 레이아웃 파일은 생략합니다.

UserProfileViewModel

class UserProfileViewModel:ViewModel(){

val userId :String= TODO() val user :User= TODO() }

UserProfileFragment

class UserProfileFragment:Fragment(){

override fun onCreateView(inflater:LayoutInflater, container:ViewGroup?, savedInstanceState:Bundle?):View{
return inflater.inflate(R.layout.main_fragment, container,false)
}
}

user를 가져오려면 ViewModel에서 Fragment 인수에 액세스해야 합니다. Fragment에서 인수를 전달할 수도 있고, 더 나은 방법으로 SavedState 모듈을 사용해 ViewModel에서 직접 인수를 읽을 수 있습니다.

참고: SavedStateHandle을 사용하면 ViewModel에서 관련 Fragment 또는 Activity의 저장된 상태와 인수에 액세스할 수 있습니다.


// UserProfileViewModel

class UserProfileViewModel( savedStateHandle:SavedStateHandle ):ViewModel(){
val userId :String= savedStateHandle["uid"]?: throwIllegalArgumentException("missing user id") val user :User= TODO()
}

// UserProfileFragment
privateval viewModel:UserProfileViewModel by viewModels(factoryProducer ={SavedStateVMFactory(this)}        ... )

이제 user 개체가 확보되면 Fragment에 알려야 합니다. 여기에서 LiveData 아키텍처 구성요소가 사용됩니다.

LiveData는 식별 가능한 데이터 홀더입니다. 앱의 다른 구성요소에서는 이 홀더를 사용하여 상호 간에 명시적이고 엄격한 종속성 경로를 만들지 않고도 개체 변경사항을 모니터링할 수 있습니다. 또한 LiveData 구성요소는 activity, fragment, 서비스와 같은 앱 구성요소의 수명 주기 상태를 고려하고, 개체 유출과 과도한 메모리 소비를 방지하기 위한 정리 로직을 포함합니다.

참고: RxJava와 같은 라이브러리를 이미 사용하고 있다면 LiveData 대신 계속 사용해도 됩니다. 그러나 이러한 라이브러리와 방법을 사용하는 경우 앱의 수명 주기를 올바르게 처리해야 합니다. 특히 관련 LifecycleOwner가 중지되면 데이터 스트림이 일시중지되고, 관련 LifecycleOwner가 제거되면 이러한 스트림이 제거되도록 해야 합니다. android.arch.lifecycle:reactivestreams 아티팩트를 추가하여 LiveData를 다른 반응형 스트림 라이브러리(예: RxJava2)와 함께 사용할 수도 있습니다.

LiveData 구성요소를 앱에 통합하기 위해 UserProfileViewModel의 필드 유형을 LiveData<User>로 변경합니다. 이제 데이터가 업데이트되면 UserProfileFragment에 정보가 전달됩니다. 또한 이 LiveData 필드는 수명 주기를 인식하기 때문에 더 이상 필요하지 않은 참조를 자동으로 정리합니다.

UserProfileViewModel

class UserProfileViewModel( savedStateHandle:SavedStateHandle):ViewModel(){

val userId :String= savedStateHandle["uid"]?: throw IllegalArgumentException("missing user id") val user :LiveData<User>= TODO()
}

이제 데이터를 관찰하고 UI를 업데이트하도록 UserProfileFragment를 수정합니다.

UserProfileFragment

override fun onViewCreated(view:View, savedInstanceState:Bundle?){ super.onViewCreated(view, savedInstanceState)
viewModel
.user.observe(viewLifecycleOwner){ // update UI } }

사용자 프로필 데이터가 업데이트될 때마다 onChanged() 콜백이 호출되고 UI가 새로고침됩니다.

반응형
반응형

이번 포스팅은 App Architecture 가이드에 대하여 알아보도록 하겠습니다.


이 가이드에는 강력한 프로덕션 품질의 애플리케이션을 구축하기 위한 모범 사례와 권장 아키텍처가 포함되어 있습니다.

이 페이지는 Android 프레임워크 기본을 잘 아는 사용자를 대상으로 합니다. Android 앱 개발에 익숙하지 않으신 분들은 Developer 가이드를 참고하여 이 가이드에 언급된 개념에 대해 자세히 알아보세요.


1. 모바일 앱 사용자 환경


대부분의 경우 데스크톱 앱은 데스크톱 또는 프로그램 실행기에서 단일 시작 지점을 가진 다음 단일 프로세스로 실행됩니다. 반면에 Android 앱은 훨씬 더 복잡한 구조를 가지고 있습니다.  일반적인 Android 앱은 activityfragment서비스콘텐츠 제공업체broadcast receiver를 비롯하여 여러 앱 구성요소를 포함합니다.

개발자는 앱 매니페스트에서 이러한 앱 구성요소 대부분을 선언하게 되며, Android OS에서 이 파일을 사용하여 기기의 전반적인 사용자 환경에 앱을 통합하는 방법을 결정합니다. 올바르게 작성된 Android 앱에 여러 구성 요소가 포함되어 있고 사용자가 짧은 시간에 여러 앱과 상호 작용하는 경우가 많다는 점을 감안할 때, 앱은 다양한 종류의 사용자 중심 워크플로우 및 작업에 적응해야 합니다.

예를 들어 좋아하는 소셜 네트워킹 앱에서 사진을 공유하면 어떻게 되는지 생각해 보세요.

  1. 앱이 카메라 인텐트를 트리거합니다. 그런 다음 Android OS에서 카메라 앱을 실행하여 요청을 처리합니다. 이 시점에서 사용자는 소셜 네트워크 앱에서 나가지만 사용 환경은 끊김 없이 연결됩니다.
  2. 카메라 앱은 파일 선택기 실행처럼 다른 인텐트를 트리거하여 다른 앱을 실행할 수도 있습니다.
  3. 이후에 사용자가 다시 소셜 네트워크 앱으로 돌아와서 사진을 공유합니다.
이 과정에서 언제든지 전화나 알림에 의해 사용 환경이 중단될 수 있습니다. 사용자는 이 중단에 대응하고 난 후에 사진 공유 프로세스로 돌아가서 작업을 계속할 수 있기를 기대합니다. 휴대기기에서는 이렇게 앱을 바꾸는 동작이 일반적이므로, 앱에서 이러한 흐름을 올바르게 처리해야 합니다.

또한 휴대기기는 리소스가 제한되어 있으므로, 언제든지 운영체제에서 새로운 앱을 위한 공간을 확보하도록 언제든지 일부 앱 프로세스를 종료해야 할 수 있습니다.

이러한 환경 조건을 고려해 볼 때 앱 구성요소는 개별적이고 비순차적으로 실행될 수 있으며, 운영체제나 사용자가 언제든지 앱 구성요소를 제거할 수 있습니다. 이러한 이벤트는 직접 제어할 수 없기 때문에 앱 구성요소에 앱 데이터나 상태를 저장해서는 안 되며 앱 구성요소가 서로 종속되면 안 됩니다.


2. 일반 Architecture 원칙


앱 데이터와 상태를 저장하는 데 앱 구성요소를 사용할 수 없다면 앱을 어떻게 디자인해야 할까요?


관심사 분리

따라야 할 가장 중요한 원칙은 관심사 분리입니다. Activity 또는 Fragment에 모든 코드를 작성하는 실수는 흔히 일어납니다. 이러한 UI 기반의 클래스는 UI 및 운영체제 상호작용을 처리하는 로직만 포함해야 합니다. 이러한 클래스를 최대한 가볍게 유지하여 많은 수명 주기 관련 문제를 피할 수 있습니다.

Activity  Fragment 구현은 소유의 대상이 아니며, Android OS와 앱 사이의 계약을 나타내도록 이어주는 클래스에 불과합니다. 사용자 상호작용을 기반으로 또는 메모리 부족과 같은 시스템 조건으로 인해 언제든지 OS에서 클래스를 제거할 수 있습니다. 만족스러운 사용자 환경과 더욱더 수월한 앱 관리 환경을 제공하려면 이러한 클래스에 대한 의존성을 최소화하는 것이 좋습니다.


Model에서 UI 만들기

또 하나의 중요한 원칙은 Model에서 UI를 만들어야 한다는 것입니다. 가급적 지속적인 Model(a persistent model)을 권장합니다. Model은 앱의 데이터 처리를 담당하는 구성요소로, 앱의 View 개체 및 앱 구성요소와 독립되어 있으므로 앱의 수명주기와 관련 문제의 영향을 받지 않습니다.

지속적인 Model이 이상적인 이유는 다음과 같습니다.

▶ Android OS에서 리소스를 확보하기 위해 앱을 제거해도 사용자 데이터가 삭제되지 않습니다.

▶ 네트워크 연결이 취약하거나 연결되어 있지 않아도 앱이 계속 작동합니다.

데이터 관리 책임이 잘 정의된 Model 클래스를 기반으로 앱을 만들면 쉽게 테스트하고 일관성을 유지할 수 있습니다.


3. 권장하는 App Architecture



이 섹션에서는 종합적인 사용 사례(end-to-end use case)를 들어 아키텍처 구성요소를 사용하여 앱을 구성하는 방법을 보여줍니다.

참고: 모든 시나리오에서 잘 작동하는 앱을 작성하는 한 가지 방법은 없습니다. 하지만 이 권장 아키텍처는 대부분의 상황 및 워크플로에 유용한 출발점이 될 것입니다. 이미 일반 아키텍처 원칙을 준수하는 Android 앱 작성 방법을 사용하고 있다면 방법을 변경할 필요가 없습니다.

사용자 프로필을 표시하는 UI를 제작한다고 가정해 보겠습니다. 이 경우 비공개 백엔드 및 REST API를 사용하여 지정된 프로필의 데이터를 가져옵니다.

개요

먼저 다음 다이어그램을 살펴보세요. 앱을 설계한 이후 모든 모듈이 서로 어떻게 상호작용해야 하는지 보여줍니다.

각 구성요소가 한 수준 아래의 구성요소에만 종속됨을 볼 수 있습니다. 예를 들어 activity 및 fragment는 ViewModel에만 종속됩니다. Repository는 여러 개의 다른 클래스에 종속되는 유일한 클래스입니다. 이 예에서 Repository는 지속 데이터 Model과 원격 백엔드 데이터 소스(Remote Data Source)에 종속됩니다.

이 디자인은 일관되고 즐거운 사용자 환경을 만들어 줍니다. 사용자가 마지막으로 앱을 닫은 후 몇 분 후 또는 며칠 후에 앱으로 돌아오든 상관없이, 로컬에서 앱이 지속된다는 사용자의 정보를 즉시 볼 수 있습니다. 이 데이터가 오래된 경우 앱의 Repository 모듈이 백그라운드에서 데이터를 업데이트하기 시작합니다.

다음으로 이어지는 작업은 다음 포스팅을 통해 자세히 설명하도록 하겠습니다.



Reference

1. https://developer.android.com/jetpack/docs/guide


반응형
반응형

이번 포스팅은 Button 위젯의 텍스트에 밑줄을 적용하는 방법에 대하여 알아보도록 하겠습니다.

정적인 텍스트와 동적인 텍스트 두 가지 방법으로 분류하여 알아보도록 하겠습니다.


Kotiln에서 아래와 같이 선언합니다.

val button = findViewById<Button>(R.id.park);
button.paintFlags = button.paintFlags or Paint.UNDERLINE_TEXT_FLAG

1) 정적인 텍스트

- string.xml에서 아래와 같이 선언합니다.

<string name="underlined_text"><u>I\'m underlined</u></string>

- Button 위젯에 위에서 선언한 값을 대입해 줍니다.

button.text = getString(R.string.underlined_text)


2) 동적인 텍스트

- string.xml에서 아래와 같이 선언합니다.

<string name="underlined_dynamic_text"><u>%s</u></string>

- Button 위젯에 위에서 선언한 값을 동적으로 대입해 줍니다.

button.text = getString(R.string.underlined_dynamic_text, "I'm underlined")


반응형

'Development > Android' 카테고리의 다른 글

[Android] App Architecture 가이드 2  (0) 2019.09.23
[Android] App Architecture 가이드 1  (0) 2019.09.23
[Android] Android ABI 관리  (0) 2019.09.22
[Android] Touch 이벤트 순서  (0) 2019.09.10
[Android] Intent Filter  (0) 2019.09.10
반응형

이번 포스팅은 Android의 ABI 관리에 대하여 알아보도록 하겠습니다.

실무를 하면서 네이티브 라이브러리를 쓰려다 ABI관련 오류를 만나게 된적이 있는데, 안드로이드에서 ABI를 어떻게 관리하는지 정리해보겠습니다. 

Android 디바이스는 제조사의 사정에 따라서 CPU를 선택해서 쓸 수 있습니다. 가장 대표적인 ARM을 비롯하여 MIPS, x86을 지원합니다. 이들이 사용하는 명령 세트는 모두 다르며, 각각 아키텍쳐 – 명령세트의 조합은 자신들에게 맞는 ABI(Application Binary Interface)를 갖습니다.

ABI(Application Binary Interface)는 런타임에 시스템과 앱의 머신코드가 어떻게 상호작용할지를 기술한 인터페이스입니다. Project에서 so파일을 로딩하는 경우, 머신코드-아키텍쳐에서 사용하는 ABI와 일치해야 구동이 가능합니다. 즉, ARM 칩에서 x86 머신코드를 네이티브로 실행할 수 없습니다.

ABI(Application Binary Interface)는 아래 정보들을 포함하고 있습니다.

▶ 머신코드가 사용해야 하는 CPU 명령 세트.

 런타임에 사용할 메모리 로드/스토어 endianness.

 ABI에서 지원하는 실행가능한 바이너리 포맷(프로그램,  shared lib)

당신의 코드와 시스템간의 데이터 전달을 위한 다양한 컨벤션. 이 컨벤션들은 시스템이 함수호출 시 스택과 레지스터를 어떻게 사용할지 뿐만 아니라 alignment 제약사항까지 포함합니다.

일반적으로 매우 특정한 라이브러리들에서, 런타임시 당신의 머신코드에서 사용가능한 함수 심볼의 목록.

이 게시물에서는 NDK가 지원하는 ABI, ABI가 제공하는 정보, 그리고 ABI가어떻게 동작하는지를 살펴보겠습니다.

1. 지원되는 ABI들



각 ABI는 1개이상의 명령 세트를 지원합니다. 

아래 표를 참고하시면 됩니다.

ABI 명

지원되는
명령 세트(들)

설명

armeabi

    ARMV5TE and later

    Thumb-1

하드웨어 FPU 지원 없음.

armeabi-v7a

(armeabi-v7a-hard)

    armeabi

    Thumb-2

    VFPv3-D16

    Other, optional

armeabi-v7a-hard가 있는경우 하드웨어 FPU 지원.
ARMv5, v6와 호환되지 않음.

arm64-v8a

    AArch-64

x86

    x86 (IA-32)

    MMX

    SSE/2/3

    SSSE3

movbe 또는 SSE4는 지원 안함.

x86_64

    x86-64

    MMX

    SSE/2/3

    SSSE3

    SSE4.1, 4.2

    POPCNT

mips

    MIPS32r1 and later

하드웨어 FPU를 사용하는 경우 최대의 호환성을 위해 CPU:FPU의 클럭비가 2:1임을 가정.  micromips와 mips16은 지원하지 않음.
mips64

    MIPS64r6

자세한 ABI별 설명은 아래에 기술합니다.


1) armeabi

armeabi는 NDK r16에서 툴체인이 deprecated되었으며, r17에서 제거되었습니다.

 armeabi는 최소 ARMv5TE 명령세트를 사용하는 ARM 기반 CPU부터 지원하기위해 존재합니다. ARMv5TE는 무려 99년도에 나온 명령세트로, Android라는 플랫폼만을 한정 할 때, 사실상 모든 ARM칩에서 구동 가능한 ABI라고 보면 됩니다.

 호환성이 가장 중시되는 장점이 있는 반면에 하드웨어적인 지원은 가장 떨어집니다. 하드웨어 FPU 사용이 불가능하며, 모든 fp 명령은 소프트웨어 방식으로 처리해야 합니다. (libgcc.a static lib)

 Thumb 명령세트(Thumb-1)를 지원합니다.


2) armeabi-v7a (armeabi-v7a-hard)

모든 ARM과 호환되는 armeabi를 확장하여 몇 가지 명령세트가 추가된 형태의 ABI 입니다.  아래는 추가된 확장명령세트에 대한 설명입니다.

 Thumb-2 확장명령세트는 32bit ARM 명령들과 성능은 비슷하면서 명령의 사이즈는 Thumb-1과 비슷합니다.

 VFP 하드웨어 FPU 명령. 더 구체적으로 얘기하자면,  VFPv3-D16의 경우 64비트 크기의 FP전용 레지스터를 16개 가지며, 추가적으로 ARM 코어로부터 16개의 32비트 크기 레지스터를 갖게 됩니다.

 v7a는 또한, NEON(ARM 아키텍쳐에서의 SIMD instruction), VFPv3-D32, ThumbEE 명령세트들도 포함됩니다.


3) armeabi-v7a-hard

armeabi-v7a의 변형으로, NDK에서는 armeabi-v7a와 구분된다. 기본적으로 아래와같은 플래그가 armeabi-v7a에서 더 붙게 됩니다.

    TARGET_CFLAGS += -mhard-float -D_NDK_MATH_NO_SOFTFP=1

    TARGET_LDFLAGS += -Wl,--no-warn-mismatch -lm_hard

성능을 위해서 하드웨어 FPU 사용을 강제해야할 경우에 이 ABI를 사용할 수 있습니다.


4) arm64-v8a

ARM의 64비트 명령세트인 AArch64를 사용합니다. NEON과 VFPv4를 지원한다.


5) x86

x86이라는 단어는 일반적으로 IA-32와 동치입니다. 즉 인텔의 32비트 프로세서를 의미합니다.

gcc 컴파일러에서는 일반적으로 아래 플래그를 통해 컴파일한다.

    -march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32

이는 i686(Pentium  Pro) 명령세트를 통해 빌드하겠다는 의미이며, MMX, SSE, SSE2, SSE3, SSSE3까지 사용가능한 프로세서를 타겟으로 합니다.

이 ABI에서는 아래 두 명령은 사용이 불가능합니다.

 MOVBE (big-endian move. Haswell 이상에서 지원.)

 SSE4.x


6) x86_64

x86의 64비트 버전입니다. (x86_64 != IA-64 && x86_64 == AMD64인건 다들 알것이라 생각합니다.)

gcc 컴파일러에서는 일반적으로 아래 플래그를 통해 컴파일합니다.

    -march=x86-64 -msse4.2 -mpopcnt -m64 -mtune=intel

이는 x86-64 아키텍쳐로 빌드하되 MMX, SSE, SSE2, SSE3, SSSE3, SSE4.x, POPCNT를 포함합니다.

이 ABI에서도 사용못하는 명령세트들이 있다. 다들 너무 최신명령들이라 그렇다.

 MOVBE

▶ SHA

 AVX

 AVX2


7) mips, mips64

MIPS의 경우, NDK r17에서 툴체인들이 제거되었습니다.

MIPS의 경우 mips32r1 명령세트 기반 프로세서부터 사용가능합니다. 아래와 같은 기능들이 지원됩니다.

 MIPS32 revision 1 ISA

 Little-endian

 O32

 Hard-float

 No DSP application-specific extensions

mips64는 MIPS 64비트 버전 명령세트인 MIPS64 R6 기반 프로세서에서 사용가능합니다.


특정 ABI로 코드 생성하기

기본적으로 NDK에서는 armeabi ABI에서 동작하는 코드를 생성합니다. 다른 ABI를 사용하고 싶다면 Application.mk 파일을 수정하면 됩니다.

    APP_ABI := armeabi armeabi-v7a

이렇게 하면 armeabi, armeabi-v7a 두가지의 so 파일이 빌드 될 것입니다. 여러개의 ABI를 지원하는 것은 호환성에서는 유리하지만 같은 so파일이 중복으로 생성되므로 앱 크기에서는 매우 불리한 일입니다. 따라서 앱 크기와 호환성간의 트레이드 오프를 잘 생각해야 할 것입니다.


Android 플랫폼에서의 ABI 관리

가장 중요한 내용으로, ABI가 시스템에서 어떻게 관리되고 각 CPU 아키텍쳐와 어떻게 매핑되어 실행하는지를 설명합니다.


앱 패키지에서의 네이티브 코드

플레이스토어와 패키지매니저는 NDK로 생성된 라이브러리를 아래와 같은 경로에 있음을 기대하고  패턴대로 검색하여 로드하게 됩니다.

/lib/<abi>/lib<name>.so

여기서 <abi>는 Android 상에서 지원되는 ABI 이름이며, <name>은 Android.mk 파일에서 LOCAL_MODULE 변수에 지정한 이름이 된다. 만약 호환성에 미친 앱같이 여러 ABI를 지원한다면 아래와 같이 되리라.

/lib/armeabi/libfoo.so /lib/armeabi-v7a/libfoo.so /lib/arm64-v8a/libfoo.so /lib/x86/libfoo.so /lib/x86_64/libfoo.so /lib/mips/libfoo.so /lib/mips64/libfoo.so

여기서 참고해야 할것은 ARMv7기반의 Android 디바이스들은 Android 버전 4.0.3 이하 버전에서는 armeabi, armeabi-v7a 디렉토리가 같이 존재하여도 armeabi를 무조건 사용한다는 이슈가 있습니다. 이는 4.0.4에서는 해결된 사항입니다.


Android 플랫폼의 ABI 지원

안드로이드 시스템은 런타임에 어떤  ABI를 지원하는지를 알고 있는데, 이는 특정 빌드환경 시스템의 속성들이 다음사항을 알려주기 때문입니다.

    해당 디바이스의 primary ABI는 시스템 이미지 그 자체에 사용되는 머신코드와 일치하며

    선택적으로 secondary ABI는 시스템 이미지가 또한 지원하는 또다른 ABI 와 일치합니다.

가장 최고의 성능을 위해서는 디바이스의 primary ABI로 직접 코드를 컴파일 하는 것입니다. 가령 대부분의 ARMv7 기반 디바이스라면 굳이 쓸데없는 고퀄리티의 호환성을 위해 armeabi를 고집할 필요가 없다.

많은 x86 기반 디바이스들은 armeabi-v7a와 armeabi를 구동할 수 있다. 이러한 디바이스들의 secodnary abi가 armeabi-v7a이기 때문입니다.

대부분의 MIPS 기반 디바이스들은 primary abi가 mips입니다.

앱 install time에 네이티브 코드 자동 extraction

앱 설치시, 패키지 매니저 서비스는 APK를 스캔하여, 아래와 같은 패턴으로 shared lib를 찾는다. 처음엔 primary ABI를 대입해 찾습니다.

lib/<primary-abi>/lib<name>.so

만약 찾지 못한다면 secondary ABI를 대입해 찾아봅니다.

lib/<secondary-abi>/lib<name>.so

라이브러리가 검색되면, 패키지 매니저는 /lib/lib<name>.so 파일을 data 디렉토리에 복사합니다. (data/data/<package_name>/lib/)

만약 shared lib를 못찾으면? 앱 설치는 되겠지만 런타임에 크래시가 발생합니다.



Reference

1. https://blog.yatopark.net/2016/03/12/%ec%95%88%eb%93%9c%eb%a1%9c%ec%9d%b4%eb%93%9c%ec%9d%98-abi-%ea%b4%80%eb%a6%ac/

반응형
반응형


이번 포스팅은 View를 touch 하였을 경우 발생하는 이벤트 순서를 알아보도록 하겠습니다.

발생하는 이벤트 순서를 알아야 UI로직을 처리 시 헤매지 않습니다.


onTouch -> onLongClick -> onClick 순서로 이벤트가 발생합니다.


만약 onTouch 메소드를 오버라이딩하고 이후 onLockClick 이벤트가 이뤄지지 않길 바란다면

return true;를 호출하면 이후 작업이 이뤄지지 않습니다.


< 정리>

View touch하였을 경우 발생하는 이벤트 순서

onTouch -> onLongClick -> onClick


이벤트 진행을 그만 중단하고 싶다면 return true;

이벤트 진행을 지속하고 싶다면 return false;


반응형
반응형

이번 포스팅은 Android에서 Intent Filter에 대하여 알아보도록 하겠습니다.


다른 앱이 자신의 Activity를 시작할 수 있도록 하기 위해서는 AndroidMenifest 파일에서 <activity> 요소에 대해 <intent-filter> 요소를 추가해야 합니다.

 <intent-filter> 요소를 추가하면 시스템이 Intent-Filter를 식별하고 설치된 모든 앱에서 지원하는 Intent의 내부 카달로그에 해당 정보를 추가합니다. 앱이 암시적 인텐트로 startActivity() 또는 startActivityForResult()를 호출하면 시스템은 그 인텐트에 응답할 수 있는 Activity(들)을 찾습니다.


Intent-Filter 추가



Activity가 처리 가능한 Intent를 올바르게 정의하려면 Activity가 받아들이는 데이터와 추가하는 인텐트 필터가 구체적이어야 합니다.

Activity의 Intent-Filter가 Intent 객체의 다음 기준을 충족할 경우, 시스템이 주어진 Intent를 해당 Activity에 보낼 수 있습니다.


Action

수행할 작업의 이름을 지정하는 문자열입니다. 일반적으로, 플랫폼에서 정의하는 값 중 하나입니다(예: ACTION_SEND 또는 ACTION_VIEW).

<action> 요소를 사용하여 Intent-Filter에 지정합니다. 이 요소에 지정하는 값은 API 상수 대신 작업의 전체 문자열 이름이어야 합니다(다음 예제 참조).


Data

인텐트와 관련된 데이터에 대한 설명입니다.

<data> 요소를 사용하여 Intent-Filter에 지정합니다. 이 요소에서 하나 이상의 속성을 사용하여 MIME 유형, URI 접두사, URI 구성표 또는 이들의 조합 그리고 수락된 데이터 유형을 나타내는 다른 요소들을 지정할 수 있습니다.


Category

인텐트를 처리하는 Activity의 특징을 지정할 수 있는 추가적인 방법을 제공합니다. 일반적으로 사용자 제스처 또는 이러한 제스처가 시작된 위치와 관련되어 있습니다. 시스템이 지원하는 카테고리는 여러 가지가 있지만 대부분은 거의 사용되지 않습니다. 하지만 모든 암시적 인텐트는 기본적으로CATEGORY_DEFAULT로 정의됩니다.

<category> 요소를 사용하여 Intent-Filter에 지정합니다.


Intent-Filter에서 Activity가 허용하는 기준을 선언할 수 있습니다. 이는 이러한 각각의 기준을  <intent-filter> 요소 내에 해당 XML 요소를 중첩하여 선언하면 가능합니다.

예를 들어, 다음은 데이터 유형이 텍스트 또는 이미지인 경우 ACTION_SEND 인텐트를 처리하는 인텐트 필터가 지정된 Activity입니다.

<activity android:name="ShareActivity">
   
<intent-filter>
       
<action android:name="android.intent.action.SEND"/>
       
<category android:name="android.intent.category.DEFAULT"/>
       
<data android:mimeType="text/plain"/>
       
<data android:mimeType="image/*"/>
   
</intent-filter>
</activity>

수신되는 인텐트는 각각 하나의 작업 및 하나의 데이터 유형만 지정합니다. 하지만 <intent-filter>의 <action><category> 및 <data> 요소에 대한 여러 인스턴스를 선언해도 문제가 되지는 않습니다.

action및 data의 두 쌍이 상호 배타적으로 동작할 경우, 어떤 데이터 유형과 페어링되었을 때 어떤 작업이 허용 가능한지를 지정하는 Intent-Filter를 각각 따로 생성해야 합니다.

예를 들어, Activity가 ACTION_SEND 및 ACTION_SENDTO 인텐트 모두에서 텍스트와 이미지 모두를 처리한다고 가정합니다. 이런 경우, 두 작업 각각에 별도의 인텐트 필터를 정의해야 합니다. 그 이유는 ACTION_SENDTO 인텐트는 데이터 Uri를 사용해서 send 또는 sendto URI 구성표를 사용하는 수신자 주소를 지정해야 하기 때문입니다.

<activity android:name="ShareActivity">
   
<!-- filter for sending text; accepts SENDTO action with sms URI schemes -->
   
<intent-filter>
       
<action android:name="android.intent.action.SENDTO"/>
       
<category android:name="android.intent.category.DEFAULT"/>
       
<data android:scheme="sms" />
       
<data android:scheme="smsto" />
   
</intent-filter>
   
<!-- filter for sending text or images; accepts SEND action and text or image data -->
   
<intent-filter>
       
<action android:name="android.intent.action.SEND"/>
       
<category android:name="android.intent.category.DEFAULT"/>
       
<data android:mimeType="image/*"/>
       
<data android:mimeType="text/plain"/>
   
</intent-filter>
</activity>

참고: 암시적 인텐트를 수신하려면 인텐트 필터 안에 CATEGORY_DEFAULT 범주를 반드시 포함해야 합니다. startActivity() 및 startActivityForResult() 메서드는 모든 인텐트를 마치 CATEGORY_DEFAULT 범주를 선언한 것처럼 취급합니다. Intent-Filter에서 이 범주를 선언하지 않으면 어떠한 암시적 인텐트도 Activity로 확인되지 않습니다.


Activity에서 Intent 처리



Activity를 시작하는 데 사용된 Intent를 읽어 Activity에서 취할 작업을 결정할 수 있습니다.

Activity가 시작되면, getIntent()를 호출하여 Activity를 시작한 Intent를 검색합니다. 이 작업은 Activity의 수명 주기 동안 언제든지 가능하지만, 일반적으로 onCreate() 또는 onStart()와 같은 초기 콜백 과정에서 수행합니다.



Reference

1. https://developer.android.com/training/basics/intents/filters?hl=ko

반응형

'Development > Android' 카테고리의 다른 글

[Android] Android ABI 관리  (0) 2019.09.22
[Android] Touch 이벤트 순서  (0) 2019.09.10
[Android] Flexable Fragment UI 구축  (0) 2019.09.06
[Android] App Fragment Test  (0) 2019.09.06
[Android] Fragment의 생성  (0) 2019.09.06

+ Recent posts