안드로이드 App 위젯을 만들어 보자

|

App을 만드셨다면 이젠 바탕화면에 위젯을 만들어 보는 방법을 알아보도록 하겠습니다.

일단 위젯을 만들기 전에 필요한 파일들이 무엇인지 알아보겠습니다.
* ExrateWidgetProvider.java - 위젯 메인 파일
* UpdateService.java - 주기적인 실행을 위한 서비스 파일
* exratewidget_layout.xml - 위젯 레이아웃 파일
* exrate_widget.xml - 위젯 설정 파일

* 그럼 각각의 파일내부를 들쳐 보도록 하겠습니다. 간단하게 xml 파일부터 설명드립니다.

> AndroidManifest.xml
<!-- 서비스 파일 등록 -->
<service android:name=".UpdateService" android:label="UpdateService">
  <intent-filter>
    <action android:name="android.intent.action.MAIN" />
  </intent-filter>
</service>

<!-- 리시버 등록 -->
<receiver android:name=".ExrateWidgetProvider" android:label="@string/app_name">
  <intent-filter>
    <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
  </intent-filter>
  <meta-data android:name="android.appwidget.provider" android:resource="@xml/exrate_widget" />
</receiver>


> exrate_widget.xml - 위젯 설정 파일
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="146dip"
    android:minHeight="72dip"
    android:updatePeriodMillis="1800000"
    android:initialLayout="@layout/exratewidget_layout"   
/> 


> exratewidget_layout.xml - 위젯 레이아웃 파일
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent" android:layout_height="fill_parent"
    android:orientation="vertical" android:background="@drawable/w_back01"
    android:padding="5px" android:gravity="center" android:id="@+id/ID_LAYOUT">

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:orientation="vertical" android:id="@+id/ID_LAYOUT1">

        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="wrap_content" android:layout_height="wrap_content"
            android:orientation="horizontal" android:gravity="center"
            android:layout_marginTop="5px" android:layout_marginLeft="0px">

            <ImageView android:id="@+id/ID_IMG1" android:src="@drawable/n_kr"
                android:adjustViewBounds="true" android:layout_width="16dip"
                android:layout_height="10dip" android:visibility="visible"
                android:gravity="center_vertical|center_horizontal"
                android:layout_marginBottom="5px" android:layout_marginLeft="5px"
                android:layout_marginTop="5px" />

            <TextView android:id="@+id/ID_SIGN1" android:text="USD"
                android:textSize="5pt" android:textStyle="bold"
                android:layout_height="wrap_content" android:gravity="center_vertical|center_horizontal"
                android:visibility="visible" android:layout_width="25dip" />

            <TextView android:id="@+id/ID_BUY1" android:layout_width="47dip"
                android:layout_height="wrap_content" android:visibility="visible"
                android:text="0000.00" android:gravity="center_vertical|center_horizontal"
                android:textSize="5pt" />

            <TextView android:id="@+id/ID_SELL1" android:layout_width="47dip"
                android:layout_height="wrap_content" android:visibility="visible"
                android:text="0000.00" android:gravity="center_vertical|center_horizontal"
                android:textSize="5pt" />

        </LinearLayout>

    </LinearLayout>

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent" android:layout_height="wrap_content"
        android:orientation="horizontal" android:id="@+id/ID_LAYOUT2"
        android:layout_marginTop="0px" android:layout_marginRight="10px">

        <TextView android:layout_width="wrap_content"
            android:layout_height="wrap_content" android:visibility="visible"
            android:text="ANDROES" android:gravity="center_vertical"
            android:layout_marginLeft="20px" android:textSize="5pt"
            android:textStyle="bold" />

        <TextView android:layout_width="fill_parent" android:text="00-00 00:00"
            android:layout_height="wrap_content" android:textSize="5pt"
            android:gravity="right" android:id="@+id/ID_DATE" android:textStyle="bold" />

    </LinearLayout>
</LinearLayout>


> UpdateService.java - 주기적인 실행을 위한 서비스 파일
package com.androes.exrate;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;

import android.app.AlarmManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;

public class UpdateService extends Service {
    private static int[] sAppWidgetIds;
    private static final String TAG = "Androes UpdateService";

    private DateFormat format = SimpleDateFormat.getTimeInstance(
            SimpleDateFormat.MEDIUM, Locale.getDefault());
    private static Context context;

    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);

        SimpleDateFormat formatStr = new SimpleDateFormat("HHmm", Locale.KOREA);
        Integer onlyHour = Integer.parseInt(formatStr.format(new Date()));
        Logger.i(TAG, "Androes Onstart: " + onlyHour + " ... " + format.format(new Date()));
        ExrateWidgetProvider.xmlViewParser(context);    
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    public static void regAppWidgetIds(Context _context, int[] widgetIds) {
        context = _context;
        sAppWidgetIds = widgetIds;
    }
}

* ExrateWidgetProvider.java - 위젯 메인 파일
package com.androes.exrate;

import java.io.InputStream;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;

import com.androes.exrate.Main.XmlData;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.RemoteViews;
import android.widget.TextView;
import android.widget.Toast;

public class ExrateWidgetProvider extends AppWidgetProvider {
    static final String TAG = "ANDROES";
    private static AppWidgetManager appWidgetManager;
    Intent intent;
    PendingIntent pendingIntent;

