본문 바로가기
안드로이드 공부 노트

[Android] 안드로이드 위젯 알아보기 3편 - Glance, Compose, Kotlin (Android Compose Glance Appwidget) 상호작용

by 지게요 2024. 5. 3.
728x90
반응형

지난 2편에서는 간단한 앱 위젯을 만들어봤다면 이번 3편에서는 액티비티 실행, 서비스 실행 등 앱 위젯 상호작용에 대해서 알아보자!

# 상호작용 종류

- 활동 실행 (Activity)

- 서비스 실행

- 브로드캐스트 이벤트 전송

- 콜백 실행

 

상호 작용이 가능한 종류로는 위 4가지가 있다.

위 종류에 대한 작업을 실행하려면 GlanceModifier.clickable 메서드를 사용하거나 Button의 onClick 메서드처럼 Action클래스에서 정의해 주면 된다.

 

하나하나 살펴보자!

## 활동 실행 (Activity)

만약 어떠한 Action이 들어왔을 때 액티비티를 띄워주고 싶다면 아래와 같이 actionStartActivity라는 메서드를 사용한다.

 

actionStartActivity에는 총 3가지를 제공할 수 있다.

 

- 띄워줄 액티비티 클래스

@Composable
fun MyContent() {
    // ..
    Button(
        text = "Go Home",
        onClick = actionStartActivity<MainActivity>()
    )
}

 

- ComponentName 

@Composable
fun MyContent() {
    // ..
    Button(
        text = "Go Home",
        onClick = actionStartActivity(
            Intent().setComponent(
                ComponentName("com.example.package", "com.example.package.TargetActivity")
            )
        )
    )
}

 

- Intent

@Composable
fun MyContent() {
    // ..
    Button(
        text = "Go Home",
        onClick = actionStartActivity(
                      Intent(
                          Intent.ACTION_VIEW,
                          Uri.parse("https://www.naver.com")
                     )
                 )
    )
}

## 서비스 실행

액티비티 실행과 비슷하게 서비스는 actionStartService메서드를 사용한다.

 

actionStartService도 마찬가지로 3가지를 제공할 수 있다.

 

- 실행할 서비스

@Composable
fun MyButton() {
    // ..
    Button(
        text = "Sync",
        onClick = actionStartService<SyncService>(
            isForegroundService = true // define how the service is launched
        )
    )
}

- ComponentName 

- Intent

 

ComponentName, Intent 코드는 활동 실행과 동일하다.


## 브로드캐스트 이벤트 전송

사용자 상호작용 시 브로드캐스트 이벤트를 전송하기 위해 actionSendBroadcast 메서드를 사용한다.

actionSendBroadcast는 총 4가지를 제공할 수 있다.

 

- 문자열작업

- ComponentName

- Intent

- BroadcastReceiver Class

@Composable
fun MyButton() {
    // ..
    Button(
        text = "Send",
        onClick = actionSendBroadcast<MyReceiver>()
    )
}

## 콜백 실행

actionRunCallback 메서드의 ActionCallback을 구현한 클래스를 제네릭으로 넣어준다.

@Composable
private fun MyContent() {
    // ..
    Image(
        provider = ImageProvider(R.drawable.ic_hourglass_animated),
        modifier = GlanceModifier.clickable(
            onClick = actionRunCallback<RefreshAction>()
        ),
        contentDescription = "Refresh"
    )
}

class RefreshAction : ActionCallback {
    override suspend fun onAction(
        context: Context,
        glanceId: GlanceId,
        parameters: ActionParameters
    ) {
        // 작업 로직
    }
}

 

코드에도 보다 시피 ActionCallback을 구현한 클래스는 onAction 함수를 필수적으로 오버라이드를 하고 콜백이 왔을 시 onAction로 들어오기 때문에 onAction 안에서 필요한 로직 처리를 해주면 된다.

 

- 작업을 실행한 후 위젯을 업데이트하는 로직 예시

