์ถ์ฒ
ChatGPT
1. @RequiresPermission
- ํด๋น ๋ฉ์๋๋ ํด๋์ค๊ฐ ํธ์ถ๋ ๋ ํ์ํ ๊ถํ์ ์ปดํ์ผ ํ์์ ๋ช ์์ ์ผ๋ก ์ ์ ์๋ค. ์ด๋ฅผ ํตํด ์ค์๋ก ๊ถํ์ ์์ฒญํ์ง ์์ ์ํ์์ ๋ฉ์๋๋ฅผ ํธ์ถํ๋ ๊ฒ์ ๋ฐฉ์งํ๋ค.
- ์ฝ๋๋ฅผ ์ฝ๋ ์ฝ๋ ๋ค๋ฅธ ๊ฐ๋ฐ์์๊ฒ ์ด ๋ฉ์๋๋ ํด๋์ค๊ฐ ํน์ ๊ถํ์ ์๊ตฌํ๋ค๋ ๊ฒ์ ๋ช ํํ ์ ๋ฌํ ์ ์์ด ์ ์ง๋ณด์์ฑ์ ๋์ธ๋ค.
- ์๋๋ก์ด๋ Lint ๋๊ตฌ๋ ์ด ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํด ๊ถํ์ด ์ ์ ํ๊ฒ ์์ฒญ๋๊ณ ์๋ ๊ฒ์ฌํ๋ค.
- ๋์ ์๊ธฐ : API ๋ ๋ฒจ 16 (Jelly Bean)๋ถํฐ.
import android.Manifest
import android.content.Context
import android.net.wifi.WifiManager
import androidx.annotation.RequiresPermission
class WifiController(private val context: Context) {
private val wifiManager: WifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager
@RequiresPermission(Manifest.permission.ACCESS_WIFI_STATE)
fun isWifiEnabled(): Boolean {
return wifiManager.isWifiEnabled
}
@RequiresPermission(Manifest.permission.CHANGE_WIFI_STATE)
fun setWifiEnabled(enabled: Boolean) {
wifiManager.isWifiEnabled = enabled
}
}
์ด ์ฝ๋์์๋ ACCESS_WIFI_STATE์ CHANGE_WIFI_STATE ๊ถํ์ด ๊ฐ๊ฐ ํ์ํจ์ ๋ช ์ํ๊ณ ์๋ค.
2. @Nullable ๋ฐ @NonNull
- @Nullable: ํด๋น ๋ณ์, ๋ฉ์๋ ๋ฐํ ๊ฐ, ๋๋ ๋ฉ์๋ ๋งค๊ฐ๋ณ์๊ฐ null์ผ ์ ์์์ ๋ํ๋ธ๋ค.
- @NonNull: ํด๋น ์์๊ฐ null์ด ๋ ์ ์์์ ๋ํ๋ธ๋ค.
- ๋ ์ด๋ ธํ ์ด์ ์ ์๋ฐ์์ ์ ์ฉํ๋ค. ์ฝํ๋ฆฐ์ Null-Safety๋ฅผ ์ธ์ด ์์ค์์ ์ง์ํ๋ค.
- ๋์ ์๊ธฐ: ์ด๊ธฐ ์๋๋ก์ด๋ ๋ฒ์ ๋ถํฐ ์กด์ฌํ์ง๋ง, API ๋ ๋ฒจ 19 (KitKat) ์ดํ๋ก ์๋๋ก์ด๋ SDK์์ ๊ณต์ ์ง์๋์๋ค.
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class UserManager {
// ์ด ๋ฉ์๋๋ ์ ๋ null์ ๋ฐํํ์ง ์์์ ๋ช
์
@NonNull
public String getUserName() {
return "John Doe";
}
// ์ด ๋ฉ์๋๋ null์ ๋ฐํํ ์ ์์์ ๋ช
์
@Nullable
public String getUserNickname() {
// ์ฌ์ฉ์์๊ฒ ๋ณ๋ช
์ด ์์ ์๋ ์์
return null;
}
// ์ด ๋ฉ์๋๋ null์ด ๋ ์ ์๋ ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฐ์์ผ ํจ์ ๋ช
์
public void printUserName(@NonNull String userName) {
System.out.println("User name: " + userName);
}
// ์ด ๋ฉ์๋๋ null์ด ๋ ์ ์๋ ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฐ์ ์ฒ๋ฆฌ
public void printUserNickname(@Nullable String userNickname) {
if (userNickname != null) {
System.out.println("User nickname: " + userNickname);
} else {
System.out.println("User has no nickname");
}
}
public static void main(String[] args) {
UserManager userManager = new UserManager();
// NonNull ๋ฐํ๊ฐ์ null ์ฒดํฌ๊ฐ ํ์ ์์
String userName = userManager.getUserName();
userManager.printUserName(userName);
// Nullable ๋ฐํ๊ฐ์ null ์ฒดํฌ๊ฐ ํ์ํจ
String userNickname = userManager.getUserNickname();
userManager.printUserNickname(userNickname);
// NonNull ํ๋ผ๋ฏธํฐ์ null์ ์ ๋ฌํ๋ ค๊ณ ํ๋ฉด ์ปดํ์ผ ์ค๋ฅ ๋ฐ์
// userManager.printUserName(null); // ์ปดํ์ผ ์ค๋ฅ
// Nullable ํ๋ผ๋ฏธํฐ์๋ null์ ์ ๋ฌํ ์ ์์
userManager.printUserNickname(null);
}
}
- @NonNull:
- getUserName() ๋ฉ์๋๋ ์ ๋ null์ ๋ฐํํ์ง ์๋๋ก ๋ณด์ฅํ๋ค.
- printUserName() ๋ฉ์๋๋ null์ด ์๋ ๊ฐ์ ๋ฐ์์ผ ํ๋ค๋ ๊ฒ์ ๋ช ์ํ๋ค.
- @Nullable:
- getUserNickname() ๋ฉ์๋๋ null์ ๋ฐํํ ์ ์์์ ๋ํ๋ด๊ณ , ์ฌ์ฉ์๋ ๋ฐํ ๊ฐ์ ์ฌ์ฉํ ๋ ๋ฐ๋์ null ์ฒดํฌ๋ฅผ ํด์ผ ํ๋ค.
- printUserNickname() ๋ฉ์๋๋ null์ผ ์ ์๋ ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฐ์ ์ฒ๋ฆฌํ๋ค.
- ๋ฉ์ธ ๋ฉ์๋:
- getUserName()์ ๋ฐํ๊ฐ์ NonNull๋ก ์ง์ ๋์๊ธฐ ๋๋ฌธ์, ๋ณ๋์ null ์ฒดํฌ ์์ด ๋ฐ๋ก ์ฌ์ฉํ ์ ์๋ค.
- ๋ฐ๋ฉด getUserNickname()์ Nullable๋ก ์ง์ ๋์๊ธฐ ๋๋ฌธ์, ๋ฐํ๋ ๊ฐ์ด null์ผ ๊ฐ๋ฅ์ฑ์ ๊ณ ๋ คํด null ์ฒดํฌ๋ฅผ ํด์ผ ํ๋ค.
3. @UiThread, @MainThread, @WorkerThread
- @UiThread: ๋ฉ์๋๊ฐ UI ์ค๋ ๋์์ ํธ์ถ๋์ด์ผ ํจ์ ๋ํ๋ธ๋ค.
- @MainThread: ๋ฉ์๋๊ฐ ๋ฉ์ธ ์ค๋ ๋์์ ํธ์ถ๋์ด์ผ ํจ์ ๋ํ๋ธ๋ค (์ฃผ๋ก UI ์ค๋ ๋๋ฅผ ์๋ฏธํ๋ค).
- @WorkerThread: ๋ฉ์๋๊ฐ ๋ฐฑ๊ทธ๋ผ์ด๋ ์ค๋ ๋์์ ํธ์ถ๋์ด์ผ ํจ์ ๋ํ๋ธ๋ค.
- ๋์ ์๊ธฐ: API ๋ ๋ฒจ 21 (Lollipop)๋ถํฐ.
import android.os.AsyncTask
import androidx.annotation.UiThread
import androidx.annotation.WorkerThread
class DataFetcher {
@WorkerThread
fun fetchData(): String {
// ์ด ๋ฉ์๋๋ ๋ฐฑ๊ทธ๋ผ์ด๋ ์ค๋ ๋์์ ์คํ๋์ด์ผ ํจ
Thread.sleep(1000) // ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ์๋ฎฌ๋ ์ด์
return "Data"
}
@UiThread
fun displayData(data: String) {
// ์ด ๋ฉ์๋๋ UI ์ค๋ ๋์์ ์คํ๋์ด์ผ ํจ
println("Displaying data: $data")
}
fun startFetching() {
AsyncTask.execute {
val data = fetchData() // ๋ฐฑ๊ทธ๋ผ์ด๋์์ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ
displayData(data) // UI ์ค๋ ๋์์ ๋ฐ์ดํฐ ํ์
}
}
}
์ฌ๊ธฐ์๋ @WorkerThread์ @UiThread๋ฅผ ์ฌ์ฉํด ๊ฐ๊ฐ์ ๋ฉ์๋๊ฐ ์ด๋์ ์คํ๋์ด์ผ ํ๋์ง ๋ช ์ํ๋ค.
4. @CheckResult
- @CheckResult: ๋ฉ์๋ ํธ์ถ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ๋์ ํ์ธํด์ผ ํจ์ ๋ํ๋ธ๋ค. ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ์ง ์์ผ๋ฉด ์ค์ํ ๋์์ ๋์น ์ ์๋ค๋ ๊ฒฝ๊ณ ๋ฅผ Lint๋ฅผ ํตํด ๋ฐ์ ์ ์๋ค.
- ๋์ ์๊ธฐ: API ๋ ๋ฒจ 17 (Jelly Bean MR1)๋ถํฐ.
import androidx.annotation.CheckResult
@CheckResult
fun calculateSum(a: Int, b: Int): Int {
return a + b
}
fun main() {
val result = calculateSum(3, 4) // ์ฌ๋ฐ๋ฅธ ์ฌ์ฉ
println("Sum: $result")
// calculateSum(3, 4) // ์ด ์ค์์ Lint๊ฐ ๊ฒฐ๊ณผ๋ฅผ ์ฌ์ฉํ์ง ์๋๋ค๊ณ ๊ฒฝ๊ณ ํ ๊ฒ
}
@CheckResult๋ ๋ฐํ๊ฐ์ด ์ฌ์ฉ๋์ง ์์ ๋ ๊ฒฝ๊ณ ๋ฅผ ํ์ํด ์ค์๋ฅผ ๋ฐฉ์งํ ์ ์.
5. @VisibleForTesting
- @VisibleForTesting: ํน์ ๋ฉ์๋, ํ๋ ๋๋ ํด๋์ค๊ฐ ํ ์คํธ ๋ชฉ์ ์ผ๋ก๋ง ์ ๊ทผ ๊ฐ๋ฅํจ์ ๋ํ๋ธ๋ค. ์๋ฅผ ๋ค์ด, ์ผ๋ฐ์ ์ผ๋ก๋ private์ด์ง๋ง ํ ์คํธ์์๋ ์ ๊ทผ ๊ฐ๋ฅํ๋๋ก ํ ๋ ์ฌ์ฉํ๋ค.
- ๋์ ์๊ธฐ: API ๋ ๋ฒจ 21 (Lollipop)๋ถํฐ.
import androidx.annotation.VisibleForTesting
class Calculator {
fun add(a: Int, b: Int): Int {
return a + b
}
@VisibleForTesting
internal fun subtract(a: Int, b: Int): Int {
return a - b
}
}
subtract ๋ฉ์๋๋ ์ฃผ๋ก ํ ์คํธ ๋ชฉ์ ์ผ๋ก๋ง ๊ณต๊ฐ๋๋ฉฐ, ์ผ๋ฐ์ ์ผ๋ก๋ internal๋ก ์ ์ง๋๋ค.
- ์ ์์ ์ฝ๋์์ @VisibleForTesting ์ด๋ ธํ ์ด์ ์ด ๋ถ์ subtract() ๋ฉ์๋์ internal ์ ๊ทผ ์ ํ์๋ฅผ ์ฌ์ฉํ ๊ฒ์ธ๊ฐ
์ ์์ ์ฝ๋์์ @VisibleForTesting ์ด๋ ธํ ์ด์ ์ด ๋ถ์ subtract() ๋ฉ์๋์ internal ์ ๊ทผ ์ ํ์๋ฅผ ์ฌ์ฉํ ๊ฒ์ธ๊ฐ
@VisibleForTesting์ internal์ ์ญํ
- @VisibleForTesting: ์ด ์ด๋ ธํ ์ด์ ์ ๋ฉ์๋๋ ํ๋๊ฐ ์๋๋ ์ ํ๋ ์ ๊ทผ ์์ค(์: private, internal)์ ๊ฐ์ง์ง๋ง, ํ ์คํธ ๋ชฉ์ ์ผ๋ก ์ ๊ทผํ ์ ์๊ฒ ํ๋ ค๋ ์๋๋ฅผ ๋ช ์ํ ๋ ์ฌ์ฉ๋๋ค. ์ฆ, ์ด ์ด๋ ธํ ์ด์ ์ "์ด ์ฝ๋๋ ์๋๋ ์ธ๋ถ์ ๋ ธ์ถ๋์ง ๋ง์์ผ ํ์ง๋ง, ํ ์คํธ๋ฅผ ์ํด ์ ๊ทผ ๊ฐ๋ฅํด์ผ ํ๋ค"๋ ์๋๋ฅผ ๋ํ๋ด๋ ๊ฒ์ด๋ค.
- internal ์ ๊ทผ ์ ํ์: ์ฝํ๋ฆฐ์์ internal์ ํด๋น ๋ฉค๋ฒ๊ฐ ๊ฐ์ ๋ชจ๋ ๋ด์์๋ง ์ ๊ทผ ๊ฐ๋ฅํ๊ฒ ํ๋ ์ ๊ทผ ์ ํ์๋ค. ๋ฐ๋ผ์ internal๋ก ์ ์ธ๋ ๋ฉ์๋๋ ํ๋๋ ๊ฐ์ ๋ชจ๋ ๋ด์ ๋ค๋ฅธ ํด๋์ค๋ ํจ์์์ ์ ๊ทผํ ์ ์์ง๋ง, ๋ชจ๋ ์ธ๋ถ์์๋ ์ ๊ทผํ ์ ์๋ค.
์์ ์ฝ๋์์ subtract()์ internal์ ์ฌ์ฉํ ์ด์
class Calculator {
fun add(a: Int, b: Int): Int {
return a + b
}
@VisibleForTesting
internal fun subtract(a: Int, b: Int): Int {
return a - b
}
}
์ด ์ฝ๋์์ subtract() ๋ฉ์๋๊ฐ internal๋ก ์ ์ธ๋ ์ด์ ๋ ํ ์คํธ ๋ชฉ์ ์ผ๋ก๋ ์ ๊ทผํ ์ ์์ง๋ง, ์ค์ ์ ํ๋ฆฌ์ผ์ด์ ์ฝ๋์์๋ ์ธ๋ถ์ ๋ ธ์ถ๋์ง ์๋๋ก ํ๊ธฐ ์ํด์.
1. ๋ชจ๋์ ์บก์ํ ์ ์ง
- subtract() ๋ฉ์๋๋ ๋ณธ๋ private์ผ๋ก ๋์ด์ผ ํ ๋ฉ์๋์ผ ์ ์๋ค. ๊ทธ๋ฌ๋ ํ ์คํธ ์ฝ๋์์๋ ์ด ๋ฉ์๋๋ฅผ ํธ์ถํด ํ ์คํธํ๊ณ ์ถ์ ๋๊ฐ ์๋ค. ์ด๋ @VisibleForTesting ์ ๋ ธํ ์ด์ ์ ์ฌ์ฉํด ์ด ๋ฉ์๋๊ฐ ํ ์คํธ๋ฅผ ์ํด์๋ง ์กด์ฌํ๋ค๊ณ ๋ช ์ํ๋ ๊ฒ์ด๋ค.
- ๋์์ internal์ ์ฌ์ฉํ๋ฉด ๊ฐ์ ๋ชจ๋ ๋ด์์๋ง ์ ๊ทผํ ์ ์๋๋ก ์ ํํด, ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๋ค๋ฅธ ๋ชจ๋์์๋ ์ด ๋ฉ์๋์ ์ ๊ทผํ ์ ์๋ค. ์ด๋ ๋ชจ๋์ ์บก์ํ๋ฅผ ์ ์งํ๋ฉด์๋, ํ ์คํธ์ ํธ์์ฑ์ ํ๋ณดํ ์ ์๋ ๋ฐฉ๋ฒ์ด๋ค.
2. ๋ชจ๋ ์ธ๋ถ์์์ ์ ๊ทผ ๋ฐฉ์ง
- ๋ง์ฝ subtract() ๋ฉ์๋๋ฅผ public์ผ๋ก ์ ์ธํ๋ฉด, ์ด ๋ฉ์๋๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ชจ๋ ๋ถ๋ถ์์ ์ ๊ทผํ ์ ์๊ฒ ๋๋ค. ๊ทธ๋ฌ๋ ์ด ๋ฉ์๋๊ฐ ํ ์คํธ ๋ชฉ์ ์ผ๋ก๋ง ์ฌ์ฉ๋๊ธฐ๋ฅผ ์ํ ๊ฒฝ์ฐ, public์ผ๋ก ๋ง๋๋ ๊ฒ์ ๋ถ์ ์ ํ ์ ์๋ค.
- internal๋ก ์ ํํ๋ฉด, ์ด ๋ฉ์๋๋ ๊ฐ์ ๋ชจ๋ ๋ด์์๋ง ์ฌ์ฉ ๊ฐ๋ฅํ๊ณ ์ธ๋ถ์์๋ ์ ๊ทผํ ์ ์๊ฒ ๋๋ฏ๋ก, ๋ถํ์ํ๊ฒ ์ธ๋ถ์ ๋ ธ์ถ๋์ง ์์๋ ๋๋ค.
internal๋ก ์ ์งํ ํ์๊ฐ ์์ ๋
๋ง์ฝ subtract() ๋ฉ์๋๊ฐ ํ ์คํธ๋ฟ๋ง ์๋๋ผ ๋ค๋ฅธ ํด๋์ค๋ ๋ชจ๋์์๋ ์ฌ์ฉ๋๊ธธ ์ํ๋ค๋ฉด public์ผ๋ก ์ ์ธํ ์ ์๋ค. ์ด๋ ๊ฒ ํ๋ฉด ๋ชจ๋ ์ฝ๋์์ ์ ๊ทผ ๊ฐ๋ฅํด์ง์ง๋ง, ์ด ๊ฒฝ์ฐ์๋ @VisibleForTesting์ ์ฌ์ฉํ๋ ๋ชฉ์ ์ด ํฌ์๋ ์ ์์ด๋ค
๊ทธ๋ฌ๋ ์์ ์์๋ ์ด ๋ฉ์๋๊ฐ ํ ์คํธ ๋ชฉ์ ์ผ๋ก๋ง ๋ ธ์ถ๋๊ธฐ๋ฅผ ์ํ๊ธฐ ๋๋ฌธ์, internal๋ก ์ ํ์ ๋์ด ๋ค๋ฅธ ๋ชจ๋์์๋ ์ ๊ทผํ ์ ์๋๋ก ํ ๊ฒ์ด.
๊ฒฐ๋ก
- @VisibleForTesting์ ํ ์คํธ๋ฅผ ์ํด ์๋๋ ์ ํ๋ ์ ๊ทผ ์์ค์ ๊ฐ์ง ๋ฉ์๋๋ฅผ ๋ ธ์ถํ ๋ ์ฌ์ฉ๋๋ค.
- internal์ ๋ชจ๋์ ๊ฒฝ๊ณ๋ฅผ ๋์ง ์๋ ์ ์์๋ง ๋ฉ์๋๊ฐ ์ฌ์ฉ๋๋๋ก ์ ํํด, ๋ชจ๋์ ์บก์ํ๋ฅผ ์ ์งํ๋ฉด์๋ ํ ์คํธ๋ฅผ ๊ฐ๋ฅํ๊ฒ ํด์ค๋ค.
- ์ด ์ ๊ทผ๋ฒ์ ์ฝ๋์ ์์ ์ฑ์ ๋์ด๊ณ , ์๋์น ์์ ์ฌ์ฉ์ ๋ฐฉ์งํ๋ ๋ฐ ๋์์ด ๋๋ค.
6. @CallSuper
- @CallSuper: ์ค๋ฒ๋ผ์ด๋๋ ๋ฉ์๋์์ ๋ฐ๋์ ์ํผ ํด๋์ค์ ํด๋น ๋ฉ์๋๋ฅผ ํธ์ถํด์ผ ํจ์ ๋ํ๋ธ๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์์์น ๋ชปํ ๋์์ด ๋ฐ์ํ ์ ์๋ค.
- ๋์ ์๊ธฐ: API ๋ ๋ฒจ 21 (Lollipop)๋ถํฐ.
import androidx.annotation.CallSuper
open class Animal {
@CallSuper
open fun makeSound() {
println("Animal sound")
}
}
class Dog : Animal() {
override fun makeSound() {
super.makeSound() // ๋ฐ๋์ ํธ์ถํด์ผ ํจ
println("Bark")
}
}
์ฌ๊ธฐ์๋ @CallSuper๋ฅผ ์ฌ์ฉํด ์๋ธํด๋์ค๊ฐ ๋ถ๋ชจ ํด๋์ค์ ๋ฉ์๋๋ฅผ ๋ฐ๋์ ํธ์ถํ๋๋ก ๋ช ์ํ๋ค.
7. @Size
- @Size: ์ปฌ๋ ์ , ๋ฐฐ์ด, ๋ฌธ์์ด ๋ฑ์ ํฌ๊ธฐ ๋๋ ๊ธธ์ด์ ๋ํ ์ ํ์ ๋ํ๋ธ๋ค. ์๋ฅผ ๋ค์ด, ํน์ ๋ฐฐ์ด์ ํฌ๊ธฐ๊ฐ 10์ด์ด์ผ ํจ์ ๋ช ์ํ ์ ์๋ค.
- ๋์ ์๊ธฐ: API ๋ ๋ฒจ 21 (Lollipop)๋ถํฐ.
import androidx.annotation.Size
fun setScores(@Size(min = 1, max = 5) scores: IntArray) {
println("Scores: ${scores.joinToString()}")
}
fun main() {
setScores(intArrayOf(10, 20, 30)) // ์ฌ๋ฐ๋ฅธ ์ฌ์ฉ
// setScores(intArrayOf()) // Lint๊ฐ ๊ฒฝ๊ณ ๋ฅผ ํ์ํจ (ํฌ๊ธฐ๊ฐ 1 ์ด์์ด์ด์ผ ํจ)
}
@Size๋ฅผ ์ฌ์ฉํด ๋ฐฐ์ด์ ํฌ๊ธฐ์ ๋ํ ์ ์ฝ์ ๋ช ์ํ ์ ์๋ค.
8. @IntDef ๋ฐ @StringDef
- @IntDef: ํน์ ๋ฉ์๋ ๋๋ ๋ณ์์ ํ์ฉ๋๋ ์ ์ ๊ฐ์ ์ ์ํ๋ ๋ฐ ์ฌ์ฉํ๋ค. ์ด๊ฒ์ ์ด๊ฑฐํ์ ๋์์ผ๋ก ์ฌ์ฉํ ์ ์์ด, ์ฑ๋ฅ ์ต์ ํ๋ฅผ ์ํด ์ฌ์ฉ๋๊ธฐ๋ ํ๋ค.
- @StringDef: ํน์ ๋ฉ์๋ ๋๋ ๋ณ์์ ํ์ฉ๋๋ ๋ฌธ์์ด ๊ฐ์ ์ ์ํ๋ ๋ฐ ์ฌ์ฉํ๋ค. ๋ฌธ์์ด ์์์ ์ ํจ์ฑ์ ๊ฒ์ฌํ๊ธฐ ์ํด ๋์ ๋๋ค. ์๋ชป๋ ๋ฌธ์์ด ๊ฐ์ ์ฌ์ฉ์ ๋ฐฉ์งํ๋ค.
- ๋์ ์๊ธฐ: API ๋ ๋ฒจ 19 (KitKat)๋ถํฐ.
import androidx.annotation.IntDef
const val MODE_A = 0
const val MODE_B = 1
@IntDef(MODE_A, MODE_B)
@Retention(AnnotationRetention.SOURCE)
annotation class Mode
fun setMode(@Mode mode: Int) {
println("Mode set to $mode")
}
fun main() {
setMode(MODE_A) // ์ฌ๋ฐ๋ฅธ ์ฌ์ฉ
// setMode(2) // ์ปดํ์ผ๋ฌ๊ฐ ์๋ชป๋ ๊ฐ์ด๋ผ๊ณ ๊ฒฝ๊ณ ํจ
}
@IntDef๋ ํ์ฉ๋๋ ์ ์ ๊ฐ์ ์ ํํด ํ์ ์์ ์ฑ์ ๋์ฌ์ค๋ค.
import androidx.annotation.StringDef;
public class NetworkManager {
public static final String WIFI = "WIFI";
public static final String MOBILE = "MOBILE";
public static final String ETHERNET = "ETHERNET";
@StringDef({WIFI, MOBILE, ETHERNET})
@Retention(RetentionPolicy.SOURCE)
public @interface NetworkType {}
private String currentNetworkType = WIFI;
public void setNetworkType(@NetworkType String networkType) {
this.currentNetworkType = networkType;
}
@NetworkType
public String getNetworkType() {
return currentNetworkType;
}
}
9. @Keep
- @Keep: ํ๋ก๊ฐ๋(ProGuard)๋ R8 ๊ฐ์ ์ฝ๋ ์์ถ๊ธฐ์์ ํด๋์ค, ๋ฉ์๋, ํ๋๊ฐ ์ ๊ฑฐ๋๊ฑฐ๋ ๋๋ ํ๋์ง ์๋๋ก ๋ณดํธํ ๋ ์ฌ์ฉํ๋ค.
- ๋์ ์๊ธฐ: API ๋ ๋ฒจ 21 (Lollipop)๋ถํฐ.
import androidx.annotation.Keep
@Keep
class ImportantClass {
fun doSomething() {
println("Doing something important")
}
}
@Keep์ ์ฌ์ฉํ๋ฉด ProGuard๋ R8์ด ์ด ํด๋์ค์ ๊ทธ ๋ฉ์๋๋ฅผ ์ ๊ฑฐํ๊ฑฐ๋ ๋๋ ํํ์ง ์๋๋ก ๋ณดํธํ ์ ์๋ค.
10. @RequiresApi
- @RequiresApi: ๋ฉ์๋๋ ํด๋์ค๊ฐ ํน์ API ๋ ๋ฒจ ์ด์์์๋ง ์ฌ์ฉ ๊ฐ๋ฅํจ์ ๋ํ๋ธ๋ค.
- ๋์ ์๊ธฐ: API ๋ ๋ฒจ 19 (KitKat)๋ถํฐ.
import android.os.Build
import androidx.annotation.RequiresApi
@RequiresApi(Build.VERSION_CODES.O)
fun useNewApiFeature() {
// Android O (API 26) ์ด์์์๋ง ์คํ๋๋ ์ฝ๋
println("Using Android O feature")
}
@RequiresApi๋ ํน์ API ๋ ๋ฒจ ์ด์์์๋ง ์ฌ์ฉํ ์ ์๋ ๋ฉ์๋๋ ํด๋์ค๋ฅผ ๋ช ์ํ ๋ ์ฌ์ฉ๋๋ค.
11. @TargetApi
- ํด๋น ๋ฉ์๋, ํด๋์ค, ๋๋ ํ๋๊ฐ ํน์ API ๋ ๋ฒจ์์๋ง ์ฌ์ฉ๋ ์ ์์์ ๋ฌธ์ํํ๋ค. ์ด๋ฅผ ํตํด ์ฝ๋ ๋ฆฌ๋ทฐ์ด์ ๊ฐ๋ฐ์๋ค์๊ฒ ๋ฉ์๋๊ฐ ์๋๋ API ๋ ๋ฒจ์ ๋ช ํํ ์๋ฆด ์ ์๋ค.
- IDE์์๋ @TargetApi ์ ๋ ธํ ์ด์ ์ด ๋ถ์ ๋ฉ์๋์ ๋ํด, ์ฌ์ฉ ์ค์ธ API ๋ ๋ฒจ์ ๋ฐ๋ผ ์ ์ ํ ๊ฒฝ๊ณ ๋ฅผ ์ ๊ณตํ ์ ์.
- ๋์ ์๊ธฐ: API ๋ ๋ฒจ 16 (Jelly Bean)๋ถํฐ.
import android.annotation.TargetApi
import android.os.Build
import android.widget.Toast
import android.content.Context
class ApiLevelExample(private val context: Context) {
// ์ด ๋ฉ์๋๋ API ๋ ๋ฒจ 21 (Lollipop) ์ด์์์๋ง ๋์ํ๋๋ก ์ค๊ณ๋จ
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
fun showToastWithNewFeature() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// API ๋ ๋ฒจ 21 ์ด์์์๋ง ์ฌ์ฉํ ์ ์๋ ๊ธฐ๋ฅ
Toast.makeText(context, "This feature is available on API 21 and above", Toast.LENGTH_LONG).show()
} else {
// API ๋ ๋ฒจ 21 ์ดํ์์๋ ์คํ ๊ฐ๋ฅํ ๊ธฐ๋ณธ ๊ธฐ๋ฅ
Toast.makeText(context, "This feature is not available on this API level", Toast.LENGTH_LONG).show()
}
}
}
๋ฐํ์์์ ์ค์ ๋ก API ๋ ๋ฒจ์ ํ์ธํ๊ณ , ํด๋น ๋ ๋ฒจ์์๋ง ํน์ ๊ธฐ๋ฅ์ด ์คํ๋๋๋ก ํ๋ ์ฝ๋๋ฅผ ์์ฑํด์ผ ํ๋ค. ์ด ์ด๋ ธํ ์ด์ ์์ฒด๊ฐ ๋ฐํ์์์ ์ฝ๋์ ์คํ์ ์ ์ดํ์ง๋ ์๋๋ค.
- @TargetApi ์ด๋
ธํ
์ด์
- ์ด ์ด๋ ธํ ์ด์ ์ ๋ฉ์๋์ ๋ถ์ฌ์, ํด๋น ๋ฉ์๋๊ฐ ํน์ API ๋ ๋ฒจ ์ด์์์๋ง ์ฌ์ฉ๋๋ค๋ ๊ฒ์ ๋ํ๋ธ๋ค.
- Build.VERSION_CODES.LOLLIPOP:
- Build.VERSION_CODES.LOLLIPOP์ API ๋ ๋ฒจ 21์ ์๋ฏธํ๋ค.
- ์ด ์์๋ ์๋๋ก์ด๋ SDK์์ ์ ๊ณตํ๋ฉฐ, ํ์ฌ ๊ธฐ๊ธฐ์ API ๋ ๋ฒจ๊ณผ ๋น๊ตํ๋ ๋ฐ ์ฌ์ฉ๋๋ค.
- showToastWithNewFeature() ๋ฉ์๋:
- ์ด ๋ฉ์๋๋ API ๋ ๋ฒจ 21 ์ด์์ ๊ธฐ๊ธฐ์์๋ง ๋์ํ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค.
- API ๋ ๋ฒจ 21 ์ดํ์์๋ ํด๋น ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์์์ ์ฌ์ฉ์์๊ฒ ์๋ฆฌ๋ ๋ฉ์์ง๋ฅผ ํ์ํ๋ค.