Android2014. 1. 13. 17:09

google-play-services_lib 업데이트 후, 죽는 문제



가끔씩 Android SDK Manger 버튼 눌러보면, SDK 등등이 업데이트 되었다고 체크되어 있다. 경험상 프로젝트가 진행중일 때는 절대로 업데이트하지 말아야 하는데, 이유는... 잘 동작하던 앱이 "죽는다"
최근에도 이런 경험을 했는데, 다행히 일 없이 널널할 때여서 뭔 일인가 꼼꼼히 살펴봤다.

이번에 업데이트를 한 것은 GCM이나 Google Map v2를 위해 추가해야하는 구글플레이서비스 라이브러리(google-play-services_lib)였는데, 처음 본 에러메시지는 아래와 같다.

01-13 14:27:16.976: E/AndroidRuntime(7367): Caused by: java.lang.IllegalStateException: The meta-data tag in your app's AndroidManifest.xml does not have the right value.  Expected 4030500 but found 0.  You must have the following declaration within the <application> element:     <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />


관련해서 찾아보니, 필수 meta-tag가 추가되었단다.

간단하다. Google Map v2의 Key를 넣는 것 처럼 매니페스트에 아래 내용을 추가하면 이 문제는 해결된다.


<Application 
...
    <meta-data
        android:name="com.google.android.gms.version"
        android:value="@integer/google_play_services_version" />
...
</Application>


그런데, 비슷한 문제가 또 발생한다.

int iErrorCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);


여기서 에러코드 "2"를 뱉어낸다.


public static final int SERVICE_VERSION_UPDATE_REQUIRED The installed version of Google Play services is out of date. The calling activity should pass this error code to getErrorDialog(int, Activity, int) to get a localized error dialog that will resolve the error when shown. Constant Value: 2 (0x00000002) Details... 


버전이 낮아서 발생하는 문제란다. 
이때 출력된 로그를 보면, 자기는 4030500을 원했는데, 내꺼는 3266136이란다.

W/GooglePlayServicesUtil(4728): Google Play services out of date. Requires 4030500 but found 3266136 


4030500이란 숫자는 뭔가 찾아봤다.

[SDK]\extras\google\google_play_services\libproject\google-play-services_lib\res\values

폴더에 version.xml파일이 있는데, 열어보면 4030500이라는 버전이 적혀있다.

<?xml version="1.0" encoding="utf-8"?> 
<resources>
    <integer name="google_play_services_version">4030500</integer>
</resources>


3266136은 못찾겠다. 어디에 적혀있었을텐데, 버전을 관리하기 위에서 이번부터 리소스에 넣기로 (안드로이드 OS개발자가...) 결정했나보다. 


어쨌든, 그렇다면 해결책은? 두 달전에 이 이슈가 발생했을 때는 해결책이 없었다. 구글플레이서비스 앱은 아직 4030500을  지원하지 않는데, 라이브러리만 4030500으로 올려놓고 먼저 배포한 구글직원의 잘못이었다.

새로운 라이브러리를 삭제하고 다시 잘 동작하던 라이브러리로 원복해서 사용할 수 밖에 없었다.


이 문제를 접한건 2013년 11월 초였는데, 지난 주, 2014년 1월 9일에 구글 플레이 서비스가 업데이트 되었다는 내용이 안드로이드 공식 블로그에 올라왔다. 구글플레이스토어 앱의 버전을 확인하니 4.5.10이란다. 업데이트 되었다. (이전 버전은 4.4.21, 구글플레이스토어 앱은 별도 설치없이 나 몰래 자동업그레이드 된다.) 


다시, 최신 라이브러리를 꺼내서 적용했더니, 잘 동작한다. 해결됐다. 새로운 구글플레이스토어 앱 어딘가에 "4030500"이란 버전명이 적혀있나보다. 이러한 문제가 발생해도 공식적으로 아무런 조언도 해주지 않는 구글이 참 섭섭하지만 어쨌든 일은 해야하니까.. "프로젝트 진행중에는 왠만하면 ADT나 SDK 관련 업데이트를 하지말자!"



Posted by 데브로망스
Android2014. 1. 8. 16:11

프레그먼트의 디자인 철학(Design Philosophy)



