구현 문제
알림 클릭하면 특정 화면을 띄어줘야 하는 문제였다.
해결 방법
PendingIntent 를 사용하면 된다. Notification 속성에 Intent 속성을 부여할 수 있는데 이 때 PendingIntent 를 넘겨준다. 또한 PendingIntent 객체에 putExtra 로 화면 이동으로 띄어줄 Fragment 의 식별자를 넘겨준다. 이를 활용하여 MainActivity 가 onCreate 됐을 때 getStringExtra 로 Fragment 의 식별자를 가져오고 해당 Fragment 로 전환한다.
코드
- ReceiverService
우선 지난번에 구현했던 이벤트 수신 알림에 대한 코드를 가져왔다.
// 이벤트를 수신했을 경우 사용자에게 알림 전송
private fun occurEventNotification() {
val bitmap = BitmapFactory.decodeStream(URL(IMAGE_URL).openConnection().getInputStream())
val intent = Intent(this@ReceiverService, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
putExtra("Fragment", "eventDetailFragment")
}
val pendingIntent: PendingIntent =
PendingIntent.getActivity(this@ReceiverService, 0, intent, 0)
val builder = NotificationCompat.Builder(this@ReceiverService, NOTIFICATION_CHANNEL[1])
.setSmallIcon(R.drawable.ic_baseline_poop_solid_icon)
.setContentTitle("배변 이벤트 수신")
.setContentText("Device 1에서 배변 이벤트가 수신되었습니다.")
.setLargeIcon(bitmap)
.setStyle(
NotificationCompat.BigPictureStyle()
.bigPicture(bitmap)
.bigLargeIcon(null)
)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentIntent(pendingIntent)
.setAutoCancel(true)
// Android 26 이상부터는 NotificationChannel 등록 필요
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel =
NotificationChannel(
NOTIFICATION_CHANNEL[1],
"이벤트 발생",
NotificationManager.IMPORTANCE_HIGH
)
val manager =
applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
manager.createNotificationChannel(channel)
}
}
기존에 Intent 를 사용하던 방식과 같이 Context 와 화면 이동을 할 Class 를 인자로 넣어준다. putExtra 를 통해서 화면 이동을 할 Fragment 의 식별자를 넣어준다. Fragment 가 EventDetailFragment 이기에 eventDetailFragment 로 넣어줬다. 이후 PendingIntent 에 정의한 Intent 를 넘겨주면 된다.
그렇다면 그냥 Intent 를 사용하면 안되는 것일까? 둘의 차이점을 살펴보면 우리가 평소에 사용하던 Intent 는 하나의 앱(프로세스) 내부에서 화면 이동을 하는 것이였지만 PendingIntent 는 하나의 앱에서 다른 앱으로 화면 이동을 하고 있다. NotificationManager 가 Intent 를 실행하여 마치 하나의 앱에서 화면 이동을 실행하는 것처럼 사용하게 한다. 즉 다른 프로세스(안드로이드 시스템) 에서 Intent 를 진행하므로 PendingIntent 를 사용해야 한다. Notification 외에도 앱 외부에서 앱의 특정 화면을 호출해야하는 경우에 PendingIntent 를 사용할 수 있다. (AlarmManager, Widget)
- MainActivity
이렇게 PendingIntent 로 MainActivity 를 호출하고 MainActivity 가 onCreate 되면 어떤 Fragment 로 이동할지를 결정한다.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val targetFragment = intent.getStringExtra("Fragment")
if (targetFragment != null) {
if (targetFragment == "eventDetailFragment") {
saveAndChangeFragment(EventDetailFragment())
} else {
saveAndChangeFragment(DeviceDetailFragment())
}
}
saveAndChangeFragment 메소드는 FrameLayout 에 띄어줄 Fragment 를 지정한다.
fun saveAndChangeFragment(fragment: Fragment) {
supportFragmentManager.beginTransaction()
.replace(binding.fragmentContainer.id, fragment)
.addToBackStack(null)
.commit()
}
결과
학습용 이미지 선택 알림을 클릭 했을 경우에 소켓 재연결이 진행되는데 Intent Flag로 NEW_TASK 와 CLEAR_TASK 를 넘겨줬기 때문이다.
느낀 점
'💻 개발 > Android' 카테고리의 다른 글
[Android] 백그라운드에서 소켓 통신으로 이벤트 수신 후 알림 (0) | 2022.06.08 |
---|---|
[Android] MVVM 패턴 적용기 - 2 (0) | 2022.05.14 |
[Android] MVVM 패턴 적용기 - 1 (0) | 2022.04.11 |
[Android] 카메라 또는 갤러리에서 이미지 가져오기 (0) | 2022.02.06 |
[Android] 다국어 지원 (0) | 2022.01.13 |