Android 14 이전에는 캐시된 App을 제한없이 실행할 수 있었지만, Android 14 이후부터는 캐시 된 App을 곧바로 Freezing 시켜 불필요하게 CPU를 점유하지 않도록 유지할 수 있다. 이로인해 전반적인 CPU cycle을 최대 50% 줄일 수 있었으며 Foreground Service
, JobSchduler
, WorkManager
와 같은 Android App Lifecycle 이외에서 동작하는 App의 Background 작업은 허용되지 않는다.
캐싱된 App의 Freezing 상태를 더 오래 유지하기 위해 App이 context 기반 BroadcastReceiver
를 수신하는 방법을 조정했다. Freezing 된 App이 캐싱 상태에서 나올 때만 BroadcastReceiver
를 전달받아 처리할 수 있도록 최적화할 수 있으며 BATTERY_CHANGED
와 같은 일부 반복적인 context 기반 BroadcastReceiver
은 App이 캐시 상태를 벗어나기전에 하나의 BroadcastReceiver
로 병합될 수 있다.
이러한 Android14 최적화 기능들은 전반적인 App launch 시간을 단축할 수 있었으며 App 코드 크기를 평균 9.3% 줄이는 최적화 기능을 더해 Device RAM 관리에 더 적합한 환경을 만들었다.
Android 14부턴 비선형적으로 글꼴을 200%까지 확장할 수 있는데, 비선형 확장을 통해 큰 텍스트가 작은 텍스트와 같은 속도로 증가하지 않도록 작업할 수 있다. 해당 기능 적용을 위한 모든 Text 크기 단위는 sp (Scaled Pixel)
여야하며 TypedValue.applyDimension
과 TypedValue.deriveDimension
을 활용하여 비선형 크기를 조정할 수 있다.
LocalManager
를 통해서 App의 LocalConfig
를 동적으로 얻어와 업데이트할 수 있다.
LocalManager.getApplicationLocales
를 통해 현재 App이 UI하고 있는 언어를 알 수 있으며 LocalManager.setOverrideLocalConfig
를 통해 App의 언어를 동적으로 최적화할 수 있다.
Android System 설정에서 사용자가 선호하는 지역 설정을 할 수 있으며 App에선 이러한 설정 정보를 읽어올 수 있을 뿐만아니라 ACTION_LOCALE_CHANGED
BroadcastReceiver를 등록하여 지역 설정 변경 event를 처리할 수 있다.
App 자체 refacotring 없이 문법적 성별을 가진 언어에 대해 지원할 수 있는 기능이 생기게 되었다.
해당 기능이 추가된 배경에는 약 30억 명의 사용자가 성별이 지정된 언어를 사용하고 있지만, 일반적으로 많은 언어에서 남성형 문법적 성별을 기본 성별 언어로 사용하고 있기 때문이라고 한다.
예시)
사용자가 문법적 성별을 설정한 후에는 GrammaticalInflectionManager.setRequestedApplicationGrammaticalGender
를 통해 App에 적용할 수 있다.
// Set app's grammatical gender to feminine
val gIM = mContext.getSystemService(GrammaticalInflectionManager::class.java)
gIM.setRequestedApplicationGrammaticalGender(Configuration.GRAMMATICAL_GENDER_FEMININE)
// Get app's grammatical gender
val grammaticalGender = gIM.getApplicationGrammaticalGender()
Android 14부터는 10bit 이미지에 대한 지원을 추가하여 Camera sensor에서 더 많은 정보를 유지하하여 생생한 색감과 높은 대비를 표현할 수 있게된다. 이러한 신규 ImageFormat은 Ultra HDR Format로 명칭되었으며 Android Window
에서도 활용할 수 있게되기에 더 생동감있는 사진 역시 Viewer에서 경험할 수 있게된다.
cf) 10bit still ImageFormat - JPEG_R
Camera Extensions을 통해 App이 더 긴 처리 사진 처리를 할 수 있도록 지원했으며 향상 된 저조도 촬영과 배경 Blur 기능 그리고 final image 전에 draft image를 보여주어 UX를 개선시킬 수 있는 feature를 지원한다. (Samsung Camera에 이미 예전부터 있는 기능인데..ㅎ)
AudoMixerAttributes를 통해 USB 연결된 headset에서 무손실 audio format을 지원한다고 한다.
Android 14부터는 Java 17 지원을 하게 된다. 이에따라 다음과 같은 주요 개선 사항들을 통해 개발 생산성을 향상시킬 수 있다.
// JAVA 17 이전
String multilineText = "Java 17이전 Text Block을 사용하여, \n" +
"멀티 라인 문자열을 쉽게 작성할 수 있다네요\n" +
"들여쓰기와 줄바꿈이 자동으로 처리됩니다.\n";
// JAVA 17 이후
String multilineText = """
Java 17이전 Text Block을 사용하여
멀티 라인 문자열을 쉽게 작성할 수 있습니다.
들여쓰기와 줄바꿈이 자동으로 처리됩니다.
""";
data
class와 같이 boliler plate code가 존재하지 않는 DTO 객체를 지원한다.public record Person(String name, String age, String gender) {
// getter, setter, toString, equals, hashcode 가 모두 자동 구현되어 있다.
// 필요에 따라 해당 method를 재정의하거나 신규 method를 추가하여 운용할 수 있다.
@Override
public String toString() {
return "Person{" +
"override_name='" + name + '\'' +
", override_age='" + age + '\'' +
", override_gender='" + gender + '\'' +
'}';
}
public boolean isMan() {
return this.gender == "man";
}
}
instanceof
에 특정 유형이 있는 것으로 취급할 수 있다. // Java 8
@Override
public boolean equals(Object obj) {
if (obj instanceof Student) {
Student student = (Student) obj;
if (this.studentNumber == student.studentNumber) {
return true;
} else {
return false;
}
}
return false;
}
// Java 17
@Override
public boolean equals(Object obj) {
if (obj instanceof Student student) {
if (this.studentNumber == student.studentNumber) {
return true;
} else {
return false;
}
}
return false;
}
// 1. Parent의 자식 class는 Child 허용한다.
public sealed class Parent permits Child {
...
}
// 2. Child는 non-sealed 키워드로 다음과 같이 상속 봉인을 해제하거나
public non-sealed class Child extends Parent {
...
}
// 3. sealed 키워드를 사용해서 또 다른 봉인 클래스로 선언할 수 있다.
public sealed class Child extends Parent permit GrandChild {
...
}
// 4. final 키워드를 사용하면 기존과 마찬가지로 아무도 상속받을 수 없게된다.
public final class Child extends Parent {
...
}
사용자가 선택한 사진 및 동영상에만 App 접근 권한을 부여할 수 있다.
사용자는 App과 Media를 보다 편안하게 공유할 수 있으며 개발자는 아래 권한을 통해 지원할 수 있으며
Google은 자기네들이 만든 PhotoPicker를 이용하면 migration 없이 편히 지원할 수 있으니 이를 사용하라고 대놓고 광고하고 있다.
Android 14부터는 동적으로 load된 파일(DEX, JAR, APK...) 을 읽기 전용으로 표시한 후 사용해야 한다.
val jar = File("DYNAMICALLY_LOADED_FILE.jar")
val os = FileOutputStream(jar)
os.use {
// Set the file to read-only first to prevent race conditions
jar.setReadOnly()
// Then write the actual file content
}
val cl = PathClassLoader(jar, parentClassLoader)
Android 14를 target하는 App대헤선 아래 기존과 같은 방식으로 암시적 인텐트를 내부 앱 구성요소로 보내는 경우 Exception을 발생시킨다. 이러한 변경 사항은 악성 앱이 앱의 내부 구성 요소에서 사용하도록 의도된 암시적 인텐트를 가로채는 것을 방지한다고 한다.
<activity
android:name=".AppActivity"
android:exported="false">
<intent-filter>
<action android:name="com.example.action.APP_ACTION" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
// Throws an exception when targeting Android 14.
context.startActivity(Intent("com.example.action.APP_ACTION"))
Exception을 발생시키지 않기 위해선, 다음과 같이 자신의 context.packageName
을 포함한 명시적 인텐트로 보내야 한다.
// This makes the intent explicit.
val explicitIntent = Intent("com.example.action.APP_ACTION").apply {
package = context.packageName
}
context.startActivity(explicitIntent)
안녕하세요 항상 잘보고있습니다.
안드로이드 14 관련하여 궁금한게 있습니다
저희 서비스에서 bindService()를 이용하여 다른앱에 바인드 하는데
처음 시도에는 앱 호출이 안되고 두번째 바인드를 해야지 호출이 되는데
말씀해주신 Freezing cached applications와 관련이 있을까요??
앱 배터리 최적화와 연관이 있는걸로 보여서 배터리 최적화를 끄면 이런 현상은 보이지 않아서
14버전의 버그로 보입니다만..
혹시 아시면 공유 부탁드리겠습니다..!