2012년 2월 26일 일요일

AppWidget Update 주기에 대하여

AppWidget의 update 주기에 대해 말씀드리겠습니다.

update 주기를 설정하는 방법은 여러가지가 있겠으나, 대략 다음중 하나를 선택하실 겁니다.

1. appwidget-provider XML 에서 updatePeriodMillis="0"
2. appwidget-provider XML 에서 updatePeriodMillis="원하는 시간만큼"
3. 아니면 프로그램 내에서 직접 AlarmManager를 통해

1. updatePeriodMillis="0"의 의미
- 이렇게 setting하면 3번과 같은 의미를 같습니다. onUpdate()는 프로그램에서 알아서 해야 하다는 말 입니다.
- 프로그램내에서 AppWidget 실행시 한번만 onUpdate()를 call 합니다.
- 이 후에 한번도 onUpdate()를 call하지 않으면, 상당한 시간이 흐른 후에 AppWidget에 setting해 놓은 기능들은, 특히 pending intent는 사라지게 되며 AppWidget은 기능을 제대로 작동되지 않습니다. 꼭 명심하세요.

2. updatePeriodMillis="원하는 시간만큼"
- 원하는 시간에 System에서 onUpdate() call 하게 되지만, 그 주기는 확신할 수는 없습니다.
- 최소시간은 30분입니다. 단위가 millisecond이니 30분 x 60초 x 1000=1800000 가 되겠습니다.
- 아무리 짧게 주어도 효과는 없습니다.

3. AlarmManager를 통해
- 2번 처럼 원하는 시간을 정할 수는 있을겁니다.
- 너무 짧은 시간을 주게 되면, 아마도 Failed Binder Transaction!!! 을 만나게 됩니다.
- AppWidget은 참 편하고 강력하며 iphone과 차별화된 기능이지만, 제가 보기에는 상당히 무겁습니다.
- 짧은 시간에 화면을 update하는 것은 금물입니다.

2012년 2월 19일 일요일

AppWidget 구현시 가장 중요한 것은?

AppWidget 구현 시 XXXConfigure, XXXProvider, Service 정말 많은 것을 구현해야 합니다.
그중에서도 Widget의 구성요소를 사용자로하여금 설정할 수 있게 해 주는 것이 XXXConfigure 인데요..

XXXConfigure를 만드는 순간 우리는 유령 Widget에 시달려야 합니다.

XXXConfigure는 Activity형태라는 것 다 아실테고..
User가 Activity를 빠져나가는 방법은 여러가지가 있을 수 있습니다.

1. home 버튼
2. back 버튼
3. 취소버튼 - 친절하게 XXXConfigure 화면에서 취소버튼을 만들은 경우
4. 그외 상상에 맞기겠습니다.

메뉴얼이나 developer site에 가서 보면

XXXConfigure내에서 Widget 만들기를 취소하는 것은 XXXConfigure에 setResult()에 RESULT_CANCELED를 setting하는 것으로 되어 있으나...아무리 이렇게 해봐도 유령은 계속 계속 생기게 됩니다.

현재 얼마나 많은 appWidget이 host에 등록 되어 있는지 대한 코드는 다음과 같습니다.

ComponentName compName = new ComponentName(this, XXXProvider.class);
int appWidgetIds[] = AppWidgetManager.getInstance(this).getAppWidgetIds(compName);
AppWidgetHost host = new AppWidgetHost(this, 0);

for(int i = 0; i < appWidgetIds.length; i++){
     Log.d(TAG, "[" + i + "] " + appWidgetIds[i]);
}

이코드를 XXXConfigure onCreate()에 넣어 보시면 현재 얼마나 많은 위젯들이 있는지 알 수 있겠죠.

유령은 XXXConfigure를 실행하고 setResult(RESULT_OK, intent); 가 호출되지 않은 상태인데요, 화면에 위젯이 표시되지 않고 host에 id로만 존재하는 놈을 말합니다.

그럼 어떻게 지울 수 있을까요....?

항상, onPause() 아니면 onDestroy()에서 (onPause()가 나을 것 같아요..) 유령을 찾아 지워야 합니다.

지우는 코드는 위에서 언급한 widgetId를 보는 코드와 동일합니다.

ComponentName compName = new ComponentName(this, XXXProvider.class);
int appWidgetIds[] =AppWidgetManager.getInstance(this).getAppWidgetIds(compName);
AppWidgetHost host = new AppWidgetHost(this, 0);

for(int i = 0; i < appWidgetIds.length; i++){
        Log.d(TAG, "[" + i + "] " + appWidgetIds[i]);
        if(appWidgetIds[i]가 유령입니까?){
              host.deleteAppWidgetId(appWidgetIds[i]);
        }else{
              // do nothing..
        }
}

빨간색으로 칠한 부분을 생각해 보겠습니다.

화면에 widget이 생성되어 있는지 아닌지 알아내는 방법을 못찾았습니다.(좀 알려주세요.)

그걸 안다면 이런짓을 하지는 않을 겁니다. 그러나 방법을 모르기에 제대로 생성된(즉, User가 XXXConfigure화면에서 OK버튼을 눌렀을때) widget과 아닌것을 구분하는 구분자 정도는 widget 생성시 만들어서 어디에 저장해 놓아야 합니다. 가장 편리하고 쉬운 것은 SharedPreferences를 이용하는 것입니다.

즉, 제대로된 생성된 appWidget의 경우, SharedPreferences 에 제대로 된놈인가를 표시하는 것이죠....

appWidgetIds[i] 가 유령인지 아닌지 판단시 SharedPreferences에 등록이 되어 있는지를 체크 하는 것입니다.

유령체크코드는 application마다 다르기에 여기서는 언급은 하지 않지만요...

조금은 지저분하고 googling을 해봐도 딱히 유령을 가장 깔끔하게 지우는 방법을 찾지는 못했습니다.

암튼 이만.... 댓글 달아 주시면 답변 드리겠습니다.