오늘은 간단하게 코틀린(Kotlin)에서 시계 만드는 방법을 알아보겠습니다. 대부분 개발 언어에서 시계를 만들기 위해서는 Thread를 사용해서 시간을 확인하는 로직을 많이 사용합니다. 하지만, Android에서는 Thread를 사용하지 않고 Widget만을 사용해서 시계를 구현할 수 있습니다.
특별한 코드 없이 Activity_main.xml에 TextClock를 선언하면 바로 시계가 동작합니다.
"java.lang.IllegalStateException: This Activity already has an action bar supplied by the window decor. Do not request Window.FEATURE_SUPPORT_ACTION_BAR and set windowActionBar to false in your theme to use a Toolbar instead"
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.office.secuex/com.office.secuex.SecuExplorer}: java.lang.IllegalStateException: This Activity already has an action bar supplied by the window decor. Do not request Window.FEATURE_SUPPORT_ACTION_BAR and set windowActionBar to false in your theme to use a Toolbar instead.
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3270)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Caused by: java.lang.IllegalStateException: This Activity already has an action bar supplied by the window decor. Do not request Window.FEATURE_SUPPORT_ACTION_BAR and set windowActionBar to false in your theme to use a Toolbar instead.
at androidx.appcompat.app.AppCompatDelegateImpl.setSupportActionBar(AppCompatDelegateImpl.java:345)
at androidx.appcompat.app.AppCompatActivity.setSupportActionBar(AppCompatActivity.java:130)
at com.office.secuex.SecuExplorer.initViews(SecuExplorer.kt:67)
at com.office.secuex.SecuExplorer.onCreate(SecuExplorer.kt:40)
at android.app.Activity.performCreate(Activity.java:7802)
at android.app.Activity.performCreate(Activity.java:7791)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1299)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3245)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
상기 오류는 toolbar가 먼저 구성되어 있는 상태에서 추가를 할 경우 발생하는 오류 입니다.
at android.app.Activity.performCreate(Activity.java:7802)
at android.app.Activity.performCreate(Activity.java:7791)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1299)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3245)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
E/AndroidRuntime: Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.android.material.appbar.AppBarLayout" on path: DexPathList
먼저 InputStream을 사용해서 생성한 폴더 assets에 접근해서 XML 파일을 open 합니다.
XmlPullParserFactory를 사용해서 신규 인터페이스를 생성합니다.
XmlPullParser를 생성해서 factory와 연결 후 xml파일을 로드합니다.
var xmlinfo:InputStream = assets.open("info.xml")
var factory:XmlPullParserFactory = XmlPullParserFactory.newInstance()
var parser:XmlPullParser = factory.newPullParser()
parser.setInput( xmlinfo, null)
전체 XML 파일을 확인하기 위해서 타입을 확인하고 END_DOCUMENT까지 로드를 반복합니다.
설정한 tag는 "bookinfo"이므로 if 문에서 "bookinfo"일 경우만 getAttributeValue를 사용해서 하위 로드에 접근합니다.
class Builder{
var path : String = ""
fun build(): FilesListFragment{
val fragment = FilesListFragment()
val args = Bundle()
args.putString(ARG_PATH, path)
fragment.arguments = args;
return fragment
}
}
package com.office.secuex.common
import java.io.File
enum class FileType {
FILE,
FOLDER;
companion object{
fun getFileType(file: File) = when(file.isDirectory){
true -> FOLDER
false -> FILE
}
}
}
data class FileModel(
val path : String,
val fileType : FileType,
val name : String,
val sizeInMB: Double,
val extension: String ="",
val subFiles: Int = 0
)