컬렉션 위젯은 동일한 유형의 여러 요소를 표시하는 데 특화되어 있습니다. 갤러리 앱의 사진, 뉴스 앱의 기사 또는 메시지를 보낼 수 있습니다 컬렉션 위젯은 일반적으로 두 가지 용도에 사례: 컬렉션을 탐색하고 컬렉션의 요소를 자세히 살펴보겠습니다. 컬렉션 위젯은 세로로 스크롤할 수 있습니다.
이러한 위젯은
표시할 항목 RemoteViewsService
개
원격 데이터(예:
provider 위젯은
컬렉션이라고 하는 다음 보기 유형 중 하나를 사용하여 데이터를 가져올 수 있습니다.
조회수:
ListView
- 목록을 세로로 스크롤하는 것이 좋습니다
GridView
- 2차원 스크롤 그리드를 표시합니다
StackView
- 스태킹 카드 롤로덱스와 비슷하며 사용자가 전면을 휙 돌리면 볼 수 있습니다. 카드를 위아래로 움직여 이전 카드나 다음 카드를 각각 확인합니다.
AdapterViewFlipper
-
어댑터 지원 단순
애니메이션
ViewAnimator
있습니다. 한 번에 한 자녀만 표시됩니다.
이러한 컬렉션 뷰는 원격 데이터로 지원되는 컬렉션을 표시하기 때문에
Adapter
를 사용하여 사용자를 바인딩
인터페이스를 제공합니다 Adapter
는 데이터 세트의 개별 항목을 결합합니다.
개별 View
객체에 추가합니다.
이러한 컬렉션 뷰는 어댑터에 의해 지원되므로 Android 프레임워크는
위젯에서 사용할 수 있도록 추가 아키텍처를 포함해야 합니다. 관련 맥락
Adapter
는 위젯의
RemoteViewsFactory
,
Adapter
인터페이스 주변의 얇은 래퍼입니다.
컬렉션의 특정 항목이 반환되면 RemoteViewsFactory
는
컬렉션의 항목을
RemoteViews
객체 예를 들어
컬렉션 뷰를 사용하고 RemoteViewsService
를 구현하고
RemoteViewsFactory
RemoteViewsService
는 원격 어댑터 요청을 허용하는 서비스입니다.
RemoteViews
객체. RemoteViewsFactory
: 어댑터용 인터페이스
컬렉션 뷰 간(예: ListView
, GridView
,
StackView
와 해당 뷰의 기본 데이터가 포함됩니다. 출처: StackWidget
샘플,
이것은 이 서비스를 구현하기 위한 상용구 코드의 예입니다.
인터페이스에 추가되었습니다.
Kotlin
class StackWidgetService : RemoteViewsService() { override fun onGetViewFactory(intent: Intent): RemoteViewsFactory { return StackRemoteViewsFactory(this.applicationContext, intent) } } class StackRemoteViewsFactory( private val context: Context, intent: Intent ) : RemoteViewsService.RemoteViewsFactory { // See the RemoteViewsFactory API reference for the full list of methods to // implement. }
자바
public class StackWidgetService extends RemoteViewsService { @Override public RemoteViewsFactory onGetViewFactory(Intent intent) { return new StackRemoteViewsFactory(this.getApplicationContext(), intent); } } class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory { // See the RemoteViewsFactory API reference for the full list of methods to // implement. }
샘플 애플리케이션
이 섹션의 코드 발췌 부분도 StackWidget
샘플:
![](https://developer.android.com/static/images/appwidgets/StackWidget.png?hl=ko)
StackWidget
.이 샘플은 값을 0으로 표시하는 10개의 뷰 스택으로 구성됩니다. 9까지 올라갑니다. 샘플 위젯에는 다음과 같은 기본 동작이 있습니다.
사용자는 위젯에서 상단 뷰를 세로로 플링하여 다음 뷰를 표시할 수 있습니다. 확인할 수 있습니다 이는 내장된
StackView
동작입니다.위젯은 사용자 상호작용 없이 다음 화면으로 자동 넘어갑니다. 순서대로 볼 수 있습니다. 이는
android:autoAdvanceViewId="@id/stack_view"
res/xml/stackwidgetinfo.xml
파일. 이 설정은 보기 ID, 이 경우 스택 뷰의 뷰 ID입니다.사용자가 상단 뷰를 터치하면 위젯에
Toast
메시지 "터치한 보기 n" 각 항목의 의미는 다음과 같습니다. n은 터치된 뷰의 색인 (위치)입니다. 방법에 대해 자세히 알아보려면 동작을 구현하는 방법은 개별 항목에 동작 추가를 참조하세요. 항목 섹션에서 찾을 수 있습니다.
컬렉션이 포함된 위젯 구현
컬렉션이 포함된 위젯을 구현하려면 아래 절차를 따라 하나의
위젯으로 이동한 후 몇 가지 추가 단계를 수행합니다.
컬렉션 뷰를 위젯 레이아웃에 추가하며,
AppWidgetProvider
서브클래스.
컬렉션이 있는 위젯의 매니페스트
매니페스트를 만들 때 매니페스트 파일을 포함하는 위젯이
컬렉션을 RemoteViewsService
에 바인딩합니다. 이를 위해서는
서비스에 권한을 부여해야 합니다.
BIND_REMOTEVIEWS
이렇게 하면 다른 애플리케이션이 위젯의 데이터에 자유롭게 액세스할 수 없습니다.
예를 들어 RemoteViewsService
를 사용하여
컬렉션 뷰에서 매니페스트 항목은 다음과 같을 수 있습니다.
<service android:name="MyWidgetService"
android:permission="android.permission.BIND_REMOTEVIEWS" />
이 예에서 android:name="MyWidgetService"
는
RemoteViewsService
컬렉션이 있는 위젯 레이아웃
위젯 레이아웃 XML 파일의 기본 요구사항은
컬렉션 뷰: ListView
, GridView
, StackView
또는
AdapterViewFlipper
입니다. 다음은 widget_layout.xml
파일입니다.
StackWidget
샘플:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<StackView
android:id="@+id/stack_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:loopViews="true" />
<TextView
android:id="@+id/empty_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:background="@drawable/widget_item_background"
android:textColor="#ffffff"
android:textStyle="bold"
android:text="@string/empty_view_text"
android:textSize="20sp" />
</FrameLayout>
빈 뷰는 빈 뷰는 빈 상태를 나타냅니다.
전체 위젯의 레이아웃 파일 외에 다른 레이아웃 생성
파일(예:
도서 컬렉션에 있는 각 도서의 레이아웃입니다. StackWidget
샘플에는 다음이 포함됩니다.
모든 항목이 동일한 항목을 사용하므로 widget_item.xml
라는 하나의 항목 레이아웃 파일만
있습니다.
컬렉션이 있는 위젯의 AppWidgetProvider 클래스
일반적인 위젯과 마찬가지로
AppWidgetProvider
서브클래스
일반적으로
onUpdate()
다음을 만들 때 onUpdate()
구현의 주요 차이점
가장 큰 장점은
setRemoteAdapter()
이렇게 하면 컬렉션 뷰에 데이터를 가져올 위치를 알 수 있습니다.
그러면 RemoteViewsService
가
RemoteViewsFactory
를 정의하기만 하면 위젯이 적절한 데이터를 제공할 수 있습니다.
이 메서드를 호출하고,
RemoteViewsService
및 업데이트할 위젯을 지정하는 위젯 ID입니다.
예를 들어 StackWidget
샘플이 onUpdate()
를 구현하는 방법은 다음과 같습니다.
콜백 메서드를 사용하여 RemoteViewsService
를 애플리케이션의 원격 어댑터로 설정합니다.
위젯 컬렉션:
Kotlin
override fun onUpdate( context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray ) { // Update each of the widgets with the remote adapter. appWidgetIds.forEach { appWidgetId -> // Set up the intent that starts the StackViewService, which // provides the views for this collection. val intent = Intent(context, StackWidgetService::class.java).apply { // Add the widget ID to the intent extras. putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId) data = Uri.parse(toUri(Intent.URI_INTENT_SCHEME)) } // Instantiate the RemoteViews object for the widget layout. val views = RemoteViews(context.packageName, R.layout.widget_layout).apply { // Set up the RemoteViews object to use a RemoteViews adapter. // This adapter connects to a RemoteViewsService through the // specified intent. // This is how you populate the data. setRemoteAdapter(R.id.stack_view, intent) // The empty view is displayed when the collection has no items. // It must be in the same layout used to instantiate the // RemoteViews object. setEmptyView(R.id.stack_view, R.id.empty_view) } // Do additional processing specific to this widget. appWidgetManager.updateAppWidget(appWidgetId, views) } super.onUpdate(context, appWidgetManager, appWidgetIds) }
자바
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { // Update each of the widgets with the remote adapter. for (int i = 0; i < appWidgetIds.length; ++i) { // Set up the intent that starts the StackViewService, which // provides the views for this collection. Intent intent = new Intent(context, StackWidgetService.class); // Add the widget ID to the intent extras. intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]); intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))); // Instantiate the RemoteViews object for the widget layout. RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout); // Set up the RemoteViews object to use a RemoteViews adapter. // This adapter connects to a RemoteViewsService through the specified // intent. // This is how you populate the data. views.setRemoteAdapter(R.id.stack_view, intent); // The empty view is displayed when the collection has no items. // It must be in the same layout used to instantiate the RemoteViews // object. views.setEmptyView(R.id.stack_view, R.id.empty_view); // Do additional processing specific to this widget. appWidgetManager.updateAppWidget(appWidgetIds[i], views); } super.onUpdate(context, appWidgetManager, appWidgetIds); }
데이터 지속
이 페이지에 설명된 것처럼 RemoteViewsService
서브클래스는 다음을 제공합니다.
원격 컬렉션 뷰를 채우는 데 사용된 RemoteViewsFactory
입니다.
특히 다음 단계를 수행합니다.
RemoteViewsService
서브클래스.RemoteViewsService
은(는) 다음을 통해 제공되는 서비스입니다. 원격 어댑터가RemoteViews
를 요청할 수 있습니다.RemoteViewsService
서브클래스에RemoteViewsFactory
인터페이스RemoteViewsFactory
는 원격 컬렉션 뷰 간 어댑터(예:ListView
)GridView
,StackView
, 해당 뷰의 기본 데이터 내 구현은 각 객체의RemoteViews
객체를 만듭니다. 할 수 있습니다. 이 인터페이스는Adapter
의 얇은 래퍼입니다.
서비스의 단일 인스턴스나 인스턴스에 포함된 데이터에만 의존해서는 안 됩니다.
지속됩니다 정적인 경우가 아니면 RemoteViewsService
에 데이터를 저장하지 마세요. 만약
유지하려는 경우 가장 좋은 방법은
ContentProvider
와(과) 누구의 데이터가
지속될 수 있습니다 예를 들어 식료품점 위젯은
다음과 같은 영구 위치에 각 식료품 목록 항목의 상태를 저장합니다.
SQL 데이터베이스로 되어 있습니다
RemoteViewsService
구현의 기본 콘텐츠는
RemoteViewsFactory
(다음 섹션에 설명되어 있음)
RemoteViewsFactory 인터페이스
RemoteViewsFactory
인터페이스를 구현하는 맞춤 클래스는 다음을 제공합니다.
해당 컬렉션의 항목 데이터가 포함된 위젯입니다. 이를 위해
위젯 항목 XML 레이아웃 파일을 데이터 소스와 결합합니다. 이 소스
데이터는 데이터베이스에서 간단한 배열에 이르기까지 무엇이든 될 수 있습니다. StackWidget
에 있음
샘플의 데이터 소스는 WidgetItems
의 배열입니다. RemoteViewsFactory
데이터를 원격 컬렉션 뷰에 결합하는 어댑터로 작동합니다.
캠페인을 위해 구현해야 하는 가장 중요한 두 가지 방법은
RemoteViewsFactory
서브클래스는
onCreate()
및
getViewAt()
입니다.
처음으로 팩토리를 만들 때 시스템은 onCreate()
를 호출합니다.
여기에서 데이터 소스에 대한 연결이나 커서를 설정합니다. 대상
예를 들어 StackWidget
샘플은 onCreate()
를 사용하여
WidgetItem
객체 위젯이 활성 상태이면 시스템은
객체를 사용하여 배열에서 색인 위치를 사용하고
합니다.
다음은 StackWidget
샘플의 RemoteViewsFactory
에서 발췌한 것입니다.
onCreate()
메서드의 일부를 보여주는 구현입니다.
Kotlin
private const val REMOTE_VIEW_COUNT: Int = 10 class StackRemoteViewsFactory( private val context: Context ) : RemoteViewsService.RemoteViewsFactory { private lateinit var widgetItems: List<WidgetItem> override fun onCreate() { // In onCreate(), set up any connections or cursors to your data // source. Heavy lifting, such as downloading or creating content, // must be deferred to onDataSetChanged() or getViewAt(). Taking // more than 20 seconds on this call results in an ANR. widgetItems = List(REMOTE_VIEW_COUNT) { index -> WidgetItem("$index!") } ... } ... }
자바
class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory { private static final int REMOTE_VIEW_COUNT = 10; private List<WidgetItem> widgetItems = new ArrayList<WidgetItem>(); public void onCreate() { // In onCreate(), setup any connections or cursors to your data // source. Heavy lifting, such as downloading or creating content, // must be deferred to onDataSetChanged() or getViewAt(). Taking // more than 20 seconds on this call results in an ANR. for (int i = 0; i < REMOTE_VIEW_COUNT; i++) { widgetItems.add(new WidgetItem(i + "!")); } ... } ...
RemoteViewsFactory
메서드 getViewAt()
는 RemoteViews
객체를 반환합니다.
데이터 세트에서 지정된 position
에 있는 데이터에 해당합니다. 다음은
StackWidget
샘플의 RemoteViewsFactory
구현에서 발췌 부분:
Kotlin
override fun getViewAt(position: Int): RemoteViews { // Construct a remote views item based on the widget item XML file // and set the text based on the position. return RemoteViews(context.packageName, R.layout.widget_item).apply { setTextViewText(R.id.widget_item, widgetItems[position].text) } }
자바
public RemoteViews getViewAt(int position) { // Construct a remote views item based on the widget item XML file // and set the text based on the position. RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_item); views.setTextViewText(R.id.widget_item, widgetItems.get(position).text); return views; }
개별 항목에 동작 추가
이전 섹션에서는 데이터를 위젯 컬렉션에 결합하는 방법을 보여줍니다. 하지만 캠페인의 개별 항목에 동적 동작을 추가하고 싶은 경우에는 컬렉션 뷰는 무엇인가요?
onUpdate()
로 이벤트 처리
클래스의 경우 일반적으로
setOnClickPendingIntent()
를 사용하여 객체의 클릭 동작(예:
버튼으로 Activity
를 실행합니다. 하지만
이 접근 방식은 개별 컬렉션 항목의 하위 뷰에는 허용되지 않습니다.
예를 들어 setOnClickPendingIntent()
를 사용하여 전역 버튼을 설정할 수 있습니다.
앱을 실행하는 Gmail 위젯에서
확인할 수 있습니다.
대신 컬렉션의 개별 항목에 클릭 동작을 추가하려면
setOnClickFillInIntent()
여기에는
컬렉션 뷰를 만든 다음
RemoteViewsFactory
을(를) 통해 컬렉션을 통해 수신됩니다.
이 섹션에서는 StackWidget
샘플을 사용하여 다음에 동작을 추가하는 방법을 설명합니다.
확인할 수 있습니다 StackWidget
샘플에서 사용자가 상단 뷰를 터치하면
위젯에 '터치된 뷰 n' Toast
메시지가 표시됩니다. 여기서 n은
터치된 뷰의 색인 (위치)입니다. 작동 방식은 다음과 같습니다.
StackWidgetProvider
:AppWidgetProvider
서브클래스 - 라는 사용자 지정 작업이 있는 대기 중인 인텐트를 만듭니다.TOAST_ACTION
입니다.사용자가 뷰를 터치하면 인텐트가 실행되고 브로드캐스트됩니다.
TOAST_ACTION
이 브로드캐스트는
StackWidgetProvider
클래스의onReceive()
메서드를 호출하고 위젯에Toast
메시지가 표시됨 볼 수 있습니다. 수집 항목의 데이터는RemoteViewsFactory
,RemoteViewsService
를 통해 전달됩니다.
대기 중인 인텐트 템플릿 설정
StackWidgetProvider
(
AppWidgetProvider
서브클래스)
대기 중 인텐트를 설정합니다. 컬렉션의 개별 항목은
할 수 있습니다 대신 컬렉션 전체가 대기 중인 인텐트를 설정합니다.
템플릿, 개별 항목은 채우기 인텐트를 설정하여 고유한
동작에 영향을 미칠 수 있습니다
또한 이 클래스는 사용자가
합니다. onReceive()
메소드에서 이 이벤트를 처리합니다. 인텐트의
TOAST_ACTION
인 경우 위젯은 Toast
메시지를 표시하여 현재
합니다.
Kotlin
const val TOAST_ACTION = "com.example.android.stackwidget.TOAST_ACTION" const val EXTRA_ITEM = "com.example.android.stackwidget.EXTRA_ITEM" class StackWidgetProvider : AppWidgetProvider() { ... // Called when the BroadcastReceiver receives an Intent broadcast. // Checks whether the intent's action is TOAST_ACTION. If it is, the // widget displays a Toast message for the current item. override fun onReceive(context: Context, intent: Intent) { val mgr: AppWidgetManager = AppWidgetManager.getInstance(context) if (intent.action == TOAST_ACTION) { val appWidgetId: Int = intent.getIntExtra( AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID ) // EXTRA_ITEM represents a custom value provided by the Intent // passed to the setOnClickFillInIntent() method to indicate the // position of the clicked item. See StackRemoteViewsFactory in // Set the fill-in Intent for details. val viewIndex: Int = intent.getIntExtra(EXTRA_ITEM, 0) Toast.makeText(context, "Touched view $viewIndex", Toast.LENGTH_SHORT).show() } super.onReceive(context, intent) } override fun onUpdate( context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray ) { // Update each of the widgets with the remote adapter. appWidgetIds.forEach { appWidgetId -> // Sets up the intent that points to the StackViewService that // provides the views for this collection. val intent = Intent(context, StackWidgetService::class.java).apply { putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId) // When intents are compared, the extras are ignored, so embed // the extra sinto the data so that the extras are not ignored. data = Uri.parse(toUri(Intent.URI_INTENT_SCHEME)) } val rv = RemoteViews(context.packageName, R.layout.widget_layout).apply { setRemoteAdapter(R.id.stack_view, intent) // The empty view is displayed when the collection has no items. // It must be a sibling of the collection view. setEmptyView(R.id.stack_view, R.id.empty_view) } // This section makes it possible for items to have individualized // behavior. It does this by setting up a pending intent template. // Individuals items of a collection can't set up their own pending // intents. Instead, the collection as a whole sets up a pending // intent template, and the individual items set a fillInIntent // to create unique behavior on an item-by-item basis. val toastPendingIntent: PendingIntent = Intent( context, StackWidgetProvider::class.java ).run { // Set the action for the intent. // When the user touches a particular view, it has the effect of // broadcasting TOAST_ACTION. action = TOAST_ACTION putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId) data = Uri.parse(toUri(Intent.URI_INTENT_SCHEME)) PendingIntent.getBroadcast(context, 0, this, PendingIntent.FLAG_UPDATE_CURRENT) } rv.setPendingIntentTemplate(R.id.stack_view, toastPendingIntent) appWidgetManager.updateAppWidget(appWidgetId, rv) } super.onUpdate(context, appWidgetManager, appWidgetIds) } }
자바
public class StackWidgetProvider extends AppWidgetProvider { public static final String TOAST_ACTION = "com.example.android.stackwidget.TOAST_ACTION"; public static final String EXTRA_ITEM = "com.example.android.stackwidget.EXTRA_ITEM"; ... // Called when the BroadcastReceiver receives an Intent broadcast. // Checks whether the intent's action is TOAST_ACTION. If it is, the // widget displays a Toast message for the current item. @Override public void onReceive(Context context, Intent intent) { AppWidgetManager mgr = AppWidgetManager.getInstance(context); if (intent.getAction().equals(TOAST_ACTION)) { int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); // EXTRA_ITEM represents a custom value provided by the Intent // passed to the setOnClickFillInIntent() method to indicate the // position of the clicked item. See StackRemoteViewsFactory in // Set the fill-in Intent for details. int viewIndex = intent.getIntExtra(EXTRA_ITEM, 0); Toast.makeText(context, "Touched view " + viewIndex, Toast.LENGTH_SHORT).show(); } super.onReceive(context, intent); } @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { // Update each of the widgets with the remote adapter. for (int i = 0; i < appWidgetIds.length; ++i) { // Sets up the intent that points to the StackViewService that // provides the views for this collection. Intent intent = new Intent(context, StackWidgetService.class); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]); // When intents are compared, the extras are ignored, so embed // the extras into the data so that the extras are not // ignored. intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))); RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget_layout); rv.setRemoteAdapter(appWidgetIds[i], R.id.stack_view, intent); // The empty view is displayed when the collection has no items. It // must be a sibling of the collection view. rv.setEmptyView(R.id.stack_view, R.id.empty_view); // This section makes it possible for items to have individualized // behavior. It does this by setting up a pending intent template. // Individuals items of a collection can't set up their own pending // intents. Instead, the collection as a whole sets up a pending // intent template, and the individual items set a fillInIntent // to create unique behavior on an item-by-item basis. Intent toastIntent = new Intent(context, StackWidgetProvider.class); // Set the action for the intent. // When the user touches a particular view, it has the effect of // broadcasting TOAST_ACTION. toastIntent.setAction(StackWidgetProvider.TOAST_ACTION); toastIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]); intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))); PendingIntent toastPendingIntent = PendingIntent.getBroadcast(context, 0, toastIntent, PendingIntent.FLAG_UPDATE_CURRENT); rv.setPendingIntentTemplate(R.id.stack_view, toastPendingIntent); appWidgetManager.updateAppWidget(appWidgetIds[i], rv); } super.onUpdate(context, appWidgetManager, appWidgetIds); } }
채우기 인텐트 설정
RemoteViewsFactory
는
컬렉션입니다. 이렇게 하면 클릭 시 개별 작업을 구별할 수 있습니다.
확인할 수 있습니다. 그런 다음 채우기 인텐트가
PendingIntent
템플릿을 사용하여
항목을 탭할 때 실행되는 최종 인텐트입니다.
Kotlin
private const val REMOTE_VIEW_COUNT: Int = 10 class StackRemoteViewsFactory( private val context: Context, intent: Intent ) : RemoteViewsService.RemoteViewsFactory { private lateinit var widgetItems: List<WidgetItem> private val appWidgetId: Int = intent.getIntExtra( AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID ) override fun onCreate() { // In onCreate(), set up any connections or cursors to your data source. // Heavy lifting, such as downloading or creating content, must be // deferred to onDataSetChanged() or getViewAt(). Taking more than 20 // seconds on this call results in an ANR. widgetItems = List(REMOTE_VIEW_COUNT) { index -> WidgetItem("$index!") } ... } ... override fun getViewAt(position: Int): RemoteViews { // Construct a remote views item based on the widget item XML file // and set the text based on the position. return RemoteViews(context.packageName, R.layout.widget_item).apply { setTextViewText(R.id.widget_item, widgetItems[position].text) // Set a fill-intent to fill in the pending intent template. // that is set on the collection view in StackWidgetProvider. val fillInIntent = Intent().apply { Bundle().also { extras -> extras.putInt(EXTRA_ITEM, position) putExtras(extras) } } // Make it possible to distinguish the individual on-click // action of a given item. setOnClickFillInIntent(R.id.widget_item, fillInIntent) ... } } ... }
자바
public class StackWidgetService extends RemoteViewsService { @Override public RemoteViewsFactory onGetViewFactory(Intent intent) { return new StackRemoteViewsFactory(this.getApplicationContext(), intent); } } class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory { private static final int count = 10; private List<WidgetItem> widgetItems = new ArrayList<WidgetItem>(); private Context context; private int appWidgetId; public StackRemoteViewsFactory(Context context, Intent intent) { this.context = context; appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); } // Initialize the data set. public void onCreate() { // In onCreate(), set up any connections or cursors to your data // source. Heavy lifting, such as downloading or creating // content, must be deferred to onDataSetChanged() or // getViewAt(). Taking more than 20 seconds on this call results // in an ANR. for (int i = 0; i < count; i++) { widgetItems.add(new WidgetItem(i + "!")); } ... } // Given the position (index) of a WidgetItem in the array, use the // item's text value in combination with the widget item XML file to // construct a RemoteViews object. public RemoteViews getViewAt(int position) { // Position always ranges from 0 to getCount() - 1. // Construct a RemoteViews item based on the widget item XML // file and set the text based on the position. RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget_item); rv.setTextViewText(R.id.widget_item, widgetItems.get(position).text); // Set a fill-intent to fill in the pending // intent template that is set on the collection view in // StackWidgetProvider. Bundle extras = new Bundle(); extras.putInt(StackWidgetProvider.EXTRA_ITEM, position); Intent fillInIntent = new Intent(); fillInIntent.putExtras(extras); // Make it possible to distinguish the individual on-click // action of a given item. rv.setOnClickFillInIntent(R.id.widget_item, fillInIntent); // Return the RemoteViews object. return rv; } ... }
컬렉션 데이터를 최신 상태로 유지
그림 2는 컬렉션을 사용하는 위젯의 업데이트 흐름을 보여줍니다. 표시
위젯 코드가 RemoteViewsFactory
와 상호작용하는 방법 및
트리거 업데이트:
![](https://developer.android.com/static/images/appwidgets/appwidget_collections.png?hl=ko)
RemoteViewsFactory
와의 상호작용컬렉션을 사용하는 위젯은 사용자에게 최신 콘텐츠를 제공할 수 있습니다. 대상
예를 들어 Gmail 위젯은 사용자에게 받은편지함의 스냅샷을 제공합니다. 이렇게 하려면
RemoteViewsFactory
및 컬렉션 뷰를 트리거하여
새 데이터를 표시합니다.
이렇게 하려면
호출하려면 AppWidgetManager
notifyAppWidgetViewDataChanged()
이 호출은 RemoteViewsFactory
객체의
onDataSetChanged()
새 데이터를 가져올 수 있습니다.
처리 집약적인 작업을
onDataSetChanged()
콜백입니다. 이 통화는 반드시 완료됩니다.
RemoteViewsFactory
에서 메타데이터 또는 뷰 데이터를 가져오기 전. 나
getViewAt()
내에서 처리 집약적인 작업을 실행할 수도 있습니다.
메서드를 사용하여 축소하도록 요청합니다. 이 호출이 오래 걸리는 경우
RemoteViewsFactory
객체의
getLoadingView()
메서드 - 컬렉션 뷰의 해당 위치에 표시됩니다.
반환됩니다.
RemoteCollectionItems를 사용하여 직접 컬렉션 전달
Android 12 (API 수준 31)는 setRemoteAdapter(int viewId,
RemoteViews.RemoteCollectionItems
items)
를 추가합니다.
메서드를 사용하면 객체를 채울 때 앱에서 컬렉션을 직접 전달할 수 있습니다.
컬렉션 뷰 이 방법을 사용하여 어댑터를 설정하면
RemoteViewsFactory
를 구현하고
notifyAppWidgetViewDataChanged()
이 방법을 사용하면 어댑터를 더 쉽게 채울 수 있을 뿐만 아니라
사용자가 목록을 아래로 스크롤할 때 새 항목을 채우는 데 걸리는 지연 시간을 없앱니다.
새 항목을 표시할 수 있습니다. 이 어댑터 설정 방법은
컬렉션 항목 집합은 상대적으로 작습니다. 그러나 예를 들어
컬렉션에 포함된 여러 개의 Bitmaps
가 있는 경우에는 적합하지 않습니다.
setImageViewBitmap
에 전달되었습니다.
컬렉션이 일정한 레이아웃 집합을 사용하지 않는 경우, 즉 일부
항목이 가끔만 존재합니다. setViewTypeCount
를 사용하여
컬렉션에 포함할 수 있는 고유한 레이아웃의 최대 개수입니다. 이렇게 하면
어댑터는 앱 위젯 업데이트에서 재사용될 수 있습니다.
다음은 간소화된 RemoteViews
컬렉션을 구현하는 방법을 보여주는 예입니다.
Kotlin
val itemLayouts = listOf( R.layout.item_type_1, R.layout.item_type_2, ... ) remoteView.setRemoteAdapter( R.id.list_view, RemoteViews.RemoteCollectionItems.Builder() .addItem(/* id= */ ID_1, RemoteViews(context.packageName, R.layout.item_type_1)) .addItem(/* id= */ ID_2, RemoteViews(context.packageName, R.layout.item_type_2)) ... .setViewTypeCount(itemLayouts.count()) .build() )
자바
List<Integer> itemLayouts = Arrays.asList( R.layout.item_type_1, R.layout.item_type_2, ... ); remoteView.setRemoteAdapter( R.id.list_view, new RemoteViews.RemoteCollectionItems.Builder() .addItem(/* id= */ ID_1, new RemoteViews(context.getPackageName(), R.layout.item_type_1)) .addItem(/* id= */ ID_2, new RemoteViews(context.getPackageName(), R.layout.item_type_2)) ... .setViewTypeCount(itemLayouts.size()) .build() );