'Android'에 해당되는 글 3건

  1. 2014.03.11 Android에서 iOS 에어로글래스 효과 만들기 (1)
  2. 2013.11.08 Gradle + AndroidStudio + AndroidAnnotations with two different product flavor(diifferent packgename)
  3. 2013.10.22 Android Studio + Gradle 이용해서 apk빌드하기
2014.03.11 14:27

이번에 아이폰으로 바꾸면서 iOS7을 접했습니다. 그런데 너무 마음에 드는게 상단 타이틀바와 위에 노티바? 가 혼연일체가 되어 같은 색으로 표시됨과 동시에 윈도의 에어로 글래스 효과인데, 안드로이드에서는 적용된 앱이 별로 없더군요. (야후 날씨앱이 적용된거 같은데....자세히는 모르겠네요)


요즘 디자인 트랜드가 Flat design 인데 여기서 나오는것이 Focus on Typo, Color 등이 있습니다. 

그중 하나가 이런 배경 흐림 효과가 다른 엘리먼트에 Focus on 할 수 있게 도와주는, 그런 역할을 하는듯 싶네요.

이런식으로 배경 흐림을 줌으로써 단순히 알파를 준것과는 다르게 인지부하를 많이 줄일 수 있는 방안이라 생각됩니다.


* iOS의 경우, status bar 또한 앱의 색상에 맞춰서 바꿀 수 있는데 안드로이드의 경우 지원하지 않습니다. 요즘 버전들은 또 이쁘게 나오는것 같은데 아이폰으로 갈아타서 자세힌 모르겠네요... 라기보단, 대신 안드로이드에서도 아이폰과 같이 status bar의 색상을 바꿀 수 있는 라이브러리가 존재합니다.



그래서 안드로이드에서는 안될까? 해서 한번 해보기로 했습니다. 


먼저 이러한 효과를 구현하기 위해서는 


1. 타이틀바의 영역을 알아내고

2. 타이틀바 아래에 위치한 뷰의 이미지를 실시간으로 가져와야하고

3. 가져온 이미지에 후처리를 가한뒤(블러)

4. 색상을 입히면 됩니다.


먼저 지금까지의 결론을 말하면 "NDK를 쓰지 않고는 제대로된 효과를 구현하기 어렵다." 입니다.

비트맵 처리가 메모리도 많이 먹고 속도도 느리기 때문에 NDK를 사용해야 실사용할 수 있을 만큼의 성능이 나올것 같습니다.



먼저 성능 생각 하지 않고 해보면 

1. 타이틀바 아래에 위치한 뷰의 원본 이미지를 가져오고

2. 타이틀바 영역부분만 잘라낸뒤,

3. 블러를 하고

4. 타이틀바의 백그라운드로 설정합니다.


이렇게 했을때 굉장히 느리고 스크롤도 힘들고 무엇보다도

스크롤할땐 갱신되지 않고 스크롤을 땟을때만 갱신이 됩니다.

(하단에 위치한 뷰는 ViewPager 이고 타이틀바의 onDraw() 를 오버라이드해 갱신을 하고 있습니다.)

굉장히 만족할만한 퀼리티이지만 실사용이 불가능해 포기.

이것은 스모키하게 색상을 추가한것입니다.



그다음으로 생각해본건 이미지의 사이즈가 너무 크다보니(갤2 기준 480x74 px) 이를 줄여서 블러 처리를 하자 인데,

(블러 처리가 부하가 심하기 때문..)

이미지를 축소한뒤, 백그라운드로 넣어주면 아래와 같이 엘리어싱이 보이게 됩니다.

하지만 퍼포먼스가 조금 나아지긴 했지만 여전히 느리고 위와 같은 문제점을 안고 있습니다.

또 퀼리티도 후지기 때문에 포기.




여기까지 진행하다가 큰 문제점인 뷰페이져에서 가로 스와이프시 타이틀바 미 갱신 문제를 해결하기로 했습니다.

일단 하단에 위치한 뷰에 대한 이미지를 가져오는 방법은 두가지가 있는데(물론 더 있겠죠.,,)


1. view.draw(muCanvas); 로 캔버스에 그리기

2. view.getDrawingCache(); 또는 view.buildDrawingCache(); 로 캐시를 비트맵 형태로 가져오기


이렇게 있습니다. 

먼저 각각 살펴보면


