Notice
Recent Posts
Recent Comments
Link
«   2025/09   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
Archives
Today
Total
관리 메뉴

코린이 개발로그

Android ListView Widget을 만들어보자 본문

Kotlin & Android

Android ListView Widget을 만들어보자

코드징어 2021. 11. 29. 01:27

위젯은 다른 애플리케이션에 삽입되어 주기적인 업데이트를 받을 수 있는 소형 애플리케이션 뷰입니다.

 

앱 위젯을 만들기 위해 다음과 같은 단계가 있습니다.

  1. Manifest에 위젯과 리시버 등록하기.
  2. AppWidgetProviderInfo객채 구현
  3. AppWidgetProvider를 상속받은 클래스 구현
  4. widget layout 구현

이 모든 과정을 끝내야 위젯이 정상적으로 작동하게 됩니다. 현재는 이 과정을 따로 하지 않아도 Android Studio에서 New > Widget > AppWidget을 통해 위 과정을 한 번에 진행할 수 있습니다.

 

Manifest에서 위젯 선언하기

<receiver android:name="ExampleAppWidgetProvider" >
        <intent-filter>
            <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
        </intent-filter>
        <meta-data android:name="android.appwidget.provider"
                   android:resource="@xml/example_appwidget_info" />
    </receiver>

여기서 name에 해당하는 속성은 직접 만들어준 AppWidgetProvider를 상속받은 클래스입니다.

또한 intent-filter 에서 위젯의 업데이트를 receiver를 통해 받고 있습니다.

<meta-data>는 AppWidgetProviderInfo를 가리키고 있습니다. 다음 단계에서 만들어줄 위젯의 정보와 관련된 resource파일입니다.

 

AppWidgetProviderInfo 만들기

 

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
        android:minWidth="40dp" //최소 넓이
        android:minHeight="40dp" //최소 길이
        android:updatePeriodMillis="86400000" //업데이트 주기 86400000 = 하루
        android:previewImage="@drawable/preview" //위젯에서 보여줄 이미지
        android:initialLayout="@layout/example_appwidget" //위젯에 사용 될 레이아웃
        android:resizeMode="horizontal|vertical"//화면에서 가로/세로 수정가능 여부
        android:widgetCategory="home_screen">
    </appwidget-provider>

여기서 사용되는 minWidth와 minHeight는 각각

셀 개수 사용 가능한 크기(dp)
1 40dp
2 110dp
3 180dp
4 250dp
... ...
n 70 x n - 30

으로 계산할 수 있습니다. 

뷰의 관한 자세한 내용은 아래 링크에서 확인할 수 있습니다.

https://developer.android.com/guide/practices/ui_guidelines/widget_design?hl=ko#anatomy_determining_size

 

앱 위젯 디자인 가이드라인  |  Android 개발자  |  Android Developers

앱 위젯 디자인 가이드라인 앱 위젯(경우에 따라 '위젯'이라고도 함)은 Android 1.5에 도입된 기능이며 Android 3.0 및 3.1에서 크게 개선되었습니다. 위젯은 애플리케이션의 정보를 적시에 또는 가장

developer.android.com

 

Widget Layout 만들기

이제 실제로 사용하게 될 위젯의 layout을 만들차례입니다.

앱에서 사용되는 View들과 달리 위젯을 RemoteView를 기반으로 사용되고 있습니다.

보통 Layout에서 많이 사용되는 ConstraintLayout이지만 위젯에서는 사용이 불가능합니다. 사용 가능한 Layout은 :

  • FrameLayout
  • LinearLayout
  • RelativeLayout
  • GridLayout

들을 지원하고 있으며 해당 Layout안에서 사용가능한 Class는

  • AnalogClock
  • Button
  • Chronometer
  • ImageButton
  • ImageVIew
  • ProgressBar
  • TextView
  • ViewFlipper
  • ListView
  • GridView
  • StackView
  • AdapterViewFlipper

를 지원하고 있습니다.

또한 많이 사용되는 Recyclerview를 사용하게 되면 에러가 뜨며 위젯 생성에 문제가 있게 됩니다.

    <FrameLayout
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:padding="@dimen/widget_margin">

      <ListView
        android:id="@+id/lv_widget_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:divider="@android:color/transparent"
        android:paddingVertical="4dp"
        />

    </FrameLayout>

현재 RecyclerView를 사용할 수 없기 때문에 ListView로 만들어 주었습니다.

 

AppWidgetProvider 상속받은 클래스 생성

