구글 I/O Extended Seoul에서 발표한 Android N

구글 IO때 예상된 일정에는 차질 없다. 빠른 시일내에 N테스트를 해야한다.


스크린 줌 설정

런타임시 화면 밀도가 바뀔 수 있으니 테스트해봐야 한다. Bitmap을 캐쉬해두는 경우 문제가 될수 있다. 고사양 기기가 sw320dp를 가질 수도 있으니 염두해둔다.


멀티스크린

가로/세로 모드를 반드시 구현해라.
멀티스크린 모드로 인해 화면이 작아 질수 있으니 최소 220dp(w/h)가 지원되도록 개발해야한다.
사용자가 화면크기를 늘리거나 줄일떄 기본으로 Activity가 재 생성되며, 필요에 따라 onConfigurationCahaged() 이벤트로 처리 할 수 있다.
attr#resizedableActivity값은 기본적으로 TRUE이며 필요에 따라 속성을 변경 하면된다. 단, Root Activity의 FLAG의 속성에 따라 작동 유무가 판단된다.

targetSdk 24를 쓰면서 멀티스트린 지원하지 않게 하는 팁!
* targetSdk = 24
* resizedableActivity = false
* launchMode = singleInstance | singleTask

앱간의 Drag and Drop API도 있으니 필요시에 사용가능하다.


배터리 최적화 모드(Doze)

Doze on the Go (light Doze모드) 새기능 추가
움직임이 있더라도 사용자가 폰을 일정시간 사용하지 않으면 doze모드 진입
네트워크 작업 중단, 잡스케줄러 지연
이미 Doze모드에 최적화된 앱은 별도로 신경 쓸 필요는 없다.

테스트

#adb shell dumpsys deviceidle step light

Doze모드 whitelist에 추가 하는 API도 있는데 잘못 하용하면 앱이 내려갈 수 있다.

참고: 안드로이드 앱 배터리 최적화 무시방법


메모리 최적화 모드

Broadcast 이벤트를 처리시 많은 앱에서 동시에 처리 하는경우 문제가 된다. 동시에 수많은 앱에서 이벤트를 처리 하기때문에 성능적으로 문제가 되며, 특히 사용하고 있지 않는 앱도 이벤트를 받는등 불필요한 작업이 있을 수 있다.

런타임시에 등록한 경우는 작동되나 안드로이드 메니페스트에서 선언한 Broadcast의 경우 작동하지 않는다.
CONNECTIVITY_CHANGE, NEW_PICTURE, NEW_VIDEO는 메니페스트에서 선언한 Broadcast의 경우 N부터 작동하지 않는다.

테스트

#adb shell cmd appops set <package-name> RUN_IN_BACKGROUND igenore







빠르고 유연한 ContraintLayout

ContraintLayout?

ContraintLayout은 2016 구글 I/O를 통해 발표된 안드로이드의 새로운 레이아웃이다. 안드로이드 스튜디오(2.2 Preview2 부터)에 내장된 새로운 레이아웃 에디터(Blue Print)와 연동을 통해 이전의 레이아웃보다 쉽게 구성할 수 있다. 뷰 계층의 깊이와 복잡성을 해결하기 위해 ContraintLayout이 만들어졌으며, 앱의 UI렌더링 속도를 높일 수 있을 뿐만아니라 다양한 기기의 해상도에 최적화된 UI를 쉽게 개발 할 수도 있다. 안드로이드 서포트 라이브러리를 통해 사용가능하며 API 레벨 9부터 사용가능하다.

build.gradle에서 해당 라이브러리를 추가한다.

compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha2'

ContraintLayout 속성

  • layout_constraintTop_toTopOf
  • layout_constraintTop_toBottomOf
  • layout_constraintBottom_toTopOf
  • layout_constraintBottom_toBottomOf
  • layout_constraintLeft_toTopOf
  • layout_constraintLeft_toBottomOf
  • layout_constraintLeft_toLeftOf
  • layout_constraintLeft_toRightOf
  • layout_constraintRight_toTopOf
  • layout_constraintRight_toBottomOf
  • layout_constraintRight_toLeftOf
  • layout_constraintRight_toRightOf
  • layout_constraintCenterX_toCenterX
  • layout_constraintCenterY_toCenterY
  • layout_constraintBaseline_toBaselineOf

속성을 보면 알겠지만 많은 속성들로 인해 복잡하고 뷰들 간의 관계에 대한 속성들이 대부분이다. 자식뷰들관의 관계를 연결해주는 것을 보면 RelactiveLayout와 비슷해보이지만 ContraintLayout은 자식들과 부모관의 관계에 대한 정렬및 배치 방식과 좌표가 아닌 비율을 통해 위치가 지정되는등 다양한 기능을 가졌다.

 

레이아웃 에디터

개발자라면 그동안 레이아웃을 XML편집기를 이용하여 텍스트로 작성했을 것이다. 하지만 ContraintLayout은 무수히 많은 속성과 타겟 뷰의 ID를 값으로 주는 만큼 레이아웃구조를 텍스트로 작성하거나 또는 읽을때 예전보다는 확연히 힘들것이다. 이렇게 복잡한 레이아웃을 텍스트가 아닌 새롭게 선보인 디자인 툴(Blue Print)을 이용하면 훨씬 쉽고 간단하게 작성할 수 있다.