1번의 경우 퍼포먼스가 좋습니다. 캔버스 영역만 그려서인지 실사용할 수준의 속도가 나오지만 뷰페이져의 경우엔 가로 스와이프시 갱신되지 않고 다른 페이지에 대해서도 갱신되지 않았습니다. - 한페이지에 대해서만 그리는데 좀 더 찾아봐야할듯합니다.


2번의 경우엔 굉장히 느립니다. 미칠듯이 느립니다. 느린 원인이 이녀석이었습니다.

먼저 캐시를 가져오는 코드가


pager.setDrawingCacheEnable(true);

pager.setDrawingCAcheQuaility(DRAWING_CACHE_QUAILITY_LOW);

// ---- 여기까진 미리 셋팅 해주면 되고


실시간으로 가져오기 위해서는 

pager.getDrawingCache();를 호출하여 뷰페이저의 캐시를 가져오고 

사용한뒤엔 반드시

pager.destoryDrawingCache(); 를 호출해서 캐시를 삭제해줘야 합니다.

이때 삭제를 해주지 않으면 제대로 캐시가 갱신되지 않고 좌우 스와이프시에도 갱신이 안됩니다.








아직 고민중인데 결국 NDK를 사용해야 할것 같습니다.


블러의 경우 스택블러라 불리는 블러기법을 사용중입니다. (박스블러보단 퀼리티가 좋고 가우시안블러보단 몇배 빠르답니다)



14.5.13



그러다 실시간 갱신은 상당한 부하를 가짐을 알고 있어 이 부분을 어떻게 해결할까를 생각하다 굉장히 쉬운 방법이 떠올랐습니다.ㅋㅋㅋ


애초에 실시간이 어렵기 때문에 차라리 블러된이미지를 미리 만들어 두고 이를 옮기는 식으로 사용하면 될것 같습니다. 하지만 이것도 스크롤이벤트를 받아다가 계속 움직여 주고 가지고있는 부분의 이미지가 끝나면 곧바로 다음 이미지를 받아다가 블러를 해줘야 해서 일종의 렉이 발생할 수 있을듯 합니다만 위 방법처럼 무식하게 계속 실시간 블러를 하는것 보단 나을듯 합니다. 


도전은 나중에;;;;;;;라고 하다가 못하겟지;;;






== 계속 작성중 ==


저작자 표시 비영리 변경 금지
신고
Trackback 0 Comment 1
  1. Favicon of http://estellesiahome.tistory.com BlogIcon 에스텔시아 2014.04.07 12:48 신고 address edit & del reply

    오랫만에 와봤더니 이런 내용이 업데이트 되어 있네
    잘 지냐냐?

2013.11.08 20:12

Gradle + AndroidStudio + AndroidAnnotations with two different product flavor(diifferent packgename)


안드로이드에서 제일 짜증나고 불편하고 반복적인 작업이 바로 R 클래스, 그러니까 리소스 사용에 관련된 모든것을 R.java 에 접근해서 사용하는 것입니다.


이때 이것을 자동화? 또는 좀더 가독성이 좋고 유지보수하기 좋게 해주는것이 바로 AndroidAnnotations, Roboguice 등이 있습니다. 물론 저런 뷰 Injection 말고도 다른 기능들 rest, async, event처리등 굉장히 많은 편리한 기능들을 내포하고 있습니다.


http://androidannotations.org/

https://github.com/excilys/androidannotations

https://code.google.com/p/androidannotations/wiki/FAQ

https://github.com/excilys/androidannotations/issues/690

https://github.com/excilys/androidannotations/issues/517

https://github.com/excilys/androidannotations/issues/676

http://stackoverflow.com/questions/17910603/android-studio-gradle-android-annotations/17999249#17999249

어노테이션 프로세서관련 stackoverflow 답변

http://stackoverflow.com/questions/19351168/gradle-annotations-flavors-wont-run-annotations-processor

메이븐 셋팅

https://github.com/excilys/androidannotations/wiki/Maven


이번에는 AndroidStudio에서 gradle로 빌드할때 아래와 같은 조건일때 빌드하는 방법을 포스팅 하려고 합니다. 한 4일? 간 삽질해서 알아낸...멍청하네요.ㅋㅋ


1. AndroidAnnotations 를 사용한다.

2. Gradle 빌드에서 두가지 서로다른 product flavor가 존재한다.

