java.util.UnknownFormatConversionException 문제
strings.xml
파일을 수정하고 애플리케이션을 실행하던 도중, 다음과 같은 예외 문제가 발생하면서 앱이 강제로 종료되었습니다.
2019-08-06 12:44:51.056 11935-11935/com.company.appname E/AndroidRuntime: FATAL EXCEPTION: main Process: com.company.appname, PID: 11935 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.company.appname/com.company.appname.MyActivity}: java.util.UnknownFormatConversionException: Conversion = ')' at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048) at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78) at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:193) at android.app.ActivityThread.main(ActivityThread.java:6669) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) Caused by: java.util.UnknownFormatConversionException: Conversion = ')' at java.util.Formatter$FormatSpecifier.conversion(Formatter.java:2781) at java.util.Formatter$FormatSpecifier.<init>(Formatter.java:2811) at java.util.Formatter$FormatSpecifierParser.<init>(Formatter.java:2624) at java.util.Formatter.parse(Formatter.java:2557) at java.util.Formatter.format(Formatter.java:2504) at java.util.Formatter.format(Formatter.java:2458) at java.lang.String.format(String.java:2883) at android.content.res.Resources.getString(Resources.java:466) at android.content.Context.getString(Context.java:594) at com.company.appname.StringUtils.setSpanTextWithStrings(StringUtils.java:47) at com.company.appname.MyActivity.onCreate(MyActivity.java:34) at android.app.Activity.performCreate(Activity.java:7136) at android.app.Activity.performCreate(Activity.java:7127) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048) at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78) at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:193) at android.app.ActivityThread.main(ActivityThread.java:6669) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) 2019-08-06 12:44:51.077 11935-11935/com.company.appname I/Process: Sending signal. PID: 11935 SIG: 9
상단 부분을 살펴보면 대략 다음과 같은 문제임을 알 수 있습니다.
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.company.appname/com.company.appname.MyActivity}: java.util.UnknownFormatConversionException: Conversion = ')'
특정 액티비티에서 String.format
메소드에 의해 알 수 없는 포맷을 참조하려 하다가 문제가 발생한 것으로 보입니다. strings.xml
의 어디선가 발생한 포맷 에러인 것 같습니다.
해결 방법
이 문제는 다양한 원인 (잘못된 문자열 포맷)으로 인해 발생할 수 있기 때문에 여기에 있는 해결책으로 해결되지 않을 수 있습니다. 가장 좋은 방법은 문제가 발생한 시점에 strings.xml
에서 수정한 내용을 살펴보는 것입니다.
먼저 퍼센트 기호를 잘못 사용한 경우입니다. 다음 예시를 확인해보겠습니다.
<resources> <string name="today">오늘의 달성률은 100%입니다.</string> </resources>
특별한 문제가 없어보이지만, 문제는 퍼센트 기호(%
)에 있었습니다. String.format
메소드를 사용할 때는 strings.xml
에서 퍼센트 기호를 사용할 때 일반적으로 사용하듯이 %
를 사용해서는 안되며, 이스케이프 문자(\
)를 사용해도 마찬가지입니다.
이럴 때는 %
대신 %%
기호를 붙이면 해결됩니다. 퍼센트 기호를 하나 더 붙이면 에러가 발생하지 않을 것입니다.
<!-- 문제가 없는 코드 --> <resources> <string name="today">오늘의 달성률은 100%%입니다.</string> </resources>
다음으로 아래와 같이 %d
, %s
와 같은 정수와 문자열 포맷 이외에 존재하지 않는 포맷을 사용하려 하는 경우에도 문제가 발생합니다. (퍼센트 기호를 위와 같이 두 개를 사용하지 않는 것과 같은 현상입니다.)
<resources> <string name="today">오늘의 달성률은 100%percent</string> </resources>
또는 다음과 같이 실수형 포맷을 잘못 사용하는 경우도 있습니다.
<resources> <string name="result">소수 표현: %3.f</string> </resources>
실수형 포맷은 %.2f
혹은 %2.4f
(숫자는 임의)와 같은 형식으로 사용되어야 합니다. 여기서 콤마(.
)의 좌측 숫자는 폭(전체 수치의 영역 크기), 우측 숫자는 소수점의 자리수에 해당합니다. 위 예시에서의 %3.f
와 같이 소수점 자리수가 없을 때는 .
이 있어서는 안됩니다.