레이아웃 에디터는 UI설계를 하는 Design과 뷰들관의 관계를 보여주는 BluePrint 화면 2개가 나타난다. 이 2개 화면을 동시에 보거나 따로보는 방법은 레이아웃 에디터의 상단 아이콘을 이용하면 전환할 수 있다.

be44fb8e685150a5565f19c94e36e954
Design 표시 아이콘: 한번 누르면 디자인 화면으로 전환 되며 또한번 누르면 BluePrint 화면을 동시에 2개가 나타난다.

a72c79e2a3bf45f38413fec30f3dac36
BluePrint 표시 아이콘: 한번 누르면 BluePrint화면으로 전환되며 또한번 누르면 디자인 화면과 동시에 2개가 나타난다.

 

레이아웃 편집시 쓰이는 아이콘

b25f376c52508c900dbab5a8bf5d68bf
BluePrint화면의 뷰들간의 관계에 대한 정보를 숨기고 보일 수 있다.

f6ea28b2afd03030cfeed10d9b3f165a
새로운 뷰를 드래그 하는 경우 다른뷰들간의 관계를 자동으로 연결할 수 있다.

3fd3b60139267dc5bd0e2abce72f6f30
관계를 정보를 모두 삭제 한다.

4d928284744c25094798de88e6cce11d
자동으로 관계에 대한 정보를 연결한다.

7c2b5cfb7453a9614c2e5507998eff27
마진값의 단위를 선택한다. 0, 8, 16dp로 전환이 가능하다.

 

레이아웃 내에서 쓰이는 툴


하나의 뷰를 나타내며 가로/세로 크기와 다른뷰와의 관계에 대해 화살표로 설정할 수 있는데 자세히 알아보자.

99a8ebe4d5ada56e4abacb2dfedc9d50
뷰 크기 변경 컨트롤: 각모서리 가장자리에 있는 네모 모양을 통해 뷰의 크기를 늘리고 줄일 수 있다.

924dedda9eb89c0ab8f6a268c4558e13
관계 설정 컨트롤: 둥글게 생긴 부분으로 다른 뷰들관의 관계를 지정할 수 있다. 가로축의 컨트롤은 다른뷰의 가로축에만 연결되며, 세로축은 다른뷰의 세로축에만 연결된다. 이미 관계가 지정되어 있을때 클릭하면 해제된다.

a6b25ad94ce53ddfedbf2d689a506b78
베이스 라인 컨트롤: 뷰의 기본 라인을 맞춘다. 베이스 라인은 뷰내의 실제 컨텐트가 배치해있는 위치이다. 해당 컨트롤을 선택하기위해서는 커서를 몇초간 위치해있어야 한다.

 

ContraintLayout에서 뷰크기 지정

뷰의 크기는 우리가 알고 있듯이 고정된크기, 뷰의 컨텐츠에 맞게 지정되는 방식, 부모크기를 따라가는 방식이 있다. 이를 UI적으로 표현하여 좀거 쉽게 설정가능하다.

e8124ddde04b2aa76e42f79582123218

7300702340c7018202fbdcf57af5b525
고정된크기: 뷰의 사이즈가 고정되어 있다.

709b28b53490f5fb5f6dcdc5380a6fb3
부모 컨텐츠 크기: MATCH_PARENT방식으로 작동한다.

af2e72fd3b0d4188c61e06da211f9835
뷰 컨텐츠 크기: 뷰의 크기에 따라 크기가 설정된다.

edcfce9f89f19fb900de367212f55c3a
수평및 수직 정렬: 부모 뷰와 자식뷰가 연결되어 있는 경우 정렬을 퍼센테이지로 설정할 수 있다. LinearLayout의 weight와 비슷하다고 생각하면 쉽다.

팁!

처음 ContraintLayout을 접해보면 생각보다 힘든 작업이 될가능성이 높다. 이것저것 버튼을 눌러서 레이아웃을 맞추기에 생각보다 번거롭기 때문이다. 그래서 한가지 팁을 소개해보겠다. 먼저 뷰들간의 관계를 연결하지 말고 배치만으로 작업을 한다. 연결 되어 있다면 모두 끊은 상태에서 배치작업을 한뒤 자동 관계아이콘을 클릭하여 연결을 자동으로 구성 후 보정작업을 하거나 간단한 경우 직접 연결해준다.

 

ContraintLayout은 알파단계로 약간의 버그가존재하며 디자인툴이 생각보다 빨리 움직이지 않고 한번씩 다운되는등의 문제점이 발생된다. 하지만 기존의 너무 깊은 레이아웃을 구조로 앱의 성능에 문제가 생긴점을 해결해줄 속 시원한 레이아웃이 될것 같다. 그리고 BluePrint로 인해 디자이너도 툴을 쉽게 익히고 사용하는데 무리가 없을것 같다. 기존의 계층구조가 복잡한 레이아웃이 있다면 조금씩 바꿔나가는 것에 추천한다.

 








jCenter로 안드로이드 라이브러리 간단하게 배포하기

