개발일지

Android Widget - 위젯 이벤트 본문

Android (안드로이드)/Widget

Android Widget - 위젯 이벤트

강태종 2022. 3. 9. 21:07

AppWidgetProvider

안드로이드에서 Widget에 관련된 생성, 삭제, 수정 등 이벤트를 제공하며 BroadcastReceiver를 통해 이벤트를 수신할 수 있습니다. 안드로이드에서 이러한 이벤트를 쉽게 처리하기 위해 AppWidgetProvider를 제공합니다.

 

실제로 내부 코드를 보면 BroadcastReceiver를 상속받고 onReceive에서 Action으로 분기하여 onEnabled, onDeleted등 함수를 호출합니다. 즉 개발자는 AppWidgetProvider를 상속받고 해당 함수를 오버로딩하면 됩니다.

public class AppWidgetProvider extends BroadcastReceiver {
    public AppWidgetProvider() {
    }

    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 (AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
            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)) {
            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_OPTIONS_CHANGED.equals(action)) {
            Bundle extras = intent.getExtras();
            if (extras != null && extras.containsKey(AppWidgetManager.EXTRA_APPWIDGET_ID)
                    && extras.containsKey(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS)) {
                int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID);
                Bundle widgetExtras = extras.getBundle(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS);
                this.onAppWidgetOptionsChanged(context, AppWidgetManager.getInstance(context),
                        appWidgetId, widgetExtras);
            }
        } else if (AppWidgetManager.ACTION_APPWIDGET_ENABLED.equals(action)) {
            this.onEnabled(context);
        } else if (AppWidgetManager.ACTION_APPWIDGET_DISABLED.equals(action)) {
            this.onDisabled(context);
        } else if (AppWidgetManager.ACTION_APPWIDGET_RESTORED.equals(action)) {
            Bundle extras = intent.getExtras();
            if (extras != null) {
                int[] oldIds = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_OLD_IDS);
                int[] newIds = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS);
                if (oldIds != null && oldIds.length > 0) {
                    this.onRestored(context, oldIds, newIds);
                    this.onUpdate(context, AppWidgetManager.getInstance(context), newIds);
                }
            }
        }
    }
    
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    }

    public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager,
            int appWidgetId, Bundle newOptions) {
    }

    public void onDeleted(Context context, int[] appWidgetIds) {
    }


    public void onEnabled(Context context) {
    }


    public void onDisabled(Context context) {
    }


    public void onRestored(Context context, int[] oldWidgetIds, int[] newWidgetIds) {
    }
}

onUpdate

updatePeriodMillis

에 맞춰서 호출됩니다. 최소 주기를 30분으로 설정할 수 있으며 그 이하로 설정한 경우 무시되어 30분마다 onUpdate를 호출합니다.(자주 업데이트가 필요한 경우 AlarmManager를 사용하면 됩니다.) 또한 위젯이 처음 생성될 때 호출되기 때문에 개발자는 onUpdate에 RemoteViews를 업데이트하는 로직을 작성하면 됩니다.

 

인스턴스별로 updatePeriodMillis를 따르는 것이 아닌. 모든 인스턴스가 같이 updatePeriodMillis에 맞춰 업데이트 됩니다. 예를 들어 2시간 간격으로 업데이트 되는 위젯인 경우 첫번째 위젯이 생성된 후 1시간 후에 두번째 위젯이 생성된 경우, 두번째 위젯은 1시간 후에 onUpdate를 호출합니다.

 

Configure Activity가 설정된 경우 Activity가 종료될 때 onUpdate를 따로 호출하지 않습니다.
-> AppWidgetManager.updateAppWidget을 호출하여 따로 업데이트합니다.

 

AppWidgetProvider는 BroadcastReceiver의 Lifecycle을 따릅니다. 즉 onUpdate의 작업이 무조건 성공될 보장이 없으며 오래 걸릴 경우 ANR이 발생할 수 있습니다.
-> Workmanager를 사용하여 이러한 이슈를 해결할 수 있습니다.
더보기

ACTION_APPWIDGET_UPDATE의 Action을 받을 때 호출되며, Widget아이디는 EXTRA_APPWIDGET_IDS를 통해 IntArray형식으로 제공됩니다.

        if (AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
            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);
                }
            }
        }

onAppWidgetOptionsChanged

위젯이 처음 생겨서 위치할 때와, 위젯의 크기가 변경될 때 호출됩니다. 주로 크기가 변경되어 위젯의 내용이 수정될 때 사용합니다. 아래와 같은 Key로 제공받는 Bundle로 부터 dp값을 얻을 수 있습니다.

  • AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH
  • AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT
  • AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH
  • AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT
  • AppWidgetManager.OPTION_APPWIDGET_SIZE
더보기

ACTION_APPWIDGET_OPTIONS_CHANGED의 Action을 받을 때 호출되며 EXTRA_APPWIDGET_ID를 통해 Int형식으로 Widget아이디를 제공받고, EXTRA_APPWIDGET_OPTIONS를 통해 Bundle을 제공받습니다.

        } else if (AppWidgetManager.ACTION_APPWIDGET_OPTIONS_CHANGED.equals(action)) {
            Bundle extras = intent.getExtras();
            if (extras != null && extras.containsKey(AppWidgetManager.EXTRA_APPWIDGET_ID)
                    && extras.containsKey(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS)) {
                int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID);
                Bundle widgetExtras = extras.getBundle(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS);
                this.onAppWidgetOptionsChanged(context, AppWidgetManager.getInstance(context),
                        appWidgetId, widgetExtras);
            }
        }

 

onDeleted

위젯이 삭제될 때마다 호출됩니다. 제공받는 widgetId로 작업을 처리할 수 있습니다.

더보기

ACTION_APPWIDGET_DELETE의 Action으로 호출되며 EXTRA_APPWIDGET_ID를 통해 Int형으로 widgetId를 제공받지만 IntArray를 만들어서 함수를 호출합니다.

        } else if (AppWidgetManager.ACTION_APPWIDGET_DELETED.equals(action)) {
            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 });
            }
        }

onEnabled, onDisabled

위젯이 활성화/비활성화될 때마다 호출됩니다. 위젯의 인스턴스가 처음으로 생길 때 활성화되고, 모든 인스턴스가 사라질 때 비활성화 됩니다.

더보기

ACTION_APPWIDGET_ENABLED, ACTION_APPWIDGET_DISABLED를 통해 실행됩니다.

        } else if (AppWidgetManager.ACTION_APPWIDGET_ENABLED.equals(action)) {
            this.onEnabled(context);
        } else if (AppWidgetManager.ACTION_APPWIDGET_DISABLED.equals(action)) {
            this.onDisabled(context);
        }

Git (예제 코드)

https://github.com/KangTaeJong98/TaeTae98/tree/main/Android/Widget

 

GitHub - KangTaeJong98/TaeTae98: Study Repository

Study Repository. Contribute to KangTaeJong98/TaeTae98 development by creating an account on GitHub.

github.com

 

 

 

 

 

 

 

 

'Android (안드로이드) > Widget' 카테고리의 다른 글

Android in A..Z - Widget (생성)  (0) 2021.12.01
Comments