//사용자 상호작용에 응답해 Fragment를 추가하거나 삭제하는등 작업을 할 수 있게 해주는 매니저
supportFragmentManager.commit {
//어느프레임 레이아웃에 띄울것이냐, 어떤프래그먼트냐
replace(R.id.frameLayout, frag)
//애니메이션과 전환이 올바르게 작동하도록 트랜잭션과 관련된 프래그먼트의 상태 변경을 최적화
setReorderingAllowed(true)
//뒤로가기 버튼 클릭시 다음 액션 (이전 fragment로 가거나 앱이 종료되거나)
addToBackStack("")
}
onAttach()
: 프래그먼트가 액티비티에 연결될 때 호출. 아직 액티비티와 완전히 연결되지 않은 상태.
onCreate()
: 프레그먼트가 생성될 때 호출. 초기화 작업, 리소스 바인딩 등을 수행하기에 적합하다.
=> 다른곳에서 전달되어 Bundle에 저장된 데이터를 get하여 저장한다.
onCreateView()
: 프래그먼트의 레이아웃이 inflate되는 지점. 뷰를 생성하고, 레이아웃을 설정한다.
=> return inflater.inflate(R.layout.프레그먼트레이아웃, container, false) : 프레그먼트레이아웃에 해당하는 xml파일을 그대로 보여준다.
=> return binding.root : 바인딩해놓은 xml파일이 보여진다.
onActivityCreated()
: 액티비티의 onCreate() 메서드가 완료된 후 호출. 액티비티와 프래그먼트의 뷰가 모두 생성된 상태이므로, 뷰와 관련된 초기화를 수행한다.
=>액티비티와의 상호작용이 필요한 경우에 사용하면 좋다.
+onViewCreated() : 프레그먼트 뷰가 완전히 생성된 후 호출. 뷰와 관련된 초기화 작업을 수행한다.
=> 뷰의 이벤트 리스너를 설정하거나, 프래그면트 뷰에 대한 참조를 얻을 때 사용하면 좋다.
onStart()
: 프래그먼트가 사용자에게 보여질 준비가 되었을 때 호출. 필요한 리소스를 할당하거나, 애니메이션을 시작할 수 있다.
onResume()
: 프래그먼트가 사용자와 상호작용할 수 있는 상태가 되었을 때 호출. 프래그먼트가 포그라운드에 있을 때 실행되는 작업을 여기서 처리한다.
onPause()
: 프래그먼트가 일시정지될 때 호출. 상태 저장, 스레드 중지 등의 작업을 수행한다.
onStop()
: 프래그먼트가 더 이상 사용자에게 보이지 않을 때 호출. 리소스 해제, 스레드 정지 등을 수행한다.
onDestroyView()
: 프래그먼트의 뷰와 관련된 리소스를 정리할 때 호출.
onDestroy()
: 프래그먼트가 파괴될 때 호출. 프래그먼트의 상태를 정리하고, 모든 리소스를 해제한다.
onDetach()
: 프래그먼트가 액티비티로부터 분리될 때 호출. 프래그먼트가 액티비티와의 모든 연결을 해제한다.
Activity → Fragment
:액티비티에서 프래그먼트로 이동할 때 메소드(newInstance 메소드)를 통해 데이터를 담아서 전달한 후 Bundle객체로 프레그먼트의 인자로 설정후, 이 인자를 프레그먼트에서 사용.
Fragment → Fragment
: 1번 방법과 유사하다. 프래그먼트에서 다른 프래그먼트로 이동할 때 메소드(newInstance 메소드)를 통해 데이터를 담아서 전달한 후 Bundle객체로 프레그먼트의 인자로 설정후, 이 인자를 프레그먼트에서 사용.
Fragment → Activity
: 콜백인터페이스를 통해 데이터전달을 해야함. 프레그먼트에서 인터페이스로 데이터를 전달하면 인터페이스는 액티비티에서 구현.
제목 : 선택 사항이며 콘텐츠 영역에 상세한 메시지,목록 또는 맞춤 레이아웃이 채워져 있는 경우에만 사용해야 한다. 단순한 메시지 또는 질문을 나타내야 하는 경우 제목은 없어도 된다.
=> setTitle( ), setIcon( )
콘텐츠 영역 : 메시지,목록 또는 다른 맞춤 레이아웃을 표시 할 수 있다.
=> setMessage( )
작업 버튼 : 대화 상자 하나에 작업 버튼이 세 개를 초과하면 안된다.
=> setPositiveButton( ), setNegativeButton( ), setNeutralButton( )
기본 다이얼로그
binding.btn1Alert.setOnClickListener {
var builder = AlertDialog.Builder(this)
builder.setTitle("기본 다이얼로그 타이틀")
builder.setMessage("기본 다이얼로그 메세지")
builder.setIcon(R.mipmap.ic_launcher)
// 버튼 클릭시에 무슨 작업을 할 지에 대해 따로 listener를 생성
val listener = object : DialogInterface.OnClickListener {
override fun onClick(p0: DialogInterface?, p1: Int) {
when (p1) {
DialogInterface.BUTTON_POSITIVE ->
binding.tvTitle.text = "BUTTON_POSITIVE"
DialogInterface.BUTTON_NEUTRAL ->
binding.tvTitle.text = "BUTTON_NEUTRAL"
DialogInterface.BUTTON_NEGATIVE ->
binding.tvTitle.text = "BUTTON_NEGATIVE"
}
}
}
builder.setPositiveButton("Positive", listener)
builder.setNegativeButton("Negative", listener)
builder.setNeutralButton("Neutral", listener)
builder.show()
}
커스텀 다이얼로그 : res>layout 안에 따로 xml파일을 만들어서 연결하여 사용 가능.
binding.btn2Custom.setOnClickListener {
val builder = AlertDialog.Builder(this)
builder.setTitle("커스텀 다이얼로그")
builder.setIcon(R.mipmap.ic_launcher)
//따로 만든 dialog.xml을 연결한다.
val v1 = layoutInflater.inflate(R.layout.dialog, null)
builder.setView(v1)
// p0에 해당 AlertDialog가 들어온다. findViewById를 통해 view를 가져와서 사용
val listener = DialogInterface.OnClickListener { p0, p1 ->
val alert = p0 as AlertDialog
val edit1: EditText? = alert.findViewById<EditText>(R.id.editText)
val edit2: EditText? = alert.findViewById<EditText>(R.id.editText2)
binding.tvTitle.text = "이름 : ${edit1?.text}"
binding.tvTitle.append(" / 나이 : ${edit2?.text}")
}
builder.setPositiveButton("확인", listener)
builder.setNegativeButton("취소", null)
builder.show()
}
날짜 다이얼로그(DatePickerDialog)
binding.btn3Date.setOnClickListener {
val calendar = Calendar.getInstance()
val year = calendar.get(Calendar.YEAR)
val month = calendar.get(Calendar.MONTH)
val day = calendar.get(Calendar.DAY_OF_MONTH)
val listener = DatePickerDialog.OnDateSetListener { datePicker, i, i2, i3 ->
// i년 i2월 i3일
// 월의 경우 0부터 시작하기 떄문에 +1을 꼭 해줘야한다.
binding.tvTitle.text = "${i}년 ${i2 + 1}월 ${i3}일"
}
var picker = DatePickerDialog(this, listener, year, month, day)
picker.show()
}
시간 다이얼로그(TimePickerDialog)
binding.btn4Time.setOnClickListener {
val calendar = Calendar.getInstance()
val hour = calendar.get(Calendar.HOUR)
val minute = calendar.get(Calendar.MINUTE)
val listener = TimePickerDialog.OnTimeSetListener { timePicker, i, i2 ->
binding.tvTitle.text = "${i}시 ${i2}분"
}
val picker = TimePickerDialog(this, listener, hour, minute, false)
// false 대신 true를 선택하면 24시간 모양.
picker.show()
}
진행 다이얼로그(ProgressDialog)
// 커스텀 다이얼로그와 유사한 방식. 따로 xml파일을 만들어서 연결해줘야한다.
binding.btn5Porgress.setOnClickListener {
val builder = AlertDialog.Builder(this)
builder.setTitle("프로그래스바")
builder.setIcon(R.mipmap.ic_launcher)
// progressbar.xml을 연결해준다.
//(xml 안에서 <ProgressBar> 태그를 사용하여 레이아웃모양을 만들 수 있다.)
val v1 = layoutInflater.inflate(R.layout.progressbar, null)
builder.setView(v1)
builder.show()
}
//Deprecate된 기능.
binding.btn5Porgress.setOnClickListener {
// 권장하진 않지만 사용은 가능하다.
pro = ProgressDialog.show(this, "타이틀입니다.", "메시지입니다.")
// 핸들러를 통해서 종료 작업을 한다.
val handler = Handler()
val thread = Runnable { pro?.cancel() }
handler.postDelayed(thread, 5000) // 딜레이는 5초
}
private val myNotificationID = 1
private val channelID = "default"
private fun createNotificationChannel() {
//Android 8.0이상인지 확인해야한다.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(channelID, "default channel",
NotificationManager.IMPORTANCE_DEFAULT)
//채널 중요도(Android 8.0이상)
channel.description = "description text of this channel."
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
}private val myNotificationID = 1
private fun showNotification() {
// NotificationCompat.Builder.build()호출하고, Notification객체를 반환
val builder = NotificationCompat.Builder(this, channelID)
//작은 아이콘
.setSmallIcon(R.mipmap.ic_launcher)
// 제목
.setContentTitle("title")
// 세부텍스트
.setContentText("notification text")
//알림 우선순위 설정 (Android 7.1이하)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
//NotificationManagerCompat.notify()를 호출해서 시스템에 Notification객체를 전달
NotificationManagerCompat.from(this).notify(myNotificationID, builder.build())
}setStyle(NotificationCompat.BigTextStyle()
.bigText( "~") // 넣을 이미지를 bitmap으로 builder 바깥에 설정
val bitmap = BitmapFactory.decodeResource(resources, R.drawable.flower)setStyle(NotificationCompat.BigPictureStyle()
.bigPicture(bitmap)
.bigLargeIcon(null)) // hide largeIcon while expanding//연결해줄 intent를 builder 바깥에 설정
val intent = Intent(this, SecondActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
val pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) addAction(R.mipmap.ic_launcher, "Action", pendingIntent)프라이버시 강화와 사용자 동의 없는 알림 전송을 방지하기 위해서 권한부여 대화상자를 표시해야한다.
POST_NOTIFICATIONS 권한을 앱의 매니페스트 파일에 명시적으로 추가해야 한다.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<!-- API 33 이상을 위한 알림 권한 추가 -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
...
</manifest>
앱이 실행중일때에도 사용자에게 알림 권한을 요청 할 수 있다.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (!NotificationManagerCompat.from(this).areNotificationsEnabled()) {
// 알림 권한이 없다면, 사용자에게 권한 요청
val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply {
putExtra(Settings.EXTRA_APP_PACKAGE, packageName)
}
startActivity(intent)
}
}