안드로이드 스튜디오로 오면서 Gradle로 인해 외부라이브러리 사용이 훨씬 편해졌다. 예전에는 JAR파일이나 라이브러리 프로젝트를 직접 다운받아 프로젝트에 Import해서 라이브러리를 사용했다. 안드로이드 스튜디오의 Gradle파일에서 Dependencies에서 라이브러리명만 작성하면 연결되어 있는 저장소에서 파일을 받아오게 된다. Maven Repository중 가장쉽고 간단한 jCenter가 있으며 최근 안드로이드 스튜디오에서 새로운 프로젝트를 생성하면 기본 저장소로 설정되어 있기도하다.

 

jCenter에 라이브러리 배포하기

1) jCenter를 운영하는 bintray.com 사이트에 가입한다.

2) 가입 후 다양한 Repository가 있는데 우리는 Maven을 사용할 것이다.

3) Maven에서 Add New Package 버튼을 눌러 새로운 패키지 만들어두어도 되나, 아래에서 업로드시 패키지가 없다면 새롭게 생성해주기 때문에 만들지 않아도 된다. 그리고 Import from Github버튼을 눌러 Github에서도 가져올 수 있다. 단, 정보만 가져온다.

 

4) 이제 사이트에서 설정하는 것은 모두 끝났으며, 안드로이스 스튜디오의 라이브러리 프로젝트에서 novoda:bintray-release를 이용하여 빌드후 bintray에 바로 배포하는 라이브러리를 사용한다.

 

5) 프로젝트의 build.gradle에 아래와 같이 novoda:bintray-release라이브러리를 추가하다. 이것을 활용하여 빌드된 파일들을 bintray로 업로드한다.

buildscript{
   repositories{
      jcenter()
   }

   dependencies{
      classpath 'com.android.tools.build:gradle:2.1.0'
      classpath 'com.novoda:bintray-release:0.3.4'
   }
}

 

6) 라이브러리의 모듈에 있는 build.gradle에 업로드할 사용자 정보를 작성한다. 참고로 artifactId는 소문자로 작성하고 단어사이에는 하이픈(-)을 넣어 컨벤션을 지키도록하자.

apply plugin: 'com.android.library'
apply plugin: 'com.novoda.bintray-release'

publish {
   userOrg = 'kmshack'
   groupId = ‘com.kmshack.library'
   artifactId = ‘android-exception-tracker'
   publishVersion = '1.0.2'
   desc = 'Android Exception Tracker'
   website = 'https://github.com/kmshack/ExceptionTracker'
   issueTracker = "https://github.com/kmshack/ExceptionTracker/issues"
   repository = "https://github.com/kmshack/ExceptionTracker.git"
}

 

7) 터미널에가서 프로젝트의 위치에서 아래명령으로 빌드를 수행해보자.

$ ./gradlew clean build bintrayUpload -PbintrayUser=BINTRAY_USERNAME -PbintrayKey=BINTRAY_KEY -PdryRun=false

*BINTRAY_USERNAME은 아이디이며, BINTRAY_KEY는 Bintray 프로필 페이지의 API Key메뉴에서 값을 확인 할 수 있다.

 

8) 빌드가 끝나면 Bintray 사이트로 가면 해당 패키지가 만들어 졌고, 관련된 라이브러리 파일들도 업로드된 것을 볼 수 있다.

 

9) 여기까지가 Bintray 저장소에 라이브러리를 올린 것이고, 기본 저장소인 jCenter에는 아직 등록 되지 않았다. jCenter에 등록은 아주 간단하다. 패키지 정보 화면에서 Add to jCenter버튼을 눌러 확인만 하고 기다리면 jCenter저장소와 연동된다.

 

10) 연동이 된다면 Add to jCenter버튼은 없어지고, jCenter아이콘이 나타나며, 이제 안드로이드 스튜디오에서 사용해보면 된다.
compile ‘<groupId>:<artifactId>:<publishVersion>’ 이런식의 주소가 붙여지니 테스트해보자.

 








안드로이드 앱 배터리 최적화 무시방법

안드로이드 마시멜로에서 앱이 백그라운드로 처리하는 작업을 막아 배터리 소모를 줄이는 최적화 기능이 들어있다. 배터리 소모를 줄이는 것도 좋지만 앱의 작동에 문제가 되는 경우를 흔치 않게 보여지고 있다. 예를 들어 스마트와치와 연결하는 구글의 안드로이드 웨어의 경우 배터리 최적화모드로 인해 블루투스간의 페이링 연결이 끊겨버리는 문제가 발생한다.

구글도 이러한 문제로 인해 최근 배터리 최적화 목록에 안드로이드 웨어앱을 무시할 수 있는 간편한 설정기능을 넣어두었으며 설정하지 않으면 지속적으로 나타나 설정해야 연결이 끊기지 않는다는 안내를 지속적으로 하게끔 업데이트 되었다.

wear_doze_setting

일반적으로 구글의 레퍼런스 폰인경우 설정 > 배터리 > 배터리 최적화에서 설정을 해야하며, 제조사별로 메뉴위치나 네이밍이 달라서 사용자들이 직접 설정하기는 힘든 부분이다. 그렇기 때문에 안드로이드 웨어앱은 자체적으로 다이얼로그를 통해 설정기능을 넣었다.

 

어떻게?

안드로이드 API 23에 배터리 최적화를 앱에서 직접제어 할 수 있는 퍼미션이 추가 되었다.
android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS

 