@Composable
private fun MyContent() {
    // ..
    Image(
        provider = ImageProvider(R.drawable.ic_hourglass_animated),
        modifier = GlanceModifier.clickable(
            onClick = actionRunCallback<RefreshAction>()
        ),
        contentDescription = "Refresh"
    )
}

class RefreshAction : ActionCallback {
    override suspend fun onAction(
        context: Context,
        glanceId: GlanceId,
        parameters: ActionParameters
    ) {
        // 작업 실행 로직
        ...
        
        // .update함수로 위젯 업데이트
        MyAppWidget().update(context, glanceId)
    }
}

 


# 작업에 매개변수 제공 방법

앱 위젯이 어떠한 상호작용을 했을 때 (액티비티 실행, 서비스 실행, 브로드캐스트 이벤트 실행, 콜백 실행) 값을 넘겨줘야 하는 상황이 생길 수 있다.

 

이 경우 어떠한 방식으로 매개변수를 넘겨주는지 알아보자!

## 액티비티로 매개변수 제공

기존에는 Intent의 putextra를 활용하여 액티비티로 매개변수를 넘겨줬다면,

앱 위젯에서는 ActionParameters API를 사용하여 키-값 형식으로 만들어주면 된다!

### 구현방법

1. 넘겨줄 액티비티에서 상수 KEY값 생성

2. 앱 위젯 상호 작용 시 키-값 형태로 actionParametersOf를 사용해 전달

3. 해당 액티비티에서 인텐트로 값을 가져옴


1. 넘겨줄 액티비티에서 상수 KEY값 생성

class NavigationActivity : ComponentActivity() {

    companion object {
        // 상수로 KEY 값 생성
        const val KEY_DESTINATION = "destination"
    }
 }

 

2. 앱 위젯 상호 작용 시 키를 가져와서 키-값 형태로 actionParametersOf를 사용해 전달

// 전에 만들어준 키값을 ActionParameters.Key로 가져와서 변수에 담음
private val destinationKey = ActionParameters.Key<String>(
    NavigationActivity.KEY_DESTINATION
)

class MyAppWidget : GlanceAppWidget() {


    override suspend fun provideGlance(context: Context, id: GlanceId) {
            provideContent {
                MyContent()
            }
        }
        
    @Composable
    private fun MyContent() {
        Column(
            modifier = GlanceModifier.fillMaxSize()
                .background(GlanceTheme.colors.background),
            verticalAlignment = Alignment.Top,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text(
                text = "어디로 이동할까요?",
                modifier = GlanceModifier.padding(12.dp)

            )

            Button(
                text = "Home",
                onClick = actionStartActivity<NavigationActivity>(
                    // actionParametersOf를 사용해 Home이라는 값 전달
                    actionParametersOf(destinationKey to "Home")
                )
            )
        }
    }
}

 

 

3. 해당 액티비티에서 인텐트로 값을 가져옴

 

intent.extras?. getString(키값) 이 함수로 넘어온 매개변수를 받는다.

class NavigationActivity : ComponentActivity() {

    companion object {
        // 상수로 KEY 값 생성
        const val KEY_DESTINATION = "destination"
    }

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

        // intent.extras?.getString로 넘어온 값을 변수에 넣어준다.
        val destination = intent.extras?.getString(KEY_DESTINATION) ?: "destination 없음"

        Toast.makeText(this, "destination: $destination", Toast.LENGTH_LONG).show()
        setContent {
            Surface(
                modifier = Modifier.fillMaxSize(),
            ) {
                Text(
                    text = "NavigationActivity 입니다",
                    fontSize = 22.sp,
                    textAlign = TextAlign.Center
                )
            }
        }
    }
}

 

결과화면

 

 

+ 추가로 ActionCallback에도 키-값을 제공할 수 있다.(아래 예시 코드 참조)

class RefreshAction : ActionCallback {

    private val destinationKey = ActionParameters.Key<String>(
        NavigationActivity.KEY_DESTINATION
    )

    override suspend fun onAction(
        context: Context,
        glanceId: GlanceId,
        parameters: ActionParameters
    ) {
        val destination: String = parameters[destinationKey] ?: ""
        // ...
    }
}

 

 

반응형