태블릿과 같은 큰 화면에서 동적이면서 유연성있는 UI 디자인을 지원하기 위해 안드로이드 3.0(API Level 11)부터 프레그먼트를 지원한다. 태블릿은 스마트폰보다 화면 사이즈가 크기때문에 UI 요소를 통합하거나 교체할 수 있는 여유 공간이 있다. 프레그먼트는 뷰계층의 복잡한 변경을 관리하지 않고도 화면을 설계할 수 있게 해준다. 액티비티의 레이아웃을 프레그먼트 단위로 나눌 수 있게되면서 우리는 런타임시에도 액티비티의 외관을 변경할 수 있고 또한, 변경된 내용을 액티비티가 관리하는 백스택으로 보존할 수도 있게 되었다.


예를 들면, 뉴스 앱에서 왼쪽 프레그먼트에는 뉴스 목록을, 오른쪽에는 해당 기사 내용을 보여줄 수 있다. 자세히 설명하면 두 프레그먼트를 하나의 액티비티에서 나란히 보여주고 각각의 프레그먼트는 자신의 생명주기 콜백함수를 정의해서 사용자 입력 이벤트를 직접 처리할 수 있다. 그래서, 아래 그림과 같이 한 액티비티에서는 뉴스 목록을 보여주고 다른 액티비티에서 선택된 뉴스 기사를 보도록 구현하는 대신 사용자는 목록을 선택하고 같은 액티비티에서 바로 기사를 읽도록 구성할 수 있다.



프레그먼트로 정의된 두 개의 UI 모듈이 태블릿에서는 결합된 형태로, 스마트폰에서는 분리된 형태로 보여주는  예시

[이미지 출처 : http://developer.android.com/guide/components/fragments.html#Design]


앱이 태블릿에서 실행될 때는 액티비티A에 두 개의 프레그먼트를 넣을 수 있다. 반면에 스마트폰에서는 공간의 여유가 없기 때문에 액비티비A에는 뉴스목록을 위한 프레그먼트만 넣고 사용자가 항목을 선택했을 때 액티비티B를 띄우면서 그 안에 뉴스 기사를 위한 프레그먼트를 넣도록 구현한다. 결과적으로 앱은 다양한 결합방법을 통해 프레그먼트를 재사용해서 태블릿과 스마트폰을 동시에 지원할 수 있다.



[원문보기]


Posted by 데브로망스
Android2014. 1. 8. 14:16

프레그먼트(Fragments)란?



프레그먼트는 액티비티 내에서의 행위 또는 UI의 일부를 대체할 수 있다. 우리는 여러개의 프레그먼트를 결합해서 하나의 액티비티를 여러개의 판으로 나뉘어진 UI를 구성할 수 있다. 또한, 정의한 프레그먼트를 다른 액티비티에서 재사용할 수도 있다. 프레그먼트는 액티비티의 모듈화된 구역이라고 이해할 수 있다. 따라서 프레그먼트는 독립된 라이프 사이클을 갖고, 자신의 입력 이벤트를 수신하며 액티비티가 살아있는 중간에 추가되거나 삭제(다른 액티비티에서 재사용할 수 있는 일종의 서브 액티비티 같은 것)될 수 있다.


프레그먼트는 항상 액티비티에 속하게되고 생명주기는 바로 그 액티비티의 생명주기에 직접적으로 영향을 받게된다. 예를 들어, 액티비티가 멈출때(Paused) 그 안에 속한 모든 프레그먼트는 멈추게 되고, 닫힐때(Destroyed)도 마찬가지다. 하지만, 액티비티가 동작할 때(Resumed 상태일 때)는 각각의 프레그먼트를 독립적으로 조작(추가/삭제)할 수 있다. 또한 프레그먼트 조작을 수행할 때 액티비티에서 관리하는 백스택(back stack)에 추가할 수도 있다. (액티비티에 속한 각각의 백스택 항목들은 프레그먼트가 조작된 기록이다.) 백스택은 백버튼을 눌렀을 때, 뒤로가기와 같은 프레그먼트 조작을 가능하게 해준다.


프레그먼트를 액티비티 레이아웃의 한 부분으로 추가하면, 이 프레그먼트는 액티비티의 뷰계층에 속해있는 ViewGroup에 존재하게 되고, 뷰 레이아웃을 스스로 정의한다. 프레그먼트를 액티비티 레이아웃에 포함시키는 방법은 두 가지가 있는데, 하나는 액티비티 레이아웃 파일에 프레그먼트를 선언(<fragment>태그)하는 방법이고, 다른 하나는 ViewGroup 객체에 Java Code로 추가하는 것이다. 하지만, 프레그먼트라고 해서 반드시 액티비티 레이아웃의 한 부분이 될 필요는 없다. UI없이 액티비티를 위한 숨은 작업을 하도록 구현할 수 있다.



[원문보기]



Posted by 데브로망스