해당 퍼미션 권한이 있으면 배터리 최적화설정을 해당앱의 권한으로 직접 설정 할 수 있다. 설정하는 방법은 Package이름과 설정 액션을 보내면된다.
API Level 23에서 추가된 PowerManager.isIgnoringBatteryOptimizations()를 이용하여 해당앱이 배터리 최적화 상태인가를 확인 할 수 있다. 그리고 ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS 액션을 이용하여 배터리 최적화를 무시할 수도 있다. 반대로 최적화 모드를 수행하기 위해서는 ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS 액션을 사용하면된다.

 

예제)

Intent i = new Intent();

String packageName = getPackageName();
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);

if (pm.isIgnoringBatteryOptimizations(packageName){
 i.setAction(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
} else {
 i.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
 i.setData(Uri.parse("package:" + packageName));
}
startActivity(i);

무시하는 액션을 수행하면 다이얼로그를 통해 사용자가 직접 배터리 최적화 무시를 할 수 있다.

 

배터리 최적화 모드로 앱의 정상작동에 문제가 된다면 앱에서 직접 배터리 최적화를 무시할 수 있도록 액션을 요청하여 다이얼로그를 통해 안내해주는 것도 하나의 방법이 될것 같다. 단, 퍼미션 추가로 부담은 있겠지만 앱이 정상작동하지 않는것 보다는 감수해볼만한 사항이다.

 

  • 2016/4/29 추가
    REQUEST_IGNORE_BATTERY_OPTIMIZATIONS을 사용하는 경우 안드로이드 플레이 스토어에서 승인을 안해주세요. 진짜 필요로하는 앱의 경우에만 승인이 가능하며 일반적으로 리젝될듯 합니다.



안드로이드 스튜디오 유용한 단축키 모음 #1

라인 아래위 이동

 alt + shift + up/down
❖ alt + shift + up/down

선택된 위치의 줄을 아래 또는 위로 움직인다.

 

라인 삭제

 cmd + backspace
❖ ctrl + y

선택된 위치의 줄을 삭제 한다.

 

라인 복제

 cmd + d
❖ ctrl + d

선택된 위치의 줄을 똑같이 복제한다.

 

확장 선택

 alt + up / down
❖ ctrl + w / ctrl + shift + w

선택 영역을 큰단위로 점차 확장 선택한다.

 

조건 추가

 cmd + alt + t
❖ ctrl + alt + t

선택된 라인및 영역 을 if / else, try / catch, for, while등으로 조건을 추가할 수 있다.

 

최근 편집 목록

 cmd + e
❖ ctrl + e

최근 편집한 파일의 목록을 보여준다. 상단 탭보다 더 많은 목록을 볼 수 있다.

 

문법 자동 완성

 cmd + shift + enter
❖ ctrl + shift + enter

해당 코드에 맞는 문법을 자동으로 완성해주는 기능이다. if를 입력하고 단축키를 누르면 괄호와 묶음 표현코드를 자동으로 작성해준다.

 

라인 합치기

 ctrl + shift + j
❖ ctrl + shift + j

문법에 맞도록 선택된 줄을 한줄로 합치는 기능이다. 주석이나 의미없이 줄바꿈한 코드를 빠르게 한줄로 수정할 수 있다.

 

클래스 구조 탐색창

 cmd + F12
❖ ctrl + F12

클래스구조 창을 띄운다. 메서드, 변수등 리스트로 한번에 볼 수 있으며 검색을 통해 해당위치로 빠르게 이동 할 수 있다.

 

구현 코드 빠른 창으로 보기

 alt + space
❖ ctrl + shift + i

선택된 메서드를 보기위해 클래스로 이동하지 않고 팝업창을 통해 빠르게 볼 수 있다.

 

북마크 기능

북마크(선택/해지 토글) 하기
 F3
❖ F11

북마크 보기
 alt + F3
❖ ctrl + F11

해당 위치를 북마크 해둘 수 있는 기능이다. 복잡한 구조에서 해당 메서드나 변수를 찾을때 북마크 해두면 쉽게 찾아 갈 수 있다.

 

액션 찾기

 cmd + shift + a
❖ ctrl + shift + a

다양한 기능을 검색을 통해 찾을 수 있다. 위에서 언급한 기능의 단축키가 생각이 나지 않다면 검색을 통해 찾을 수 있다.

 

해당 단축키는 윈도우 리눅스 Default, OSX는 Mac OSX 10.5+기반으로 작성되었다.

 




Android VectorDrawables

안드로이드 롤리팝에서 Vector방식의 Drawable을 사용 할 수 있는 VectorDrawable이 추가되었다. 구글의 안드로이드 Support Library 23.2부터 안드로이드 5.0 이하 버전에도 VectorDrawable을 지원한다.

픽셀 마다 색상 정보를 가지는 Bitmap과는 다르게 Vector방식은 Path정보를 통해 그래픽을 나타나게 된다. 이렇게 선과 선의 연결 정보를 가지고 있기때문에 정확한 크기정보를 가지고 있지않아 사이즈를 임의로 늘리거나 원하는 색상으로 변경해도 Bitmap처럼 뭉게지거나 깨지지 않는 장점이 존재하게 된다. 하지만 Bitmap처럼 복잡한 그래픽을 표현 하지는 못한다.

안드로이드 5.0 발표 당시 구글이 머트리얼 디자인을 함께 발표 하였다. 이 머트리얼 디자인 가이드의 주된 요점은 요소를 “단순화” 한다는 점에서 Vector와 정확하게 일치 한다. 머트리얼 디자인 아이콘을 보더라도 Vector방식으로 모두 표현이 가능하다.

기존의 BitmapDrawble을 사용함으로 DPI별로 각각 다른 이미지 리소스를 준비 했다면 VectorDrawable을 활용 한다면 DPI별로 각각 다른 이미지를 준비 할 필요가 전혀 없어진다. 이미지 관리 갯수도 작아질 뿐만아니라 용량도 많이 줄것이다.

android

 

 

 

 

 

 

<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="500px" height="500px" viewBox="0 0 500 500" enable-background="new 0 0 500 500" xml:space="preserve">
<g id="max_width__x2F__height" display="none">
<path display="inline" d="M499.001,1v498H1V1H499.001 M500.001,0H0v500h500.001V0L500.001,0z"/>
</g>
<g id="androd">
<path fill="#9FBF3B" d="M301.314,83.298l20.159-29.272c1.197-1.74,0.899-4.024-0.666-5.104c-1.563-1.074-3.805-0.543-4.993,1.199
L294.863,80.53c-13.807-5.439-29.139-8.47-45.299-8.47c-16.16,0-31.496,3.028-45.302,8.47l-20.948-30.41
c-1.201-1.74-3.439-2.273-5.003-1.199c-1.564,1.077-1.861,3.362-0.664,5.104l20.166,29.272
c-32.063,14.916-54.548,43.26-57.413,76.34h218.316C355.861,126.557,333.375,98.214,301.314,83.298"/>
<path fill="#FFFFFF" d="M203.956,129.438c-6.673,0-12.08-5.407-12.08-12.079c0-6.671,5.404-12.08,12.08-12.08
c6.668,0,12.073,5.407,12.073,12.08C216.03,124.03,210.624,129.438,203.956,129.438"/>
<path fill="#FFFFFF" d="M295.161,129.438c-6.668,0-12.074-5.407-12.074-12.079c0-6.673,5.406-12.08,12.074-12.08
c6.675,0,12.079,5.409,12.079,12.08C307.24,124.03,301.834,129.438,295.161,129.438"/>
<path fill="#9FBF3B" d="M126.383,297.598c0,13.45-10.904,24.354-24.355,24.354l0,0c-13.45,0-24.354-10.904-24.354-24.354V199.09
c0-13.45,10.904-24.354,24.354-24.354l0,0c13.451,0,24.355,10.904,24.355,24.354V297.598z"/>
<path fill="#9FBF3B" d="M140.396,175.489v177.915c0,10.566,8.566,19.133,19.135,19.133h22.633v54.744
c0,13.451,10.903,24.354,24.354,24.354c13.451,0,24.355-10.903,24.355-24.354v-54.744h37.371v54.744
c0,13.451,10.902,24.354,24.354,24.354s24.354-10.903,24.354-24.354v-54.744h22.633c10.569,0,19.137-8.562,19.137-19.133V175.489
H140.396z"/>
<path fill="#9FBF3B" d="M372.734,297.598c0,13.45,10.903,24.354,24.354,24.354l0,0c13.45,0,24.354-10.904,24.354-24.354V199.09
c0-13.45-10.904-24.354-24.354-24.354l0,0c-13.451,0-24.354,10.904-24.354,24.354V297.598z"/>
</g>
</svg>

Vector방식에서 가장 흔히 쓰이는 SVG 형식으로 아이콘을 제작하면 된다. 하지만 안드로이드에서는 SVG형식의 확장자를 바로 사용 할 수 없으며 VectorDrawable로 변환 해야한다. 최근 안드로이드 스튜디오에서는 SVG를 Import하면 자동으로 VectorDrawable 변경해주는 기능이 추가되어 쉽게 사용 할 수 있다. 위의 안드로이드 아이콘은 Path를 통해 SVG로 제작된 아이콘이다. 안드로이드에서 사용하기위해 아래와 같이 만들 수 있다.

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:viewportWidth="500"
android:viewportHeight="500"
android:width="500px"
android:height="500px">
<group android:name="android">
<path
android:name="head"
android:fillColor="#9FBF3B"
android:pathData="M301.314,83.298l20.159-29.272c1.197-1.74,0.899-4.024-0.666-5.104c-1.563-1.074-3.805-0.543-4.993,1.199L294.863,80.53c-13.807-5.439-29.139-8.47-45.299-8.47c-16.16,0-31.496,3.028-45.302,8.47l-20.948-30.41c-1.201-1.74-3.439-2.273-5.003-1.199c-1.564,1.077-1.861,3.362-0.664,5.104l20.166,29.272c-32.063,14.916-54.548,43.26-57.413,76.34h218.316C355.861,126.557,333.375,98.214,301.314,83.298" />
<path
android:name="left_eye"
android:fillColor="#FFFFFF"
android:pathData="M203.956,129.438c-6.673,0-12.08-5.407-12.08-12.079c0-6.671,5.404-12.08,12.08-12.08c6.668,0,12.073,5.407,12.073,12.08C216.03,124.03,210.624,129.438,203.956,129.438" />
<path
android:name="right_eye"
android:fillColor="#FFFFFF"
android:pathData="M295.161,129.438c-6.668,0-12.074-5.407-12.074-12.079c0-6.673,5.406-12.08,12.074-12.08c6.675,0,12.079,5.409,12.079,12.08C307.24,124.03,301.834,129.438,295.161,129.438" />
<path
android:name="left_arm"
android:fillColor="#9FBF3B"
android:pathData="M126.383,297.598c0,13.45-10.904,24.354-24.355,24.354l0,0c-13.45,0-24.354-10.904-24.354-24.354V199.09c0-13.45,10.904-24.354,24.354-24.354l0,0c13.451,0,24.355,10.904,24.355,24.354V297.598z" />
<path
android:name="body"
android:fillColor="#9FBF3B"
android:pathData="M140.396,175.489v177.915c0,10.566,8.566,19.133,19.135,19.133h22.633v54.744c0,13.451,10.903,24.354,24.354,24.354c13.451,0,24.355-10.903,24.355-24.354v-54.744h37.371v54.744c0,13.451,10.902,24.354,24.354,24.354s24.354-10.903,24.354-24.354v-54.744h22.633c10.569,0,19.137-8.562,19.137-19.133V175.489H140.396z" />
<path
android:name="right_arm"
android:fillColor="#9FBF3B"
android:pathData="M372.734,297.598c0,13.45,10.903,24.354,24.354,24.354l0,0c13.45,0,24.354-10.904,24.354-24.354V199.09c0-13.45-10.904-24.354-24.354-24.354l0,0c-13.451,0-24.354,10.904-24.354,24.354V297.598z" />
</group>
</vector>

변형되는 xml은 SVG와 비슷한 구조로 부모 vector내에 path들이 존재하며 group을 통해서 path들을 묶어서 관리 할 수 있다. 이 SVG파일은 약 4kByte로 500×500의 Bitmap형식일때 25kByte 보다 약 6배이상 작은 공간을 차지한다. 사용법은 기존의 Drawable사용법과 동일하며 전혀 이질감 없이 VectorDrawable을 사용 할 수 있다.

<ImageView
android:id="@+id/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/android"/>

이렇게 VectorDrawable은 구글의 최신 디자인인 머트리얼 디자인을 표현하기에 가장 적합한 그래픽요소이며, 기존의 BitmapDrawable방식을 사용함으로 DPI별로 리소스를 준비해야하는 문제점은 한번에 해결 해 줄 수 있다. 안드로이드 스튜디오를 통해 자동 Import도 지원하고 있어 한결 편하게 사용 할 수 있기때문에 이제 선택 아닌 필수로 사용해볼만 하다.

 

 




3가지 메소드로 끝내는 안드로이드 마시멜로 권한 획득

안드로이드 마시멜로부터 권한획득이 변경되었다. 기존의 안드로이드 Manifest에 권한을 선언 해두기만 하면 되었다. 사용자 입장에서는 설치시 해당 권한을 확인 할뿐 설치 후 앱을 사용하면서 해당 권한을 언제 사용하는지 알 수 없다. 구글은 이러한 보안적인 문제점을 해결 하기 위해 권한획득의 시점을 변경 하였다. 관련된 API를 사용하기전 권한을 획득 하는 방식으로 변경하여 사용자는 언제 어느시점에 권한이 필요한지 인지 할 수 있으며 보안적인 문제점을 좀 더 보완할 수 있다는 점이다. 마시멜로 권한 획득 어떻게 대응하는지 알아보자.

권한 획득은 3가지의 지원되는 메소드만 이용하면 간단하게 대응 할 수 있다.

ContextCompat.checkSelfPermission(Context context, String permission)

해당 퍼미션의 상태를 체크한다. 메소드를 이용하여 퍼미션이 허용되었는지 거부된 퍼미션인지 체크 할 수 있다. 단, 마시멜로 이전 버전으로 빌드된 앱이 마시멜로를 타겟으로 빌드된 앱으로 업데이트 설치된 사용자의경우 기존의 모든 퍼미션은 허용되어 있다.

Manifest.permission.*에 모든 퍼미션이 정의되어 있으며, PERMISSION_GRANTED(허용된 퍼미션), PERMISSION_DENIED(거부된 퍼미션)으로 결과값이 리턴된다.

ActivityCompat.shouldShowRequestPermissionRationale(Context context, String permission)

사용자가 권한 요청을 한번이라도 거부한 경우를 알 수 있다. 사용자가 권한에 대한 의심으로 인해 거부하는 경우 좀더 상세한 안내를 표시 해줄 수 있다. 최초 퍼미션 요청시에는 false를 리턴한다.

ActivityCompat.requestPermissions(Activity activity, Stringp[] permission, int requestCode)

Callback
onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)

퍼미션을 요청한다. 퍼미션을 퍼미션 그룹을 통해 한번에 간소화된 다이얼로그로 창이 뜬다. onRequestPermissionsResult()를 통해 결과값이 Callback된다.

정리

1) ContextCompat.checkSelfPermission()
– 해당권한이 허용되 있는지 체크한다.