3. 각 product flavor에는 pckage name이 조금씩 다르다.

(ex, free버전에는 패키지네임 뒷부분에 **.**.**.free가 붙는다)


먼저 AndroidAnnotations는 컴파일 시간에 미리 관련 뷰들을 바인딩 해줘서 런타임에서 속도 저하 없이 사용할 수 있고, Roboguice는 런타임에? 하는걸로 알고 있습니다. (이 부분에 대해서 자세히 아시는 분은 지적해 주시면 감사하겠습니다.)


따라서 컴파일 타임에 뭔가를 하는데 이름에서도 나타내듯이 어노테이션을 사용하게 됩니다.

즉, @~~~~~뭐 이런것을 사용한단 말이죠. JUnit 에서 @Test 처럼 미리 정의된 어노테이션을 가지고 뷰를 바인딩 하게 됩니다. 

그리고 컴파일시에 자바의 어노테이션 프리프로세서를 통해서 어노테이션을 사용한 클래스를 상속받아 새로 클래스를 만들게 되고 여기서 바인딩이 이뤄지게 됩니다.


첫번째 문제는 새로 클래스(엑티비티)를 생성하기 때문에 기존의 이름을 사용할 수 없습니다. 따라서 AndroidAnnotations에서는 이름 뒤에 언더스코어, '_' 이것을 붙여서 구분하게 됩니다.

즉, AndroidManifest.xml 에서 엑티비티를 정의할때 '_' 를 추가해야합니다.

Intent를 사용할때도 위와 같습니다.


두번째 문제는, 이 바인딩이 이뤄질때 onCreate에서 바로 뷰들을 사용할 수 없습니다. 이때 사용하게되면 바인딩이 아직 이뤄지지 않았기 때문에 NullPointerException 이 나게 됩니다.

따라서 바인딩이 다 된 시점에야 뷰들을 초기화 하고 사용할 수 있는데 이것을 콜백으로 받아오는 어노테이션이 바로 @AfterViews 입니다. 즉 이 어노테이션이 붙은 매소드에서 바인딩이 다 된후에 호출하게 되고 뷰에 대해서 접근할 수 있습니다. 따라서 onCreate 매서드에는 거의 바디가 조촐합니다.


첫번째 링크에서 보다시피 굉장히 매소드들, 필드들이 굉장히 가독성이 좋게 되고 유지보수 펴하게 되어있으며 코드 또한 간결하게 됩니다. 이렇게 뷰에 대한 반복적인 작업만 없앴는데도 상당히 편해졌다는것을 알 수 있습니다.


이정도만 AndroidAnnotations 설명을 마치고 이제 본격적인 Gradle 과의 연동?에 대한 내용입니다.


먼저 메이븐으로 의존성 관리를 하고 있으면 좋습니다. 따라서 AndroidStudio에서 의존성을 추가해주는데 이때 중요한것이 최신버전이 아닌 스냅샷 버전을 사용할것입니다.

현재 최신버전이 2.7.1 인거 같은데 최신버전에 없는 컴파일 인자를 사용하기에 3.0 SNAPSHOT을 사용하도록 합니다. (여기서 굉장히 삽질한것이, build.gradle에 정의한 AA버전과 메이븐의 AA버전이 안맞아서....이틀간....-_-)


그런뒤 build.gradle에 아래와같이 추가해줍니다.


ext.daggerVersion = '1.0.0';

androidAnnotationsVersion = '3.0-SNAPSHOT';

repositories {

mavenCentral()

maven {

url 'https://oss.sonatype.org/content/repositories/snapshots/'

}

}

android {

productFlavors {

paid {

packageName "com.my.app"

}

free {

packageName "com.my.app.free"

}

}

}

android.applicationVariants.all { variant ->

aptOutput = file("${project.buildDir}/source/apt_generated/${variant.dirName}")

println "****************************"

println "variant: ${variant.name}"

println "manifest:  ${variant.processResources.manifestFile}"

println "aptOutput:  ${aptOutput}"

println "****************************"


variant.javaCompile.source = variant.javaCompile.source.filter { p ->

return !p.getPath().startsWith(aptOutput.getPath())

}


variant.javaCompile.doFirst {

println "*** compile doFirst ${variant.name}"

aptOutput.mkdirs()


variant.javaCompile.options.compilerArgs += [

'-classpath', configurations.compile.asPath,

'-processorpath', configurations.apt.getAsPath(),

'-AandroidManifestFile=' + variant.processResources.manifestFile,

'-AresourcePackageName=com.my.app',

'-s', aptOutput

]

}

}

