4th Development Log
💡 멀티스레드를 활용하여 앱 만들어보기
- 게임, 플레이어, 네트워크 활용 등 활용 방식은 무관
✔️ 실습 영상
https://youtu.be/1wZzW1abDm4
✔️ 레퍼런스
-
DiffUtil(Recyclerview 관련)
https://thdev.tech/kotlin/2020/09/22/kotlin_effective_03/ -
게임 에셋 참고 자료
- https://gall.dcinside.com/mgallery/board/view/?id=game_dev&no=14403
여기에 에셋 사이트와 게임 그래픽에 대해 잘 정리되어 있어요! - https://itch.io/game-assets/free
이 사이트는 2D 에셋 위주고 다운받기 쉬워서 가장 사용하기 좋아요. - https://craftpix.net/
여기는 퀄리티는 좋은데 유료가 좀 많은 편이에요. - https://opengameart.org/
여기는 에셋 사이트 중에서 오래 된 편이고 유명하긴 한데 사이트가 좀 불편해보여서 저는 사용해본 적이 없습니다. - https://www.epidemicsound.com/music/featured/
여기는 배경음악 올라가는 사이트인데 간단하게 가입만 하면 좋은 노래가 많아서 괜찮은 사이트에요! - https://bgmstore.net/
국내 bgm 사이트로 접근성이 좋습니다! - 이 외에도 구글에서 free game asset 이나 free game bgm 으로 검색
- https://gall.dcinside.com/mgallery/board/view/?id=game_dev&no=14403
SharedPreferences
Context.getSharedPreferences(String, int)
에서 반환된 기본 설정 데이터에 액세스하고 수정하기 위한 인터페이스
- 앱의 데이터를 저장 및 관리해야 할 때 그 데이터가 중요한 데이터가 아닌 간단한 설정값이나 문자열 등일 경우, DB 에 저장하는 대신 안드로이드에서 기본적으로 제공하는 SharedPreferences 를 사용하여 관리하면 편리함
- 데이터를 타입에 따라 관리하며, 데이터는 앱 내 폴더에 파일로 저장되므로 앱을 삭제하면 데이터도 삭제됨
private fun setScore() {
val score = intent.extras!!.getInt("score")
val sharedPreference = getSharedPreferences("ScoreInformation", 0)
var highestScore = sharedPreference.getInt("HighestScore", 0)
val editor = sharedPreference.edit()
if (score > highestScore) {
highestScore = score
editor.putInt("HighestScore", highestScore)
editor.apply()
}
tvScore = findViewById(R.id.tv_initialScore)
tvHighestScore = findViewById(R.id.tv_initialHighestScore)
tvScore!!.text = score.toString()
tvHighestScore!!.text = highestScore.toString()
}
companion object
어떤 클래스의 모든 인스턴스가 공유하는 객체를 만들고 싶을 때 사용
- java 와 달리 kotlin 에는 static 이 없음, 클래스 인스턴스 없이 어떤 클래스 내부에 접근하고 싶다면 클래스 내부에 객체를 선언할 때 companion object 를 사용하면 됨
- 클래스 당 하나만 가질 수 있음
@JvmStatic
Companion 에 등록된 변수를 자바의 static 처럼 선언하기 위한 annotation
static 변수의get()
/set()
함수를 자동으로 만들라는 의미
//나는 이런 식으로 사용했다!
companion object {
var screenWidth: Int = 0
var screenHeight: Int = 0
@JvmStatic
var spaceShipWidth: Int = 0
@JvmStatic
var spaceShipHeight: Int = 0
}
screenWidth = point.x
screenHeight = point.y
spaceShipWidth = spaceShip.width //== spaceShip.getWidth()
spaceShipHeight = spaceShip.height //== spaceShip.getHeight()
onDraw()
커스텀 뷰 그리기에서 가장 중요한 단계는 onDraw()
메서드를 재정의하는 것
onDraw()
의 매개변수는 뷰에서 자기 자신을 그릴 때 사용할 수 있는 Canvas 객체onDraw()
를 호출하려면 먼저 Paint 객체를 만들어야 함- Paint
- android.graphics 프레임워크는 그리기 작업을 두 영역으로 나눈다
- 그리는 내용(Canvas에서 처리)
- 그리기 방법(Paint에서 처리)
- ex) Canvas 는 선을 그릴 수 있는 메서드를 제공하고 Paint 는 선의 색상을 정의하는 메서드를 제공한다. Canvas 에는 직사각형을 그리는 메서드가 있는 반면 Paint 는 직사각형을 색으로 채울지 또는 비워 둘지 정의한다. 간단히 말해, Canvas 는 화면에 그릴 수 있는 도형을 정의하고, Paint 는 그리는 각 도형의 색상, 스타일, 글꼴 등을 정의한다.
-> 따라서, 무엇을 그리기 전에 하나 이상의 Paint 객체를 만들어야 한다.
- ex) Canvas 는 선을 그릴 수 있는 메서드를 제공하고 Paint 는 선의 색상을 정의하는 메서드를 제공한다. Canvas 에는 직사각형을 그리는 메서드가 있는 반면 Paint 는 직사각형을 색으로 채울지 또는 비워 둘지 정의한다. 간단히 말해, Canvas 는 화면에 그릴 수 있는 도형을 정의하고, Paint 는 그리는 각 도형의 색상, 스타일, 글꼴 등을 정의한다.
- Paint
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
canvas.drawBitmap(spaceShip, spaceShipX, spaceShipY, null)
canvas.drawText("Score: " + (hitTargetCount * 10), 0f, TEXT_SIZE.toFloat(), scorePaint)
canvas.drawRect(
(screenWidth - 130).toFloat(),
10f,
(screenWidth - 130 + 10 * lives).toFloat(),
TEXT_SIZE.toFloat(),
healthPaint
)
handlerObject.postDelayed(runnable, UPDATE_MILLI_SECONDS)
}
개체를 미리 만드는 것은 중요한 최적화 작업이다. 뷰를 다시 그리는 경우는 매우 자주 발생하며 다수의 그리기 객체는 많은 비용을 들여 초기화해야 한다. 따라서, onDraw()
내에서 그리기 객체를 만들면 성능이 크게 저하되고 UI 가 느리게 표시될 수 있다.
Thread, Handler
스레드란 하나의 프로세스 안에서 실행되는 여러 흐름의 단위
- 메인 스레드 이외의 스레드는 UI를 업데이트할 수 없음(접근할 수 없음)
- ANR 발생 가능
단일 스레드에서 앱이 리소스를 많이 소모하는 작업을 수행하는 경우, 네트워크 액세스나 데이터베이스 쿼리 등의 긴 작업을 수행할 때 전체 UI가 차단된다. 스레드가 차단되면 모든 이벤트가 발생하지 않아 사용자에게는 애플리케이션이 중단된 것처럼 보인다. 심각한 경우, UI 스레드가 몇 초 이상 차단되면(현재 약 5초) 사용자에게 "애플리케이션이 응답하지 않습니다"(ANR)라는 대화상자가 표시될 수 있다.- Handler
- 메인 스레드 이외의 스레드에서도 UI 를 변경 가능하게 해줌(접근은 역시 불가능)
- 자신의 스레드와 다른 스레드에서 수행할 작업을 대기열에 추가하여 순서대로 처리함
- Handler
var mediaPlayer: MediaPlayer? = null
private var handler = Handler(Looper.getMainLooper())
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
thread {
handler.post {
mediaPlayer = MediaPlayer.create(this, R.raw.background_music)
mediaPlayer!!.isLooping //무한재생
mediaPlayer!!.start()
}
}
}
cf. 스레드와 관련한 간단한 예제는 https://velog.io/@morgankim/4th-Development-Practice 참고!
➕ AsyncTask 사용해보기!
MediaPlayer
- SoundPool
- 장점
짧은 사운드 재생에 효과적 (10초 내)
사운드 연타 구현 가능 - 단점
긴 사운드 재생 불가
3gp 재생불가, mp3 재생 불안정, ogg 재생은 안정적
- 장점
- MediaPlayer
- 장점
긴 사운드 재생에 효과적 - 단점
연타 처리의 어려움
- 장점
Author And Source
이 문제에 관하여(4th Development Log), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@morgankim/4th-Development-Log저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)