2) ActivityCompat.shouldShowRequestPermissionRationale()
– 이미 한번 이라도 거부한 경우 좀 더 상세한 안내페이지를 표시해준다.
– 다시 묻지 않기를 선택 후 거부한 사용자를 위해 안내페이지에 설정으로 바로가는 액션을 준비 해둔다.

3) ActivityCompat.requestPermissions()
– 퍼미션을 요청한 후 Callback되었을때 결과값 또는 checkSelfPermission()을 통해 해당 퍼미션 권한을 획득하면 다음 단계를 실행 한다.

TIP!

퍼미션 권한 획득 후 획득된 퍼미션 그룹과 동일한 퍼미션이 추가 되는 경우
퍼미션이 추가 된 경우 해당 그룹에서 이미 권한을 획득한 사항이라면 requestPermissions()을 호출 하면 아무런 UI없이 onRequestPermissionsResult()를 통해 자동으로 권한이 획득된다.

다시 묻지않기 선택 후 거부시 requestPermissions()을 요청하는 경우
더이상 다이얼로그를 통해 해당 퍼미션의 권한을 요청 할수 없는 상태임으로 안내페이지를 통해 앱 정보->권한에서 해당 권한을 받도록 유도한다.
권한으로 바로가는 링크는 없으며, ACTION_APPLICATION_DETAILS_SETTINGS 액션을 통해 앱 정보페이지로 연결 해주는 정도가 최선이다.

