본문 바로가기

Application Programming Interface/Android

위젯 구현하기

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

Android Widget 구현하기

- by Tapito


 Widget은 안드로이드의 홈 화면에서 보여질 수 있는 일종의 작은 어플리케이션입니다. iOS에서는 Today Extension에 해당합니다. 이를 구현하기 위해서는 3가지의 파일(Layout, WidgetProvider XML, WidgetProvicer Class)을 새로 작성하고 AndroidManifest.xml을 수정합니다.

위젯 레이아웃 XML 파일 (widget.xml)

 위젯이 홈 화면에서 보여줄 View 들을 배치하는 파일입니다. Widget에서 사용할 수 있는 요소는 아래와 같이 제한되어 있습니다.

 Layout 요소들

  • FrameLayout
  • LinearLayout
  • RelativeLayout

 View 요소들

  • AnalogClock
  • Button
  • Chronometer
  • ImageButton
  • ImageView
  • ProgressBar
  • TextView

 아래는 widget.xml의 내용입니다. Linear Layout에 TextView 1개와 Button 1개가 들어 있는 단순한 구성입니다. TextView를 통해 사용자가 설정한 문자열을 보여줄 것이고 Button을 클릭하면 MainActivity가 보여지게 할 것입니다.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:layout_width="match_parent"
	android:layout_height="match_parent"
	android:orientation="vertical">

	<TextView android:id="@+id/textView1"
		android:layout_width="match_parent"
		android:layout_height="wrap_content"
		android:text="Hello, Widget" />

	<Button
		android:id="@+id/button1"
		android:layout_width="match_parent"
		android:layout_height="wrap_content"
		android:text="Button" />

</LinearLayout>

위젯 프로바이더 XML 파일 (widget_provider.xml)

 위젯 프로바이더(Widget Provider)는 액티비티처럼 안드로이드로부터 각종 메시지, 인텐트 들을 받는 역할을 수행합니다. 위젯 프로바이더는 고정된 속성을 지정하는 XML 파일과 동적으로 메시지나 인텐트에 반응하는 Java Class 파일로 구성되어 있습니다. 먼저 XML 파일은 다음과 같이 작성할 수 있습니다.

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
	android:minHeight="72dp"
	android:minWidth="294dp"
	android:updatePeriodMillis="0"
	android:initialLayout="@layout/widget">
</appwidget-provider>

 홈 스크린은 크기의 기본 단위가 정사각형의 타일입니다. 1타일은 72dp x 72dp이고 minWidth, minHeight는 72dp의 배수로 지정합니다.

 android:initialLayout은 홈 스크린으로 보여줄 레이아웃을 지정합니다. widget.xml의 경로인 "@layout/widget"을 지정합니다.

 android:updatePeriodMillis는 위젯의 자동 새로고침 주기를 지정합니다. 단위는 msec입니다.

위젯 프로바이더 Java Class 파일 (WidgetProvider.java)

 XML 파일로써 홈 스크린에 보여질 겉 모습을 완성했다면 Java Class를 작성하여 인텐트와 메시지를 받고 동적 요소를 부여합니다.

package com.example.widgettest;

import android.app.*;
import android.appwidget.*;
import android.content.*;
import android.widget.*;

public class WidgetProvider extends AppWidgetProvider
{	
	// 위젯이 자기 자신을 업데이트해야할 때 호출되는 함수입니다.
	// 기기 사용자의 기호에 따라 홈 스크린에 위젯 자신이 여러개 띄워질 수도 있는데 이와 같은 쌍둥이들은 appWidgetIds로 들어온 위젯 ID로 각각 구분합니다.
	@Override
	public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
	{
		// TODO Auto-generated method stub
		super.onUpdate(context, appWidgetManager, appWidgetIds);
		
		for (int appWidgetId : appWidgetIds)
		{
			// 홈 스크린에 띄워진 widget.xml에 대한 인스턴스를 RemoteViews로 받아옵니다.
			// widget.xml이 갖는 각종 View들은 RemoteViews가 제공하는 함수들로만 접근이 가능합니다.
			// Widget에서 추가할 수 있는 View가 몇 종류로 제한된 것도 이 때문입니다.
			RemoteViews remoteViews = new RemoteViews(context.getPackageName(), com.example.widgettest.R.layout.widget);
			// MainActivity와 Widget간 데이터 교환의 매개체입니다.
			SharedPreferences sharedPreferences = context.getSharedPreferences("com.example.widgettest.sharedPreferences", Context.MODE_WORLD_WRITEABLE);

			// 버튼을 클릭하면 MainActivity가 뜨도록 지정합니다.
			// intent에 MainActivity가 뜨는 작동을 기억시킨 후
			Intent intent = new Intent(context, MainActivity.class);
			PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
			// R.id.button1 의 버튼을 클릭하는 동작과 이 인텐트를 연결합니다.
			remoteViews.setOnClickPendingIntent(R.id.button1, pendingIntent);

			// 또한 MainActivity에서 위젯에 띄울 문자열을 고쳤다면 이를 반영해야 합니다. sharedPreferences를 통해 MainActivity가 저장한 textBox라는 이름의 문자열 값을 가져옵니다.
			// 아직 MainActivity가 실행된 적도 없어 그런 이름의 문자열이 없다면 기본 문자열인 "HaHaHa"를 지정합니다.
			remoteViews.setTextViewText(com.example.widgettest.R.id.textView1, sharedPreferences.getString("textBox", "HaHaHa"));

			// 이 위젯이 신세지고 있는 AppWidgetMaster에게 자기 자신이 변경되었음을 알립니다.
			appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
		}
	}
}

 

AndroidManifest.xml 수정

 새로 작성한 Widget Layout, Widget Provider가 안드로이드로부터 메시지를 받으며 잘 작동하려면 AndroidManifest.xml에 아래 구분을 추가해야 합니다.

<application
	android:allowBackup="true"
	android:icon="@drawable/ic_launcher"
	android:label="@string/app_name"
	android:theme="@style/AppTheme" >

	<!-- Java Class인 WidgetProvider가 실제로 Android로부터 인텐트를 받는 위젯 프로바이더로 작동되도록 합니다. -->
	<receiver android:name=".WidgetProvider">
		<!-- 이 클래스와 관련된 설정은 widget_provider.xml에 있음을 알려줍니다. -->
		<meta-data android:name="android.appwidget.provider" android:resource="@xml/widget_provider" />
		<intent-filter>
			<!-- WidgetProvider 클래스가 onUpdate 메서드를 받아서 처리하겠다는 선언입니다. -->
			<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
		</intent-filter>
	</receiver>

	<!-- 이하 생략 -->
	<activity
		android:name=".MainActivity"
		android:label="@string/app_name" >
		<!-- 이하 생략 -->
	</activity>
</application>