D-day 앱을 한번 만들어보다가 헷갈리는 부분이 있었는데 해결하게 되어 글을 남겨본다.

만들고자 했던 앱의 주요 기능/조건은 다음과 같다.

 - 사용자가 특정 날짜를 선택하면 오늘과의 일 수 차이를 계산하여 위젯에 띄워준다

 - 액티비티에서 값(선택한 날짜)을 변경하면 위젯에 즉시 반영되어야 한다

 - 하루가 지나거나 시간을 수정하면 자동으로 D-day가 바뀌어야한다

 

위젯에 띄워주는 것은 몇 번의 검색으로도 쉽게 이해할 수 있었고 만들기도 쉬웠지만

액티비티에서 값을 변경했을 시 즉시 반영되는 부분은 잘 되지 않았다.

우선 위젯의 생명주기를 이해해야한다. 오버라이드 된 함수들에 로그만 띄워도 어느 정도 이해할 수 있다.

onEnabled : 위젯이 처음 생성될 때 호출된다.

onDisabled : 위젯이 화면에서 삭제될 때 호출된다.

onUpdate : 위젯 xml 파일 내의 android:updatePeriodMillis 값에 따라 주기적으로 호출된다. 위젯을 갱신하는 함수를 여기 넣으면 된다.(주기는 최소 30분으로 제한)

onReceive : 브로드캐스트가 왔을 때 호출된다.

 

액티비티에서 날짜 값을 변경하거나 하루가 지나면 브로드캐스트를 날리게 만들었다.

아래는 액티비티에서 위젯으로 브로드캐스트 날리는 예시이다

Intent intent = new Intent(MainActivity.this, MainAppWidget.class);
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
MainActivity.this.sendBroadcast(intent);

 

액티비티에서 날린 브로드캐스트를 받으려면 브로드캐스트 리시버 역할을 하는 onReceive에 값을 변경해주는 코드를 넣어야 했다.

그런데 onReceive 에서는 위젯을 갱신하지 않는다. 로그로 확인해보니 값이 정상적으로 변경이 되어도 위젯 상에는 반영이 안되었다.

30분 주기로 실행되는 onUpdate가 한번 실행되고 나서야 값이 변경이 되었다.

 

해결 방법은 이렇다. onReceive 에서 브로드캐스트를 받으면, 값 계산을 해 준 다음(이 경우에는 오늘 날짜에서 선택한 날짜를 뺀다)

onReceive 내에서 onUpdate 를 호출해주면 되는 것이다.

onReceive 의 인자와 onUpdate의 인자는 다르기 때문에 onReceive 내에서 다음과 같이 초기화가 필요하다.

아래 코드는 onReceive 내에서 브로드캐스트를 받고 값을 모두 수정한 다음에 써주는 게 좋다.

AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
ComponentName testWidget = new ComponentName(context.getPackageName(), [위젯클래스이름].class.getName());

int[] widgetIds = appWidgetManager.getAppWidgetIds(testWidget);

if(action.equals(AppWidgetManager.ACTION_APPWIDGET_UPDATE)){
if(widgetIds != null && widgetIds.length >0) {
this.onUpdate(context, AppWidgetManager.getInstance(context), widgetIds);
}
}

 

위 부분을 써주지 않으면 앞서 말한 것처럼 값은 바뀌나 위젯에 즉시 적용이 되지 않는다.

onUpdate의 주기를 30분 미만으로 조정해서 하는 방법도 있다고 들었지만 그렇게 자주 업데이트할 필요가 없다면 위 방법이 적절할 것이다.

 

 

  

안드로이드에서 DatePicker를 다이얼로그 없이 사용하려다 문제가 생겨 해결하게 되었다.

DatePicker는 크게 두 가지로 나뉜다고 생각하는데, 그 분기점이 5.0 이다.

5.0 이전에는 위아래에 삼각형 버튼이 있는 스피너를 통해 년/월/일 을 조정했는데, 이후부터는 달력에서 날짜를 직접 선택하는 방법으로 바뀌었다.

 

내가 가진 문제는 DatePicker 를 다이얼로그 없이 사용했을 때 5.0 이상의 버전에서 날짜 선택에 대한 이벤트가 일어나지 않는다는 것이었다.

찾아보니 머티리얼 테마가 적용되는 롤리팝 버전부터는 OnDateChangedListener 함수가 제대로 적용되지 않는다고 한다.

하지만 방법은 있다. 롤리팝 이후에 나온 버전에서도 스피너를 이용하여 날짜를 선택하게 하는 것이다.

기존의 자바 코드는 그대로 두고 Datepicker에 대해 설명된 xml 레이아웃에 다음과 같은 옵션 하나를 써주면 된다.

android:datePickerMode="spinner"

그러면 다이얼로그를 쓰지 않고 기존의 코드를 사용할 수 있다. 대신 깔끔한(?) 머티리얼 UI는 사용할 수 없겠지만..

 

원본 글 : http://stackoverflow.com/questions/31609777/ondatechanged-is-not-called-in-date-picker-android-lollipop

 

 

 

  

앱을 하나 만들다가 문법적인 오류가 없음에도 불구하고 빌드 에러가 난 적이 있었다.

아마 Projekt structure 의 Dependencies 에서 라이브러리를 이것저것 넣고 빼다 보니 그랬던 것 같다.

대략적인 에러 코드는

Error:Execution failed for task ':app:dexDebug'    ...    java.exe finished with non-zero exit value 2 였다.

처음에 jar 파일을 직접 넣고 File Dependency 에서 추가를 했는데, 나중에는 Library Dependency에서 다시 추가해서 그런 것 같다.

같은 버전의 jar 파일이 이름이 다르게 중복되어 들어갔던 것이다.

 

해결방법은 이렇다.

C:\Users\사용자\AndroidStudioProjects\앱 이름\app\build\intermediates\pre-dexed\debug

에 들어가보면 중복된 라이브러리가 들어있을 것이다.

중복된 라이브러리들만(!) 지운 다음 다시 Project Structure 에 들어가서 라이브러리를 import 해주면 된다.

 

 

  
 «이전 1 2 3 4 5 6  다음»