Intent i = new Intent();
i.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
i.addCategory(Intent.CATEGORY_DEFAULT);
i.setData(Uri.parse("package:" + context.getPackageName()));
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
i.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
context.startActivityForResult(i, REQUEST_CODE_SETTING_ACTIVITY);


권한 안내 가이드는 아래 구글 머티리얼 디자인 사이트를 참조하자.

https://www.google.com/design/spec/patterns/permissions.html#permissions-request-patterns

 

추가 참고:
http://googledevkr.blogspot.kr/2015/09/android60runtimepermission.html

http://developer.android.com/intl/ko/guide/topics/security/permissions.html#normal-dangerous

 




디자이너 없이 머티리얼 아이콘 쉽게 제작하기

안드로이드 머티리얼 디자인이 발표 된지 이제 2년이라는 시간이 지났다. 머티리얼 디자인은 단순함을 추구하고 아주 심플한 디자인이다. 아이콘또한 2가지 이상의 색상으로 표현하지 않는 정말 한순화된 디자인 스타일이다. 이렇게 머티리얼 디자인은 개발자에게는 기회이다.

구글에서 안드로이드의 아이콘 리소스를 엄청난 양으로 공개한 마당이 이를 활용한다면 디자이너 없이 머티리얼 디자인의 앱을 만들 수 있다. 이번에 소개 할 아이콘을 제작도구또한 마찬가지다. 단순한 머티리얼 디자인이기때문에 이렇게 툴을 통해서 아이콘을 제작할 수 있도록 만들 수 있었다.