    public void onReceive(Context context, Intent intent) {
        // Protect against rogue update broadcasts (not really a security issue,
        // just filter bad broacasts out so subclasses are less likely to
        // crash).
        String action = intent.getAction();
        if (action.equals("CLICK_RELOAD")) {
            Logger.d("Androes", "ACTION_CLICK_RELOAD");
            Toast.makeText(context, "Data Collecting", Toast.LENGTH_SHORT).show();
            xmlViewParser(context);
        } else if (AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
            Logger.d("Androes", "ACTION_APPWIDGET_UPDATE");
            Bundle extras = intent.getExtras();
            if (extras != null) {
                int[] appWidgetIds = extras
                        .getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS);
                if (appWidgetIds != null && appWidgetIds.length > 0) {
                    this.onUpdate(context, AppWidgetManager
                            .getInstance(context), appWidgetIds);
                }
            }
        } else if (AppWidgetManager.ACTION_APPWIDGET_DELETED.equals(action)) {
            Logger.d("Androes", "ACTION_APPWIDGET_DELETED");

            final int appWidgetId = intent.getExtras().getInt(
                    AppWidgetManager.EXTRA_APPWIDGET_ID,
                    AppWidgetManager.INVALID_APPWIDGET_ID);
            if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
                this.onDeleted(context, new int[] { appWidgetId });
            }
            /*
             * Bundle extras = intent.getExtras(); if (extras != null &&
             * extras.containsKey(AppWidgetManager.EXTRA_APPWIDGET_ID)) { final
             * int appWidgetId = extras
             * .getInt(AppWidgetManager.EXTRA_APPWIDGET_ID);
             * this.onDeleted(context, new int[] { appWidgetId }); }
             */
        } else if (AppWidgetManager.ACTION_APPWIDGET_ENABLED.equals(action)) {
            Logger.d(TAG, "ACTION_APPWIDGET_ENABLED");

            this.onEnabled(context);
        } else if (AppWidgetManager.ACTION_APPWIDGET_DISABLED.equals(action)) {
            Logger.d(TAG, "ACTION_APPWIDGET_DISABLED");

            this.onDisabled(context);
        } else {
            super.onReceive(context, intent);
        }
    }

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

        Logger.d(TAG, "onUpdate");
        if (appWidgetIds == null) {
            appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(
                    context, ExrateWidgetProvider.class));
        }

        if (appWidgetIds == null) {
            Logger.d(TAG, "onUpdate appwidgetIds is null");
            return;
        }
        this.appWidgetManager = appWidgetManager;
        UpdateService.regAppWidgetIds(context, appWidgetIds);
        
        // updatePeriodMillis 옵션 미사용시 아래 스크립트 이용
        // StartUpdate(context, appWidgetIds);

        // updatePeriodMillis 옵션 사용시
        xmlViewParser(context);
    }

    /*
     * public static void buildUpdate(Context context, String time_str, int
     * appWidgetId) { Logger.e(TAG,time_str); RemoteViews views= new
     * RemoteViews(context.getPackageName(), R.layout.time_layout);
     * views.setTextViewText(R.id.now_time, (CharSequence)time_str);
     * appWidgetManager.updateAppWidget(appWidgetId, views); }
     */
    public static void StartUpdate(Context context, int[] appWidgetsIds) {
        Intent updateIntent = new Intent(context, UpdateService.class);
        PendingIntent pendingIntent = PendingIntent.getService(context, 0,
                updateIntent, 0);
        if (pendingIntent == null)
            Logger.e(TAG, "pendingIntent is null");
        else
            Logger.e(TAG, "pendingIntent is not null");

        Calendar cal = Calendar.getInstance();
        // Schedule alarm, and force the device awake for this update
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        
        int delay = 10000; // 10초: 10000 / 30분: 1800000
        alarmManager.setRepeating(AlarmManager.RTC, cal.getTimeInMillis(), delay, pendingIntent);
    }

    public static void xmlViewParser(Context context) {
        RemoteViews remoteViews;
        ComponentName watchWidget;

        // TODO Auto-generated method stub
        remoteViews = new RemoteViews(context.getPackageName(),
                R.layout.exratewidget_layout);
        ....

        Intent intent = new Intent(context, ExrateWidgetProvider.class);
        intent.setAction("CLICK_RELOAD");
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0,intent, 0);
        remoteViews.setOnClickPendingIntent(R.id.ID_LAYOUT, pendingIntent);

        watchWidget = new ComponentName(context, ExrateWidgetProvider.class);
        appWidgetManager.updateAppWidget(watchWidget, remoteViews);
    }
}


updatePeriodMillis 옵션 사용하지 않고 수동으로 업데이트를 이용하고자 할 경우에는

AndroidManifest.xml내 service 항목과 ExrateWidgetProvider.java내 StartUpdate(), UpdateService.java 는 필요없습니다.

'Android 개발 > Android SDK' 카테고리의 다른 글

Handler와 AlarmManager를 통한 Timer 작업 처리  (0) 2011.05.12
Bitmap OutofMemoryError  (0) 2011.05.12
Screen On / Off 핸들링  (0) 2011.05.02
Application, Activity  (0) 2011.04.28
Native Content Providers List  (0) 2011.04.19
And