configurations {

apt

}

dependencies {

compile "com.android.support:support-v13:13.0.0"


apt "org.androidannotations:androidannotations:${androidAnnotationsVersion}"

compile "org.androidannotations:androidannotations-api:${androidAnnotationsVersion}"


apt "com.squareup.dagger:dagger-compiler:${daggerVersion}"

compile "com.squareup.dagger:dagger:${daggerVersion}"

}

* androidannotations.jar 은 딱 컴파일 할때 필요한, 즉 어노테이션 프로세서가 있는 jar이고,
실제 우리가 써야 하는건  androidannotations-api 인듯. 이틀간 이거때문에 삽질 함


여기서 스냅샷을 사용하는 이유가 바로 free버전의 패키지 네임이 다르기 때문입니다.

만악 스냅샷이 아닌 최신버전을 사용하게 되면(물론 나중의 최신버전엔 기 인자가 포함될 수 있겠죠), 


*** compile doFirst FreeDebug

Note: Starting AndroidAnnotations annotation processing

Note: AndroidManifest.xml file found: */build/manifests/free/debug/AndroidManifest.xml

warning: The AndroidManifest.xml file was found, but not the compiled R class: com.my.app.free.R

/SettingViewPagerActivity.java:30: error: Resource id value not found in R.id: 2131165208

@ViewById(R.id.pager)

^

Note: Number of files generated by AndroidAnnotations: 1

Note: Generating source file: com.my.app.activity.SettingViewPagerActivity_

Note: Time measurements: [Whole Processing = 135 ms], [Process Annotations = 63 ms], [Validate Annotations = 31 ms], [Extract Annotations = 13 ms], [Generate Sources = 12 ms], [Find R Classes = 9 ms], [Extract Manifest = 5 ms],

Note: Time measurements: [Whole Processing = 0 ms],

warning: The following options were not recognized by any processor: '[androidManifestFile, resourcePackageName]'

1 error

1 warning

:MyApp:compileFreeDebug FAILED


처럼 실패하게 됩니다. 이유는 R.class를 찾아야 하는데 못찾아서 해당 리소스를 가져오지 못해 에러가 납니다.

그러면 어떻게 R.class를 찾아야 하나...? 보면 R을 com.my.app.free.R 인줄 알기 때문입니다.

즉 product flavor에서 package name을 정의한대로 찾아가기 때문입니다.

그래서 -AresourcePackageName=com.my.app 이 인자를 사용해서 고정해주게 됩니다.


이 인자가 얼른 최신버전에 반영이 되기를 바랍니다.




저작자 표시 비영리 변경 금지
신고
Trackback 0 Comment 0
2013.10.22 15:54

안드로이드 스튜디오에서 프로젝트를 생성하게 되면 기본적으로 gradle이 적용된? 상태가 된다.


이때 프로젝트 구조가 기존에 알던 자바 프로젝트와 조금 다른데,


먼저 프로젝트폴더 안에 실제 어플리케이션의 root가 존재하게 되고, 프로젝트 폴더안에는 그 밖에 전체적인 셋팅을 담고 있다.

여기서 build.gradle이 여기도 존재하고, 어플리케이션폴더 안에도 존재하는데, 이는 밖에 위치한 build.gradle이 최상위란 뜻인거 같다.


우리가 작업해줘야 할것은 어플리케이션폴더 안의 build.gradle파일.


먼저 android gradle 참고할만한 문서 : http://tools.android.com/tech-docs/new-build-system/user-guide


먼저 나의 경우, Free 앱과 Paid앱을 따로 개발할 수는 없고, 단순히 앱 이름과 리소스만 변경하고자할때 이런 빌드 툴이 굉장히 편리하다. 알고 있으면.


그래서 한 일주일간 삽질 해가며 결국 이클립스를 버리고 안드로이드 스튜디오로 왔는데 옮긴 이유가 위에서도 언급했듯이 일단 프로젝트의 구조부터가 다르다. 그래서 gradle을 이용해서 뭔가 해보기가 애매했다. 그냥 옮기니 참 편하드라...?