해당 툴을 이용하면 머티리얼 아이콘을 단숨에 만들 수 있다. SVG파일이나 기존의 구글에서 아이콘 리소스를 공개한것으로 사용가능하다. 다양한 설정값을 조절해가면서 마음에 드는 아이콘을 쉽게 제작할 수 있다.

http://bitdroid.de/Android-Material-Icon-Generator/

이툴은 깃허브를 통해 소스도 오픈되어 있다.




Support Library “BottomSheet Behavior”

AppCompat V23.2에서 머트리얼 디자인 가이드 중 BottomSheet를 구현한  위젯이 추가 되었다. 기존의 CoordinatorLayout에 하나의 행동 방법으로 BottomSheet가 구현되었다. 또한 독립적으로 사용하기 위해 BottomSheetFragmentDialog를 이용하여 다이얼로그형태로도 사용가능하다. CoordinatorLayout의 Bottom Sheet Behavior를 어떻게 사용하는지 알아보자.

어디에 사용되는가?

BottomSheet는 이미 구글 앱을 보면 많이 적용되어 있다. 구글 맵, 플러그, 뮤직등 다양한 디자인과 형태로 사용중이다. 이는 컨텐츠를 화면 전환 없이 더 많이 빠르게 보여주는데 사용된다. 또한 특정 액션을 했을때 사용할 여러가지 액션들을 선택할때도 사용된다.

스크린샷 2016-03-16 오후 1.35.27.png
스크린샷 2016-03-16 오후 1.35.44.png

어떻게 사용하는가?

BottomSheet는 별도의 위젯으로 존재 하지는 않는다. CoordinatorLayout을 이용하여 자식뷰들의 행동을 구현한것으로 속성변경만으로 간단하게 BottomSheet를 사용 할 수 있다.

  • appbar_scrolling_view_behavior
    – android.support.design.widget.AppBarLayout$ScrollingViewBehavior
  • bottom_sheet_behavior
    – android.support.design.widget.BottomSheetBehavior