AppWidgetProvider는 BroadcastReceiver를 상속받고 있는 클래스로, 위젯의 브로드캐스트를 처리하기 위한 클래스입니다. 이 클래스는 위젯의 업데이트, 삭제, 생성, 설정 등등의 작업에 사용되고 있으며 이벤트들을 수신하는 데 사용됩니다.

AppWidgetProvider는 다음과 같은 함수들을 가지고 있습니다.

 

onUpdate()

위의 메타데이터에서 지정한 updatePeriodMillis속성에 의해 지정된 시간 간격마다 위젯을 업데이트하기 위해 호출됩니다. 또한 이 함수는 사용자가 위젯을 처음으로 설치할 때 불려지게 됩니다.

 

onAppWidgetOptionsChanged()

위젯이 처음으로 설치될 때 혹은 위젯의 크기에 변경이 있을 때 불려지는 함수입니다.

 

onReceive(Context, Intent)

BroadcastReceiver를 상속받기 때문에 브로드캐스트를 필터링하여 자신과 부합하는 호출에 응답을 합니다.

 

위젯에서 가장 중요한건 onUpdate()함수입니다. 위젯이 생성될때 실행 되기때문에 원하는 방식으로 이곳에서 해당 위젯을 초기화 시켜줄 수 있습니다. 현재 AppWidgetProvider에 등록된 위젯의 메타데이터는 하나 뿐이기때문에 원하는 방식으로 초기화 해주고 있습니다. 또한 클릭 이벤트같은 이벤트들은 모두 onUpdate함수에서 지정해 주어야 합니다.

 

    class ExampleAppWidgetProvider : AppWidgetProvider() {

        override fun onUpdate(
                context: Context,
                appWidgetManager: AppWidgetManager,
                appWidgetIds: IntArray
        ) {
            // Perform this loop procedure for each App Widget that belongs to this provider
            appWidgetIds.forEach { 
                val serviceIntent = Intent(context, MyRemoteViewsService::class.java)
            	val widget = RemoteViews(context.packageName, R.layout.widget)
            	widget.setRemoteAdapter(R.id.lv_widget_list, serviceIntent)
				
                appWidgetManager.updateAppWidget(appWidgetId, views)
            }
        }
    }

만약 보통의 위젯이었다면 그저 해당 위젯의 layout을 불러와 적용시켜주면 됐지만, 현재 만들고 싶은 ListView 위젯은 말 그대로 ListView이기 때문에 ListAdapter가 필요합니다, 하지만 위에서도 말했듯이 위젯은 RemoteView를 기반으로 하고 있기에 따로 이에 해당하는 Adapter를 만들어 주어야 합니다.

그래서 MyRemoteViewsService라는 객채를 생성하여 Adapter를 대신하여 Item을 생성해 줄 것입니다.

 

class MyRemoteViewsService : RemoteViewsService() {
    override fun onGetViewFactory(intent: Intent?): RemoteViewsFactory {
        return ContactRemoteViewsFactory(this.applicationContext)
    }
}
class ContactRemoteViewsFactory(
    private val context: Context
) : RemoteViewsService.RemoteViewsFactory {

    private var data = listOf(1,2,3,4,5)

    override fun onCreate() {}

    override fun onDataSetChanged() {
        //data 가 바뀌었다는 호출을 받았을 때 실행되는 함수
    }

    override fun onDestroy() {}

    override fun getCount() = data.size

    override fun getViewAt(position: Int): RemoteViews {
        val listviewWidget = RemoteViews(context.packageName, R.layout.item_widget)
        // ListView에 들어갈 item 뷰를 따로 생성해 줬습니다.
        val number = data[position]
        setTextViewText(R.id.title, number)// 해당 item의 속성을 변경해줍니다.
        return listviewWidget
    }

    override fun getLoadingView(): RemoteViews? {
        return null
    }

    override fun getViewTypeCount(): Int {
        return 1
    }

    override fun getItemId(position: Int): Long {
        return 0
    }

    override fun hasStableIds(): Boolean {
        return false
    }
}

위의 코드대로 아이템을 지정하여 ListView의 아이템을 생성해줄 수 있습니다.

 

이렇게 하여 ListView Widget의 생성과정을 알아보았습니다.

'Kotlin & Android' 카테고리의 다른 글

Compose ViewModel  (0) 2025.02.26
DI 와 Hilt 와 Repository패턴  (0) 2021.11.29
AAC 와 MVVM  (0) 2021.11.09
FireBase Gradle build 오류  (2) 2021.04.24
Comments