본문 바로가기
안드로이드

앱 위젯 만들기

by 희안 2021. 5. 8.

앱 위젯은 안드로이드 단말의 홈 화면에서 위젯을 바로 보여주고 싶을 때 사용할 수 있다.

위젯은 다른 앱 안에 들어갈 수 있도록 만들어져서 홈화면에 위젯이 보이는 과정은 홈 화면 안에 위젯으로 구성한 앱이 들어가 있다고 생각하면 된다. 앱 위젯은 홈 화면안의 일정영역을 할당받아 보여지지만 결과 화면만을 보여준다. 

 

위젯의 구성은 위젯을 담고있는 그릇인 앱 위젯 호스트위젯을 보여주는 제공자인 앱 위젯 제공자로 구성되어 있다. 앱 위젯을 만든다는 건 앱 위젯 제공자를 만드는것이고 앱 위젯 제공자를 구성할 때 필요한 요소는 :

1. 위젯 초기 뷰 레이아웃 : 앱 위젯이 처음에 화면에 나타날때 필요한 레이아웃(XML)

2. 위젯 제공자 정보 객체 : 위젯을 위한 메타데이터(레이아웃, 업데이트 주기 등)을 가진다. 앱 위젯 제공자 클래스에 대한 정보도 가지고 있다. (XML)

3. 앱 위젯 제공자 : 앱 위젯과 정보를 주고받기 위한 기본 클래스. 브로드캐스트 수신자로 만들고 위젯 상태변화에 따른 기능을 구현한다.

 

위젯으로 만든 뷰는 주기적으로 업데이트 될 수 있는데 위젯 제공자의 onUpdate()가 호출된다. 위젯 제공자가 위젯을 바꾸고 싶을 땐 위젯 매니저를 통해 업데이트 할 수 있다. 

 

내 위치 표시해주는 위젯 만들어보기 : 

앱 위젯에 들어갈 수 있는 뷰 유형은 FrameLayout, LinearLayout, Relative Layout, AnalogClock, Button, Chronometer ImageButton, ImageView, ProgressBar, TextView가 있어서 이 뷰들을 추가해서 사용할 수 있다. 이 이유는 앱 위젯으로 표현되는 뷰들이 다른 프로세스에 들어가 있고 이 다른프로세스 뷰를 접근하기 위해 RemoteViews객체가 사용되기 때문이다. 이 뷰를 이용해서 위젯 레이아웃을 정의해봤다.

<LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/happy"
        android:padding="10dp">

        <TextView
            android:id="@+id/txtInfo"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center_horizontal|center_vertical"
            android:text="내 위치 정보 수신중 ..."
            android:textColor="#FFFFFFFF"
            android:lineSpacingExtra="4dp" />

    </LinearLayout>

이 정보를 이용해 앱 위젯 제공자 정보를 만들자. app/res/아래에 xml 폴더를 만들어 앱위젯 제공자 정보를 넣었다.

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="294dp"
    android:minHeight="72dp"
    android:updatePeriodMillis="1800000"
    android:initialLayout="@layout/mylocation">
</appwidget-provider>

앱 위젯 뷰의 최소크기는 minWidth와 minHeight로 지정하고 주기적으로 업데이트되는 간격은 updatePeriodMillis 로 지정할 수 있다. 180000는 30분을 의미한다. 위젯의 크기는 홈 화면의 화면 분할에 따라 74dp 단위로 설정하는게 좋다. 

 

앱위젯을 구성하기위한 앱 위젯 제공자 클래스를 정의하자. 앱 위젯 제공자 클래스는 AppWidgetProvider클래스를 상속하여 정의하고 이 클래스의 주 역할은 앱 위젯이 주기적으로 업데이트될때 처리할 코드를 구현하는 것이다. 

앱 위젯 클래스를 상속해서 onUpdate()를 다시 정의한다. 

여기선 텍스트뷰를 눌렀을때 실행할 인텐트를 지정하고 GPS 확인을 위해 새로 정의한 서비스를 시작한다. 텍스트뷰를 눌렀을때 내 위치를 이용해 지도를 보여줄 수 있는 가장 간단한 방법은 geo:로 시작하는 URI객체를 만들어 인텐트로 지도를 띄워주는 것이다. 이 객체는 PendingIntent객체로 만들어 설정하고 이 객체는 RemoteViews의 setOnClickget()을 호출해서 위젯을 업데이트하면 텍스트뷰의 클릭이벤트를 처리하기 위한 인텐트가 설정된다.

public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        super.onUpdate(context, appWidgetManager, appWidgetIds);

        Log.d("MyLocationProvider", "onUpdate() called : " + ycoord + ", " + xcoord);

        final int size = appWidgetIds.length;

        for (int i = 0; i < size; i++) {
            int appWidgetId = appWidgetIds[i];

            //String uri = "geo:"+ ycoord + "," + xcoord + "?z=10";
            //Intent intent = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse(uri));


            String uriBegin = "geo:" + ycoord + "," + xcoord;
            String query = ycoord + "," + xcoord + "(" + "내위치" + ")";
            String encodedQuery = Uri.encode(query);
            String uriString = uriBegin + "?q=" + encodedQuery + "&z=15";
            Uri uri = Uri.parse(uriString);

            Intent intent = new Intent(Intent.ACTION_VIEW, uri);


            PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);

            RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.mylocation);
            views.setOnClickPendingIntent(R.id.txtInfo, pendingIntent);

            appWidgetManager.updateAppWidget(appWidgetId, views);
        }

        context.startService(new Intent(context,GPSLocationService.class));
    }

public static class GPSLocationService extends Service 로 GPSLocationService로 클래스를 지정해서 서비스를 시작했다. (이 서비스에 대한 코드는 너무 길어 티스토리에 추가하지 않았다.) Manifest에서 receiver 태그에 새로 정의한 앱 위젯 제공자 클래스를 지정한다. 인텐트 필터의 액션정보로 APPWIDGET_UPDATE를 지정하고 metadata 태그로 앱 위젯 제공자 정보 담는 xml리소스를 지정한다. 서비스 태그엔 내 위치 확인을 위해 만들어둔 서비스를 태그한다. 

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

        <service android:name=".MyLocationProvider$GPSLocationService"></service>

앱 위젯으로 만든 텍스트나 이미지에 애니메이션을 적용하려면 스레드를 이용하면 되지만 이 위젯은 사용자가 항상 보도록 설정되어있어 전원 소모량이나 정보바뀌는 주기를 잘 고려해서 적용해야한다. 

이렇게 위젯을 추가했고 누르면 내 위치를 표시하는 지도를 볼 수 있다.

'안드로이드' 카테고리의 다른 글

시스템 서비스, 네트워크 활용하기  (1) 2021.05.11
푸시 알림 설정하기  (1) 2021.05.10
위치 지도에 표시하기  (1) 2021.05.08
위치기반 서비스 이용. 내 위치 알려주기.  (2) 2021.05.06
내용 제공자  (1) 2021.05.04

댓글