CoordinatorLayout을 사용해본 적이 있다면 레이아웃에 layout_behavior속성을 사용해본 적이 있을 것이다. 속성의 값으로 appbar_scrolling_view_behavior를 사용한적이 있을 것이다. 이는 툴바와 스크롤 되는 뷰간의 상호 작용을 위해 구현된 behavior이다. BottomSheet또한 CoordinatorLayout의 하나의 behavior이며, bottom_sheet_behavior를 사용하면 된다. bottom_sheet_behavior는 스트링 이름이며 값은 클래스명으로 지정되어 있으며 해당 클래스가 로드되어 수행되는 구조이다.

레이아웃

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white">

    <LinearLayout
        android:id="@+id/bottomSheet"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#EEE"
        android:orientation="vertical"
        app:behavior_peekHeight="64dp"
        app:behavior_hideable="false"
        app:layout_behavior="@string/bottom_sheet_behavior">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="16dp"
            android:textColor="@color/colorPrimaryDark"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:text="Bottom sheets" />


        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="16dp"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:text="Bottom sheets slide up from the bottom edge of the screen to reveal additional content."/>


        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="16dp"
            android:layout_marginTop="8dp"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:text="Modal bottom sheets are alternatives to menus, or simple dialogs, and can display deep-linked content from another app. They appear above other UI elements and must be dismissed in order to interact with the underlying content. When a modal bottom sheet slides into the screen, the rest of the screen dims, giving focus to the bottom sheet." />

    </LinearLayout>

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="16dp"
        android:layout_marginEnd="16dp"
        android:src="@mipmap/ic_launcher"
        app:layout_anchor="@+id/bottomSheet"
        app:layout_anchorGravity="top|right" />

</android.support.design.widget.CoordinatorLayout>

CoordinatorLayout 자식뷰에서 BottomSheet를 사용하고 싶은 레이아웃에 behavior속성을 주면된다.  값에는 이미 정의된 @string/bottom_sheet_behavior값을 주면된다. 정의된 값은 라이브러리에 기본적으로 포함되어 있으며, 나타나지 않는 다면 AppCompat V23.2인지 확인해봐야 한다.

BottomSheet높이는 자식뷰의 크기에 따라 변하게 되며 기본적으로 보여지게 될 높이는 behavior_peekHeight 속성을 통해 지정 할 수 있다. behavior_peekHeight[dpi] 값은 반드시 필요하며 값을 주지 않는 경우 자식뷰의 크기계산을 하지 못하기 때문에 뷰가 나타나지 않을 수 있다. 그리고 behavior_peekHeight 속성을 준 높이보다 더 최소한으로 사용자가 감출 수 있도록  behavior_hideable[true/false] 속성을 지원한다.

  • behavior_peekHeight: 기본적으로 보여질 높이
  • behavior_hideable: 사용자의 액션에 의해 완전지 감춰질지 여부

Listener

BottomSheet의 상태가 확장된 상태인지 완전히 숨겨져있는지등에 대한 상태를 알 수 있도록 Listener를 지원한다.

mBottomSheet = findViewById(R.id.bottomSheet);
mBehavior = BottomSheetBehavior.from(mBottomSheet);
mBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
    @Override
    public void onStateChanged(@NonNull View bottomSheet, int newState) {
        // newState = 상태값
    }
    @Override
    public void onSlide(@NonNull View bottomSheet, float slideOffset) {
    }
});

상태 값은 아래와 같이 5가지로 정의되어 있다.

  • STATE_COLLAPSED: 기본적인 상태이며, 일부분의 레이아웃만 보여지고 있는 상태. 이 높이는 behavior_peekHeight속성을 통해 변경 가능
  • STATE_DRAGGING: 드래그중인 상태
  • STATE_SETTLING: 드래그후 완전히 고정된 상태
  • STATE_EXPANDED: 확장된 상태
  • STATE_HIDDEN: 기본적으로 비활성화 상태이며, app:behavior_hideable을 사용하는 경우 완전히 숨겨져 있는 상태
상태 값을 통해 좀 더 확장된 기능을 구현할 수 있다.
이 BottomSheet는 이미 잘알려진 AndroidSlidingUpPanel과 동일하며, 좀 더 정리된 형태라고 보면된다. 머트리얼 디자인을 구현함에 있어서 CoordinatorLayout는 흔히 쓰이고 있으며 BottomSheet 또한 구현에 있어서 필수 요소가 될것이다. 특히 컨텍스트 메뉴를 BottomSheet를 통한 메뉴로 대체 되고 있는 느낌이 들며 사용성또한 좋기때문이다.



StatusBar의 아이콘 색상 변경

안드로이드 마시멜로에서 windowLightStatusBar속성이 생겼다. 상태바의 백그라운드를 임의로 조절 할 수 있기때문에 아이콘의 색상이 문제가 제기되어 왔다. 흰색배경인 경우 아이콘의 색과 동일해지기 때문에 아이콘이 보이지 않게 된다. 이를 위해 상태바의 아이콘색을 흰색배경에 맞도록 검은색으로 바꿔주는 속성이 생기게 된것이다.

기본 속성

속성적용

설정방법은 style.xml에 속성을 지정하거나 코드를 통해 가능하다.

style.xml

<item name="android:windowLightStatusBar">true</item>

Code

View view = findViewById(R.id.your_view);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
  if (view != null) {
    view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
  }
}
이 글은 Evernote에서 작성되었습니다. Evernote는 하나의 업무 공간입니다. Evernote를 다운로드하세요.