일단 어플리케이션의 build,gradle을 보면 기본적으로 몇가지가 적혀있는데 gradle 버전 명시와 플러긴(여기서는 안드로이드) 그리고 안드로이드 버전정도가 있다.


gradle의 버전의 경우 현재 기준으론 1.8버전이 최신인데 이 버전은 0.6.+로 기재하면되고 그 이전버전의 경우 0.5정도 하면 될거 같다. 아직 완벽히 아는게 아니라서 왜 버전이 다른지는...



buildscript {

    repositories {

        mavenCentral()

    }

    dependencies {

        classpath 'com.android.tools.build:gradle:0.6.+'

    }

}



apply plugin: 'android'


repositories {

    mavenCentral()

}


// 사용할 안드로이드 sdk버전

android {

    compileSdkVersion 17

    buildToolsVersion "17.0.0"


    defaultConfig {

        minSdkVersion 9

        targetSdkVersion 17

    }




// 키스토어 설정 관련

// 내 경우 free, paid 두개를 동시에 빌드하기 위해서 서로 다른 키카 필요하다.(서로다른 키스토어가 필요하다는 뜻 아님.)

// 그리고 storeFile file() 에 키스토어의 경로를 기재해준다.

// 그리고 키 이름과 스토어 암호, 키 암호를 적어준다.

// 그런데 이렇게 하게 되면 build.gradle을 까보는것만으로도 비번을 알 수 있기에 위험한데 이걸 뭐 따로 저장한다던가 뭐 몇가지 대체하는 방법이 있었음. 여유가 생기면 찾아봐야지.

    signingConfigs {

        freeConfing {

            storeFile file(".../");

            storePassword "password"

            keyAlias "keyname_free"

            keyPassword "keypassword"

        }

        paidConfing {

            storeFile file(".../");

            storePassword "password"

            keyAlias "keyname_paid"

            keyPassword "keypassword"

        }

    }



// 이부분은 빌드를 진행할때 어떤 프로덕트를 생성할 것인지에 대한것을 기술하는거 같음.

// 보면 flavor이름이 paid, free이렇게 있다.

// 그리고 각각의 flavor에서 

// buildConfig -> BuildConfig.java에 대해서 한라인 수정 

// versionCode -> 버전 코드 - 빌드시에 AndroidMenifest.xml에 적용되서 빌드됨. 굳이 매니페스트 파일을 수정 할 필요 없음.

// versionName -> 버전 이름

// signingConfig -> 아까 위에서 정의한 사이닝컨픽. 반드시 이 위에 정의해줘야함...

    productFlavors {

        paid {

            packageName "com.example.myapp"

            buildConfig "public final static boolean isFullVersion = true;"

            versionCode 2

            versionName "1.1"

            signingConfig signingConfigs.paidConfing


        }

        free {

            packageName "com.example.myapp"

            buildConfig "public final static boolean isFullVersion = false;"

            versionCode 2

            versionName "1.1

            signingConfig signingConfigs.freeConfing

        }

    }

}


dependencies {

    compile 'com.android.support:appcompat-v7:+'

}



터미널에서   gradle을 빌드할땐 그냥 gradle build하면 빌드를 진행함.


기존의 apk등등 모두 지우고 새로 빌드할땐 gradle clean build해주면 됨.


일단 플래그 변경으로 어플리케이션 내부의 동작을 변경 할 수 있지만(이건 그냥 이클립스에서 할때도 됨.) 리소스의 경우는 조금 다르다.


먼저 src/main, src/res등의 폴더가 있는데 src폴더 하위에 free, paid폴더를 만들고 각각의 리소스를 경로에 맞게 넣어주면 빌드시에 해당 flavor을 찾아서 빌드한다.

따라서 각각 다른 리소스를 사용 할 수 있다. 



하다가 갑자기 com.example.myapp.R을 못 읽어온다고 할 수 있는데 이때는 프로젝트 설정에 들어가서 R.java가 포함된 폴더를 Source폴더로 설정해주면됨.


단점이 있다면 뭔가 용량이 늘어났다. 뭐때문인진 모르는데,,,기존 약 500kb에서 현재 1.2mb로 늘어났다.

라이브러리 포함도 안시켰는데도 이럼....ㅅㅂ


저작자 표시 비영리 변경 금지
신고
Trackback 0 Comment 0


티스토리 툴바