액티비티던 뷰모델이던 기본이 중요하지
- BaseActivity란 여러 Activity를 사용할 때 중복되는 코드를 미리 정의하여
필요한 코드만 구현하도록 사용하는 기본 액티비티입니다.
말로만 설명하면 이해하기 힘드니까 코드로 살펴보면
abstract class BaseActivity<T: ViewDataBinding, R: BaseViewModel>: AppCompatActivity() {
lateinit var binding: T // 데이터 바인딩
abstract val TAG :String // 액티비티 태그
abstract val layoutRes: Int // 바인딩에 필요한 layout
abstract val viewModel: R // 뷰모델
lateinit var timer: TimeCheckService
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.i(TAG,"onCreate")
binding = DataBindingUtil.setContentView(this, layoutRes)
timer = TimeCheckService(this, viewModel.countTime,1000)
setMarketInfo()
setDisplayBind()
setRv()
}
override fun onRestart() {
super.onRestart()
Log.i(TAG,"onRestart")
}
override fun onStart() {
super.onStart()
Log.i(TAG,"onStart")
}
override fun onResume() {
super.onResume()
Log.i(TAG,"onResume")
}
override fun onPause() {
super.onPause()
Log.i(TAG,"onPause")
}
override fun onStop() {
super.onStop()
Log.i(TAG,"onStop")
}
override fun onDestroy() {
super.onDestroy()
Log.i(TAG,"onDestroy")
}
open fun setDisplayBind(){
}
open fun setMarketInfo(){
}
fun startTimer(){
if (!timer.isRunning){
timer.isRunning = true
timer.start()
}
}
fun stopTimer(){
if (timer.isRunning){
timer.isRunning = false
timer.time = 1
timer.cancel()
}
}
fun resetTimer(){
stopTimer()
startTimer()
}
override fun onTouchEvent(event: MotionEvent?): Boolean {
when (event?.action) {
MotionEvent.ACTION_DOWN -> if (timer.isRunning){
println("다운")
}
MotionEvent.ACTION_UP -> if (timer.isRunning){
println("업")
}
MotionEvent.ACTION_MOVE -> if (timer.isRunning){
println("무브")
}
}
return super.onTouchEvent(event)
}
/**
* 리사이클러뷰를 셋팅
*/
@SuppressLint("UseCompatLoadingForDrawables")
open fun setRv(){
}
}
위의 코드에서 살펴보면 abstract로 선언하여 추상 클래스로 구현하고 AppCompatActivity()
를 상속받으며 T: ViewDataBinding, R: BaseViewModel
을 사용하여 데이터 바인딩과 뷰모델을 편리하게 사용할 수 있습니다.
데이터 바인딩 같은 경우에는 lateinit var binding: T
로 늦은 초기화를 사용하여
onCreate
함수에서 binding = DataBindingUtil.setContentView(this, layoutRes)
로 layout을 받아 바인딩 객체를 생성합니다.
또한 액티비티마다 중복되는 함수를 필요한 부분에 선언하여 불필요한 코드를 줄일 수 있습니다. 예를 들면 open클래스나 생명주기 함수들을 선언하여 생명주기 함수가 호출될 때 Log를 찍도록 미리 선언 해줄 수 있습니다.
이때 코틀린에서 함수는 open fun setDisplayBind(){}
이런식으로 앞에 open을 붙여 상속이 가능하도록 만들어야 합니다.
이제 MainActivity에서 위의 BaseActivity를 상속받는 코드를 보겠습니다.
class MainActivity : BaseActivity<ActivityMainBinding, MainViewModel>() {
override val TAG : String = MainActivity::class.java.simpleName
override val layoutRes: Int = R.layout.activity_main
override val viewModel: MainViewModel by inject()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.i(TAG,"onCreate")
// binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
// viewModel = ViewModelProvider(this, MainViewModel.Factory(application)).get(MainViewModel::class.java)
}
}
위와 같은 식으로 TAG, layoutRes, viewModel등의 추상 변수를 override하여 정의해 줍니다.
보통 데이터 바인딩과 뷰모델을 사용하면 onCreate()
에서 초기화해주는데 BaseActivity를 상속받았기 때문에 binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
이 부분은 주석처리 했고 viewModel
부분은 di를 사용하여 주석처리를 하였습니다. onCreate를 제외한 다른 생명주기 함수를 선언하지 않아도 BaseActivity에서 Log 코드를 적었기 때문에 MainActivity의 로그를 살펴보면 각 생명주기가 호출될 때 Log가 찍히는 것을 볼 수 있습니다.