-->
대부분 분위기에 맞지 않는 기본 타이틀바를 완전히 없애거나 다른 이미지로 교체하려는 경우가 대부분이다.
인터넷을 검색해보면 많은 방법을 제시하지만 대부분 안드로이드가 제공하는 테마 기능의 사용을 어렵게 만드는 방법 뿐이다. 즉 AndroidManifest.xml에서 타이틀바가 없는 테마로 기본 테마를 교체하거나 코드에서 테마를 직접 지정하는 것인데 별로 좋은 방법은 아니다.
그래서 인터넷에 떠도는 몇 가지 방법을 정리해보고 문제점과 최선의 방법을 정리해볼까 한다. 자세히 읽어보고 가장 좋은 방법이 무엇인지 각자 생각해보면 좋겠다. 참고로 나의 경우에는 마지막 방법이 가장 합리적이고 좋은 방법이라고 생각한다.
AndroidManifest.xml 파일 태그 "@android:style/Theme.NoTitleBar"로 바꿔서 타이틀바를 없애는 방법
이 방법은 application의 전체 테마를 완전히 교체하는 것이다.
이미 개발이 어느 정도 진행 중이라면 기존에 지정되어있던 테마의 값을 알게 모르게 사용하고 있을 것이므로 아마도 개발이 어느 정도 진행된 후에 이 값을 바꾸면 앱이 죽거나 글자 색상이나 배경색 등이 완전히 바뀌어 보이는 부작용이 생긴다.
앱이 실행되지 않고 죽는 건 SDK가 버전업되면서 기본적으로 상속받는 Activity 클래스가 다른 파생 클래스로 바뀌면서 이전 버전과 달라졌기 때문이다. 예외를 발생시키는 태그의 속성으로 android:theme="@style/Theme.AppCompat"를 지정해주면 해결된다.
참고로 "@android:style/Theme.NoTitleBar" 테마는 타이틀바를 없애는 속성 말고는 아무것도 선언되지 않은 테마이다. 아마도 전에 있던 색상 값들이 모두 사라지면서 기본 컨트롤들의 색상이 확 바뀌었을 것이다.
타이틀바도없고 상태바도 없는 Full Screen을 사용하는 테마는 "@android:style/Theme.NoTitleBar.Fullscreen"이므로 기억해두도록 하자.
Activity의 onCreate()에서requestWindowFeature(Window.FEATURE_NO_TITLE)를 호출해주는 방법
주면 되는데 이 방법은 Activity 클래스를 상속하고 있는 경우에는 동작하지만 AppCompatActivity같은 파생 클래스를 상속하는 경우에는 동작하지 않는다. 예전 SDK의 경우에는 기본 생성되는 프로젝트 템플릿들의 액티비티가 Activity 클래스를 상속했지만 요즘 SDK가 버전업이 되면서 AppCompatActivity등 다른 Activity 파생 클래스를 상속하는 경우가 많으므로 만약 동작하지 않는다면 Activity 클래스로 바꿔서 해보면 동작할 것이다. 하지만 다른 Activity 클래스를 상속하도록 하는데는 다 이유가 있으므로 구버전만 지원할 게 아니라면 이 방법은 추천하지 않는다.
이 방법도 Activity의 onCreate() 메소드에서 setTheme(android.R.style.Theme_NoTitleBar)를 호출하는 것이다.
위 그림과 같이 호출해주면 된다. 위의 2번 방법과 다른점은 Activity의 테마를 완전히 교체한다는 것이다. 1번에서 테마를 바꾼 것처럼 완전히 확 바뀐 색상의 Activity의 모습을 보게될 것이다.
게다가 이 방법은 2번의 문제점도 똑같이 적용된다. Activity를 그대로 상속한 경우에는 잘 동작하는데 AppCompatActivity 등의 다른 파생 클래스를 상속한 경우에는 동작하지 않는 경우가 있다. 마찬가지로 Activity로 바꿔서 해보면 동작은 하겠지만 1번과 2번의 문제점을 동시에 가지고 있는 만큼 이 방법도 사용을 권하지 않는다.
내가 추천하는 가장 안전하고 간단한 방법이다. 아마도 이 방법이 가장 정확한 방법일 것이다. 위의 방법들은 예전에는 먹히는 방법들이었지만 그럼에도 불구하고 사실 편법이었을 뿐이다.
방법은 간단하다. 프로젝트 생성 시 기본적으로 생성된 style.xml 파일을 열어서 아래 그림과 같이 하나를 추가하는 것이다.
사실 이 태그가 @android:style/Theme.NoTitleBar 테마가 가진 전부이다. 따라서 이 item 태그만 기본 style에 추가해주면 다른 모든 style은 그대로 이고 타이틀바 제거 속성만 enable 시키게 된다. 즉, 이 item을 추가한 후에도 타이틀바 외에 모든 색상, 스타일 등은 그대로 유지된다. 게다가 최신 SDK에서도 전혀 문제가 없다. 인터넷에 떠도는 수많은 정보들은 이 방법을 잘 다루지 않는다. 하지만 가장 제대로 동작하는 방법이다.
링크텍스트
<style name="AppTheme"
parent="Theme.AppCompat.Light.DarkActionBar">
<item name="windowNoTitle">true</item>
** <item name="android:windowLightStatusBar">true</item>**
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
**<item name="colorPrimaryDark">#FFFFFF</item>**
<item name="colorAccent">@color/colorAccent</item>
</style>
예)
imageView에 test라는 이름의 activity이다 하면
ivtest블라블라
textView에 text라는 이름의 activity이다 하면
tvtext블라블라
++) for u image left 이다 하면, forUImageLeft 이런식으로 띄어쓰는 부분 대문자
left of, right of 보다 start of, end of를 더 많이 쓴다.
콜백 : 이벤트가 발생하면 특정 메서드를 호출해 알려준다(1개)
리스너 : 이벤트가 발생하면 연결된 리스너(핸들러)들에게 이벤트를 전달한다(n개)
콜백을 리스너와 비교하고 콜백은 1개, 리스너는 n개라고 한다.
리스너 : 이벤트 발생 시 사용하는 개념
옵저버 : 변경을 감지하기 위해 사용하는 개념
구현은 둘 다 인터페이스로 하지만 개념 자체가 달라서 확실히 구별해야 한다.
지금까지 공부한 것을 종합해보면 콜백과 리스너란 용어의 뜻이 한번에 와닿진 않는다.
그래도 정리해보자면, 내 생각엔 콜백 메서드란 다른 메서드에 인수로서 전달될 수 있는 함수인 것 같다. 리스너는 이 콜백 메서드를 가진 인터페이스라 할 수 있겠다.
디벨로퍼의 생명주기 문서에도 onStart(), onStop() 등 생명주기 메서드들도 콜백이라고 하니 이것들도 콜백이라 말할 수 있을까? 왜 이것들을 콜백이라 하는지는 더 공부해봐야겠다.
결론 :
리스너 : View.OnClickListener 콜백 메소드 : onClick()
-> 사용자가 어떤 항목을 터치하거나 내비게이션 키나 트랙볼로 항목으로 이동한 후에 엔터키를 눌러서 선택하면 호출된다.
리스너 : View.OnLongClickListener
콜백 메소드 : onLongClick()
-> 사용자가 항목을 터치하여서 일정 시간 동안 그대로 누르고 있으면 발생한다.
리스너 : View.OnFocusChangeListener
콜백 메소드 : onFocusChange()
-> 사용자가 하나의 항목에서 다른 항목으로 포커스를 이동할 때 호출된다.
리스너 : View.OnKeyListener
콜백 메소드 : onKey()
-> 포커스를 가지고 있는 항목 위에서 키를 눌렀다가 놓았을 때 호출된다.
리스너 : View.OnTouchListener
콜백 메소드 : onTouch()
-> 사용자가 터치 이벤트로 간주되는 동작을 한 경우에 호출된다.
리스너 : View.OnCreateContextMenuListener
콜백 메소드 : onCreateContextMenu()
-> 컨텍스트 메뉴가 구축되어 있는 경우에 호출된다.
※ 인텐트란
화면 간 이동과 데이터 전달
인텐트는 앱 컴포넌트가 무엇을 할 것인지를 담는 메시지 객체입니다.
메시지는 의사소통을 하기 위해 보내고 받는 것이지요. 메시지를 사용하는 가장 큰 목적은 다른 액티비티, 서비스, 브로드캐스트 리시버, 컨텐트 프로바이더 등을 실행하는 것입니다.
인텐트는 그들 사이에 데이터를 주고 받기 위한 용도로도 쓰입니다.
OnCreate()는 생성자랑 비슷하다고 생각하면된다. 처음에 액티비티가 생성되었을 때 나온다.
OnStart()는 말그대로 액티비티가 시작되기 직전이라 생각하면된다. OnCreate()와 OnResume() 사이의 순서에 있다.
OnResume()은 OnStart와 비슷한데 이제 액티비티가 뜨고 동작하기 완전 직전에 실행 된다. OnStart보다 액티비티가 실행되기 더 직전에 가깝다.
(onPause에서 sharedpreferences에 임시저장된 데이터를 불러오는데 주로 사용된다.)
OnCreate=>OnStart=>OnResume은 액티비티가 실행되기 전에 차례대로 실행되는 순서라고 생각하면 이해하기가 쉬웠다.
OnPause()부터는 액티비티가 실행상태인 이후의 생명주기이다.
추가적으로 onPause()는 데이터를 저장하는데 주로 사용된다.
예를들어 게임을 하고있다가 중간에 전화가오거나 멈춰진 경우 전화가 끝나고 게임을 시작하면 게임이 원래 하던곳부터 계속 진행될수 있어야 할 것이다.
그런 경우 onPause()에서 현재의 데이터들을 sharedpreferences를 사용하여 저장해놓고 다시 앱을 진행했을때 복원 할 수 있게 onResume()에서 저장한 데이터들을 복원해 진행시킬 수 있다.
+) 추가적으로 데이터를 저장하는데 onSaveInstanceState() , onRestoreInstanceState()를 사용하는 방법도 있는데 화면전환할때 데이터 유지에도 유용하다.
OnStop은 우리가 쓰던 액티비티가 완전히 이제 뒤로가서 안보일 때 호출되는 메소드이다. 그런데 OnStop인 상태일때 앱을 다시 킬수도 있는데 그런 경우 OnRestart()를 거쳐 onStart 생명주기로 다시 넘어간다. 참고로 onStop은 아직 액티비티가 소멸된 상태는 아니다.
추가로 하나 예를 더 들면 액티비티를 사용중에 홈버튼을 눌렀을 경우 onPasue와 OnStop이 순서대로 호출될 것이다. 그리고 다시 앱이 종료되지 않았으므로 앱을 다시 키면 원래 액티비티가 뜰건데 이때 onRestart와 onStart 가 호출된다.
그리고 만약 뒤로가기로 앱을 끄면 OnPasue->OnStop->OnDestory 순서로 호출될거고 다시 종료된 앱을 키면 OnCreate() 부터 호출된다.
OnDestory는 액티비티를 더이상 쓰지 않을 경우 액티비티를 종료했을 때 호출된다. 이 이후에 액티비티를 다시실행시키면 onCreate() 부터 진행될 것이다.
즉 OnPause=>OnStop=>OnDestory 도 위에서 말한거와 마찬가지로 액티비티가 실행되고 이후의 생명주기 순서라고 보면된다. 다만 어느정도 액티비티가 가려지느냐 없어지느냐로 판단하면 쉽게 이해 할 수 있을거 같다.
이 생명주기 그림은 중요하므로 꼭 외우고 이해하도록 해야한다.
오버라이딩은 상속 관계에 있는 두 클래스 중, 하위 클래스에서 상위 클래스의 메소드를 재정의하는 것을 의미합니다. 오버라이딩이야말로 안드로이드 어플리케이션 개발에 있어서 가장 자주 쓰이는 기술이 아닐까 싶네요.
간단히 예를들어보죠 [오리]라는 클래스가 있다고 하겠습니다. 이[오리] 클래스는 [난다()]라는 메서를 가집니다. 이 [난다()]라는 메서드에는 오리가 1초에 6번 날개짓을 하는 코드가 기록되있다고 합시다.
여기서 [좀더빨리나는오리]를 만들고자 [오리]클래스를 상속받았다고 합시다. 그럼 좀더빨리날려면 1초에 7번이상 날개를 퍼덕거려야 되겠죠 이때 [난다()]메서드를 오버라이드를 통해 재정의 하면서 1초에 7번 퍼덕이는 코드를 다시 적어주는겁니다. 이런게 오버라이드입니다. 상속받은 클래스에서 메서드를 바꿀 필요가 있을때 재정의 한다는 의미입니다.