위젯을 처음 사용해봤어서, 언젠가 쓸 날을 위해 정리해보도록 하겠습니다
Widget
- 홈 화면에 배치 하는 뷰 컴포넌트 (RemoteView 기반)
- RemoteView이기에 일반 View처럼 직접 조작 불가 즉, 동적 뷰 생성이 불가하기 때문에 RecyclerView, ListView, Glide등이 사용 불가
⚙️ Widget의 필수 구성 요소
AppWidgetProvider - 위젯 생명주기 관리
widget_info.xml - 위젯 크기, 초기 레이아웃, 업데이트 주기, configureActivity 설정
RemoteViews - 위젯 UI를 위한 뷰 생성 도구, 동적 뷰는 생성 불가능
ConfigureActivity - 위젯 추가 시 보여지는 Activity (widget_info.xml에서 선언한 경우만 보여짐)
위젯 동작 전체 흐름
1️⃣ 위젯은 widget_info.xml, AppWidgetProvider, RemoteViews로 구성
2️⃣ 위젯 추가 시 ConfigureActivity가 있으면 설정 화면(ConfigureActivity로 선언한 화면)으로 진입
3️⃣ 설정 완료 시 setResult(RESULT_OK)로 위젯 ID 등록
4️⃣ 시스템이 onUpdate() 호출 → RemoteViews로 위젯 UI 구성
5️⃣ AppWidgetManager.updateAppWidget()으로 실제 위젯 업데이트
전체 코드
widget ui
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/widget_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
android:orientation="vertical"
android:gravity="center">
<TextView
android:id="@+id/widget_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello Widget!"
android:textSize="18sp"
android:textColor="#000000" />
</LinearLayout>
widget_info
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="180dp"
android:minHeight="60dp"
android:updatePeriodMillis="86400000" //업데이트 주기
android:initialLayout="@layout/widget_ui" //사용할 위젯 ui
android:resizeMode="horizontal|vertical"
android:widgetCategory="home_screen" // 홈화면에서 사용할지, 잠금화면에서 사용할지
/>
widget provider
class SimpleTextWidgetProvider : AppWidgetProvider() {
override fun onUpdate(
context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray
) {
for (appWidgetId in appWidgetIds) {
// RemoteViews 생성
val views = RemoteViews(context.packageName, R.layout.widget_simple)
// 텍스트 동적으로 변경 가능 (필요 시)
views.setTextViewText(R.id.widget_text, "Hello Widget!")
// 위젯 업데이트
appWidgetManager.updateAppWidget(appWidgetId, views)
}
}
}
manifest
<receiver android:name=".SimpleTextWidgetProvider" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/simple_widget_info" />
</receiver>
🔌 onEnabled()
- 호출 시점: 위젯이 홈 화면에 ‘처음’ 추가될 때 딱 한 번 호출됨.
- 주요 용도: 시스템이 onUpdate()를 누락하거나 앱이 재실행될 때 강제 업데이트 trigger
💡 앱이 다시 실행돼도 시스템이 onUpdate()를 보장하지 않기 때문에 → onEnabled()나 앱 onCreate() 시점에서 수동 갱신 권장
- 사용 방식: AppWidgetManager.getAppWidgetIds()로 위젯 ID를 가져와 ACTION_APPWIDGET_UPDATE 브로드캐스트 전송.
- 주의사항: UI 업데이트는 여기서 직접 XXX
🧪 알아두면 좋을 팁
ConfigureActivity가 안 뜰 때 : info.xml에 선언되어 있는지 확인 필요
미리보기 이미지 등록: AndroidManifest.xml에서 <meta-data>로 android.appwidget.preview 등록
RemoteViews 제약: setTextViewText, setImageViewBitmap 등 제한된 API만 가능(동적 뷰는 XX)
주기적 갱신: AlarmManager, WorkManager 등을 활용해 수동 트리거. 단, 실시간 갱신은 비추천.
❓ 테스트하며 들었던 의문들.,
Q. Glide로 불러온 이미지를 위젯에 넣을 수 있을까?
✅ Glide에서 비트맵으로 만든 후 setImageViewBitmap()으로 넣으면 가능
Glide.with(context)
.asBitmap()
.circleCrop()
.load(imageUrl)
.into(object : CustomTarget<Bitmap>()
{
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?)
{
views.setImageViewBitmap(R.id.widget_iv, resource)
}
})
Q. configureActivity가 한 번 안 뜨면 계속 안 뜰 때?
왜냐하면 시스템이 해당 위젯 ID는 이미 설정 완료된 것으로 간주 → setResult(RESULT_OK) 또는 RESULT_CANCELED를 명확히 호출해야 재설정 가능
Q. 앱 재설치하면 다시 잘 뜨는 이유?
✅ 시스템은 위젯 상태를 앱 패키지 단위로 캐싱
: 앱을 삭제하면 위젯 관련 정보도 전부 삭제됨 → 새 앱처럼 동작 → 설정 화면 다시 뜸
Q. 위젯 크기가 실제보다 너무 클 때
✅ res/xml/widget_info.xml의 minHeight, minWidth 값을 조정해야 함(grid 단위도 있으니 확인 필요)
✅ 위젯 미리보기 이미지는 metat-data에 등록필수
AndroidManifest.xml에서 <meta-data> 등록
<meta-data
android:name="android.appwidget.preview"
android:resource="@drawable/preview_image" />
<meta-data android:name="android.appwidget.description"
android:value="@string/widget_description" />