====== android studio ======
===== Mac =====
Android studio를 Mac에서 설치/사용하기 위해서는 JRE(Java Runtime Environment) 6를 설치하고 7또는 8버전 JDK를 추가로 설치해야 한다.
-> Android studio 실행시 JRE6(java 6)를 이용해야 폰트 렌더링이 정확히 동작한다고 한다. (java 7, 8에서는 앤티-에일리어싱에 문제가 있음)
Mac에서 android studio를 사용할 때는 java 6 버전, java 7 또는 상위 버전을 두개 설치해 사용하자.
관련 자료: [[http://tools.android.com/tech-docs/configuration/osx-jdk|Mac OSX JDK Selection]]
위 자료를 보고 java 6를 설치하고, oracle 홈페이지에서 java 8(JDK 8)을 설치했다. (2016년 4월 16)
==== 단축키 ====
줄 처음으로 이동: Command + <-
줄 끝으로 이동: Command + ->
단어 단위로 앞으로 이동: Option(Alt) + <-
단어 단위로 뒤로 이동: Option(Alt) + ->
show method signature: Command + P
===== Troubleshooting =====
==== java.lang.VerifyError: Bad return type ====
Android Studio 에서 Robolectric 라이브러리를 사용해 unit test 코드를 작성한 후
Run test code with coverage 를 실행할 경우 아래와 같은 에러 메시지가 표시된다.
* 단일 테스트 클래스를 With coverage 로 실행시는 오류가 안나지만, 전체 테스트 클래스 코드를 함께 실행 시킬 경우 발생한다.
---- IntelliJ IDEA coverage runner ----
sampling ...
include patterns:
exclude patterns:[Robolectric] com.example.myunittest.PhoneUtilTest.dummyTest: sdk=28; resources=BINARY
Called loadFromPath(/system/framework/framework-res.apk, true); mode=binary sdk=28
java.lang.VerifyError: Bad return type
Exception Details:
Location:
android/content/res/ResourcesImpl.$$robo$$android_content_res_ResourcesImpl$loadComplexColorForCookie(Landroid/content/res/Resources;Landroid/util/TypedValue;ILandroid/content/res/Resources$Theme;)Landroid/content/res/ComplexColor; @565: areturn
Reason:
Type 'java/lang/Object' (current frame, stack[0]) is not assignable to 'android/content/res/ComplexColor' (from method signature)
Current Frame:
bci: @565
flags: { }
locals: { 'android/content/res/ResourcesImpl', 'android/content/res/Resources', 'android/util/TypedValue', integer, 'android/content/res/Resources$Theme', 'java/lang/Object', 'java/lang/String', 'java/lang/Object', 'android/content/res/XmlResourceParser', 'android/util/AttributeSet', integer, 'java/lang/String' }
stack: { 'java/lang/Object' }
Bytecode:
0x0000000: 128a b800 903a 0519 0511 0437 b800 942c
0x0000010: b401 b1c7 002a 1905 1104 38b8 0094 bb04
0x0000020: 4359 bb01 2359 b701 2413 0445 b601 2a2c
0x0000030: b402 b9b6 0187 b601 34b7 0446 bf19 0511
0x0000040: 043c b800 942c b401 b1b9 01b2 0100 3a06
0x0000050: 1905 1104 4db8 0094 013a 0719 0511 044f
0x0000060: b800 9414 01d6 1906 b801 df19 0511 0450
0x0000070: b800 9419 0613 0393 b603 9799 0154 1905
0x0000080: 1104 52b8 0094 2a19 061d 2cb4 01af 1304
0x0000090: 48b6 039b 3a08 1905 1104 55b8 0094 1908
0x00000a0: b804 4e3a 0919 0511 0457 b800 9419 08b9
0x00000b0: 0451 0100 5936 0a05 9f00 0c15 0a04 9f00
0x00000c0: 06a7 ffe4 1905 1104 5bb8 0094 150a 059f
0x00000d0: 0016 1905 1104 5cb8 0094 bb03 d759 1304
0x00000e0: 53b7 0454 bf19 0511 045f b800 9419 08b9
0x00000f0: 0457 0100 3a0b 1905 1104 60b8 0094 190b
0x0000100: 1304 59b6 019a 9900 1a19 0511 0461 b800
0x0000110: 942b 1908 1909 1904 b804 5f3a 07a7 002a
0x0000120: 1905 1104 62b8 0094 190b 1304 61b6 019a
0x0000130: 9900 1719 0511 0463 b800 942b 1908 1909
0x0000140: 1904 b804 643a 0719 0511 0465 b800 9419
0x0000150: 08b9 03a2 0100 1905 1104 6db8 0094 a700
0x0000160: bf19 0511 0466 b800 943a 0819 0511 0467
0x0000170: b800 9414 01d6 b802 6919 0511 0468 b800
0x0000180: 94bb 0016 59bb 0123 59b7 0124 1301 b8b6
0x0000190: 012a 1906 b601 2a13 0466 b601 2a1d 1905
0x00001a0: 1104 6ab8 0094 b801 30b6 012a b601 34b7
0x00001b0: 0137 3a09 1905 1104 6bb8 0094 1909 1908
0x00001c0: b601 cc57 1905 1104 6cb8 0094 1909 bf19
0x00001d0: 0511 046f b800 9414 01d6 b802 6919 0511
0x00001e0: 0470 b800 94bb 0016 59bb 0123 59b7 0124
0x00001f0: 1301 b8b6 012a 1906 b601 2a13 01ba b601
0x0000200: 2a1d 1905 1104 72b8 0094 b801 30b6 012a
0x0000210: 1304 30b6 012a b601 34b7 0137 bf19 0511
0x0000220: 0474 b800 9414 01d6 b802 6919 0511 0476
0x0000230: b800 9419 07b0
Exception Handler Table:
bci [126, 342] => handler: 353
Stackmap Table:
append_frame(@61,Object[#4])
full_frame(@165,{Object[#2],Object[#24],Object[#428],Integer,Object[#27],Object[#4],Object[#208],Null,Object[#929],Object[#1131]},{})
append_frame(@196,Integer)
same_frame(@229)
append_frame(@288,Object[#208])
full_frame(@327,{Object[#2],Object[#24],Object[#428],Integer,Object[#27],Object[#4],Object[#208],Object[#4],Object[#929],Object[#1131],Integer,Object[#208]},{})
full_frame(@353,{Object[#2],Object[#24],Object[#428],Integer,Object[#27],Object[#4],Object[#208],Object[#4]},{Object[#335]})
full_frame(@463,{Object[#2],Object[#24],Object[#428],Integer,Object[#27],Object[#4],Object[#208],Null},{})
full_frame(@541,{Object[#2],Object[#24],Object[#428],Integer,Object[#27],Object[#4],Object[#208],Object[#4],Object[#929],Object[#1131],Integer,Object[#208]},{})
at android.content.res.Resources.__constructor__(Resources.java:228)
at android.content.res.Resources.(Resources.java)
at android.content.pm.PackageParser.parseBaseApk(PackageParser.java:1334)
at android.content.pm.PackageParser.parseMonolithicPackage(PackageParser.java:1299)
at android.content.pm.PackageParser.parsePackage(PackageParser.java:1022)
at android.content.pm.PackageParser.parsePackage(PackageParser.java:1042)
at org.robolectric.shadows.ShadowPackageParser.callParsePackage(ShadowPackageParser.java:41)
at org.robolectric.android.internal.AndroidEnvironment.loadAppPackage_measured(AndroidEnvironment.java:291)
at org.robolectric.android.internal.AndroidEnvironment.lambda$loadAppPackage$1(AndroidEnvironment.java:261)
at org.robolectric.util.PerfStatsCollector.measure(PerfStatsCollector.java:53)
at org.robolectric.android.internal.AndroidEnvironment.loadAppPackage(AndroidEnvironment.java:259)
at org.robolectric.android.internal.AndroidEnvironment.installAndCreateApplication(AndroidEnvironment.java:158)
at org.robolectric.android.internal.AndroidEnvironment.setUpApplicationState(AndroidEnvironment.java:149)
at org.robolectric.RobolectricTestRunner.beforeTest(RobolectricTestRunner.java:298)
at org.robolectric.internal.SandboxTestRunner$2.lambda$evaluate$0(SandboxTestRunner.java:247)
at org.robolectric.internal.bytecode.Sandbox.lambda$runOnMainThread$0(Sandbox.java:89)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
[Robolectric] com.example.myunittest.PhoneUtilTest.getImeiJsonArray: sdk=28; resources=BINARY
java.lang.VerifyError: Bad return type
Exception Details:
Location:
android/content/res/ResourcesImpl.$$robo$$android_content_res_ResourcesImpl$loadComplexColorForCookie(Landroid/content/res/Resources;Landroid/util/TypedValue;ILandroid/content/res/Resources$Theme;)Landroid/content/res/ComplexColor; @565: areturn
Reason:
Type 'java/lang/Object' (current frame, stack[0]) is not assignable to 'android/content/res/ComplexColor' (from method signature)
Current Frame:
bci: @565
flags: { }
locals: { 'android/content/res/ResourcesImpl', 'android/content/res/Resources', 'android/util/TypedValue', integer, 'android/content/res/Resources$Theme', 'java/lang/Object', 'java/lang/String', 'java/lang/Object', 'android/content/res/XmlResourceParser', 'android/util/AttributeSet', integer, 'java/lang/String' }
stack: { 'java/lang/Object' }
Bytecode:
0x0000000: 128a b800 903a 0519 0511 0437 b800 942c
0x0000010: b401 b1c7 002a 1905 1104 38b8 0094 bb04
0x0000020: 4359 bb01 2359 b701 2413 0445 b601 2a2c
0x0000030: b402 b9b6 0187 b601 34b7 0446 bf19 0511
0x0000040: 043c b800 942c b401 b1b9 01b2 0100 3a06
0x0000050: 1905 1104 4db8 0094 013a 0719 0511 044f
0x0000060: b800 9414 01d6 1906 b801 df19 0511 0450
0x0000070: b800 9419 0613 0393 b603 9799 0154 1905
0x0000080: 1104 52b8 0094 2a19 061d 2cb4 01af 1304
0x0000090: 48b6 039b 3a08 1905 1104 55b8 0094 1908
0x00000a0: b804 4e3a 0919 0511 0457 b800 9419 08b9
0x00000b0: 0451 0100 5936 0a05 9f00 0c15 0a04 9f00
0x00000c0: 06a7 ffe4 1905 1104 5bb8 0094 150a 059f
0x00000d0: 0016 1905 1104 5cb8 0094 bb03 d759 1304
0x00000e0: 53b7 0454 bf19 0511 045f b800 9419 08b9
0x00000f0: 0457 0100 3a0b 1905 1104 60b8 0094 190b
0x0000100: 1304 59b6 019a 9900 1a19 0511 0461 b800
0x0000110: 942b 1908 1909 1904 b804 5f3a 07a7 002a
0x0000120: 1905 1104 62b8 0094 190b 1304 61b6 019a
0x0000130: 9900 1719 0511 0463 b800 942b 1908 1909
0x0000140: 1904 b804 643a 0719 0511 0465 b800 9419
0x0000150: 08b9 03a2 0100 1905 1104 6db8 0094 a700
0x0000160: bf19 0511 0466 b800 943a 0819 0511 0467
0x0000170: b800 9414 01d6 b802 6919 0511 0468 b800
0x0000180: 94bb 0016 59bb 0123 59b7 0124 1301 b8b6
0x0000190: 012a 1906 b601 2a13 0466 b601 2a1d 1905
0x00001a0: 1104 6ab8 0094 b801 30b6 012a b601 34b7
0x00001b0: 0137 3a09 1905 1104 6bb8 0094 1909 1908
0x00001c0: b601 cc57 1905 1104 6cb8 0094 1909 bf19
0x00001d0: 0511 046f b800 9414 01d6 b802 6919 0511
0x00001e0: 0470 b800 94bb 0016 59bb 0123 59b7 0124
0x00001f0: 1301 b8b6 012a 1906 b601 2a13 01ba b601
0x0000200: 2a1d 1905 1104 72b8 0094 b801 30b6 012a
0x0000210: 1304 30b6 012a b601 34b7 0137 bf19 0511
0x0000220: 0474 b800 9414 01d6 b802 6919 0511 0476
0x0000230: b800 9419 07b0
Exception Handler Table:
bci [126, 342] => handler: 353
Stackmap Table:
append_frame(@61,Object[#4])
full_frame(@165,{Object[#2],Object[#24],Object[#428],Integer,Object[#27],Object[#4],Object[#208],Null,Object[#929],Object[#1131]},{})
append_frame(@196,Integer)
same_frame(@229)
append_frame(@288,Object[#208])
full_frame(@327,{Object[#2],Object[#24],Object[#428],Integer,Object[#27],Object[#4],Object[#208],Object[#4],Object[#929],Object[#1131],Integer,Object[#208]},{})
full_frame(@353,{Object[#2],Object[#24],Object[#428],Integer,Object[#27],Object[#4],Object[#208],Object[#4]},{Object[#335]})
full_frame(@463,{Object[#2],Object[#24],Object[#428],Integer,Object[#27],Object[#4],Object[#208],Null},{})
full_frame(@541,{Object[#2],Object[#24],Object[#428],Integer,Object[#27],Object[#4],Object[#208],Object[#4],Object[#929],Object[#1131],Integer,Object[#208]},{})
at android.content.res.Resources.__constructor__(Resources.java:228)
at android.content.res.Resources.(Resources.java)
at android.content.pm.PackageParser.parseBaseApk(PackageParser.java:1334)
at android.content.pm.PackageParser.parseMonolithicPackage(PackageParser.java:1299)
at android.content.pm.PackageParser.parsePackage(PackageParser.java:1022)
at android.content.pm.PackageParser.parsePackage(PackageParser.java:1042)
at org.robolectric.shadows.ShadowPackageParser.callParsePackage(ShadowPackageParser.java:41)
at org.robolectric.android.internal.AndroidEnvironment.loadAppPackage_measured(AndroidEnvironment.java:291)
at org.robolectric.android.internal.AndroidEnvironment.lambda$loadAppPackage$1(AndroidEnvironment.java:261)
at org.robolectric.util.PerfStatsCollector.measure(PerfStatsCollector.java:53)
at org.robolectric.android.internal.AndroidEnvironment.loadAppPackage(AndroidEnvironment.java:259)
at org.robolectric.android.internal.AndroidEnvironment.installAndCreateApplication(AndroidEnvironment.java:158)
at org.robolectric.android.internal.AndroidEnvironment.setUpApplicationState(AndroidEnvironment.java:149)
at org.robolectric.RobolectricTestRunner.beforeTest(RobolectricTestRunner.java:298)
at org.robolectric.internal.SandboxTestRunner$2.lambda$evaluate$0(SandboxTestRunner.java:247)
at org.robolectric.internal.bytecode.Sandbox.lambda$runOnMainThread$0(Sandbox.java:89)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Class transformation time: 2.124387851s for 7295 classes or 2.91211494311172E-4s per class
Process finished with exit code 255
임시 해결 방법 3가지:
- Coverage 도구를 JaCoCo 로 변경 : Run > Edit Configurations.. > 관련 Run 항목 선택 > Code Coverage 선택 > Choose coverage runner: IntelliJ IDEA -> JaCoCo 로 변경
- -noverify 옵션 추가 : Run > Edit Configurations.. > 관련 Run 항목 선택 > Configuration 선택 > VM Options 에 '-noverify' 옵션 추가
관련 Issue link: https://github.com/robolectric/robolectric/issues/3023
리포트된 이슈 글타래를 보면 아직 해결이 안된 상태다.
특이사항
JaCoCo 선택후 실행시 대상 코드가 실행되었으나 커버리지에는 측정되지 않는 부분이 나왔다.
예를 들면 Robolectric 나, Powermock으로 테스트 한 모듈같은 경우가 측정이 안되었다. (0%로 나오고 실행안된 부분으로 나옴)
JaCoCo에서 PowerMock으로 테스트되는 Code의 Code Coverage 확인 방법이 현재까지는 없다고 한다.
We are going to replace Javassist with ByteBuddy (#727) and it should help to resolve this old issue. But right now there is NO WAY TO USE PowerMock with JaCoCo On-the-fly instrumentation. And no workaround to get code coverage in IDE.
https://github.com/powermock/powermock/wiki/Code-coverage-with-JaCoCo
Robolectric으로 테스트 되는 Code의 code coverage 는 IntelliJ 를 써야 할 듯..
https://stackoverflow.com/questions/35735085/jacoco-doesnt-work-with-robolectric-tests
"-noverify" 옵션
Jvm에서 class를 로딩할 때 bytecode 의 신뢰성을 검증하지 않도록 한다.
Code Coverage를 측정할 때 class byte code를 변형하게 되면 이 byte code verification에 걸리게 되서 문제가 되는 것 같다.
개발 중에만 이 옵션을 사용하고 **절대 production 환경에서는 사용하면 안되는 옵션**으로 보인다.
관련 링크
* https://blogs.oracle.com/buck/never-disable-bytecode-verification-in-a-production-system
* https://github.com/spring-projects/spring-loaded#readme
* https://stackoverflow.com/questions/300639/use-of-noverify-when-launching-java-apps
* https://stackoverflow.com/questions/45936475/why-noverify-added-at-the-end-of-jvm-arguments
==== major version 53 is newer than 52 ====
> Task :app:compileDebugJavaWithJavac
warning: /Users/lindol/.gradle/caches/transforms-2/files-2.1/0147da73be67184dae3524a6fab40462/jetified-basic.jar(kr/lindol/test/Calc.class): major version 53 is newer than 52, the highest major version supported by this compiler.
It is recommended that the compiler be upgraded.
1 warning
/Users/lindol/.gradle/caches/transforms-2/files-2.1/0147da73be67184dae3524a6fab40462/jetified-basic.jar(kr/lindol/test/Calc.class): major version 53 is newer than 52, the highest major version supported by this compiler.
원인: 프로젝트에서 사용하는 class (여기서는 basic.jar 에 포함된 Calc 클래스) 가 현재 컴파일러 (jdk8) 보다 상위의 컴파일러(jdk9)에서 컴파일 됨.
해결방법: jdk8로 .jar library 소스 재빌드??
-Xlint:deprecation
> Task :app:compileDebugJavaWithJavac
Note: /Users/lindol/Job/AndroidStudioProjects/My-Cashbook/MyCashbook/app/src/main/java/kr/lindol/mycashbook/list/CashLogListFragment.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
소스 구현에 deprecated API 를 사용한 부분이 있다.
자세한 내용을 확인 하려면 -Xlint:deprecation을 추가해서 빌드하라는 의미
안드로이드 스튜디오에서는 아래처럼 app/build.gradle 에 추가하면 자세한 내용을 확인 할 수 있다.
allprojects {
...
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
options.compilerArgs << "-Xlint:deprecation"
}
}
}
출처: https://stackoverflow.com/questions/49711773/how-to-recompile-with-xlintdeprecation