-
Notifications
You must be signed in to change notification settings - Fork 1
[정현수_Android] 6-2주차 과제 제출 #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| 알림 실습 | ||
| 알림 레이아웃을 먼저 만들고, 알림을 띄우는 코드를 작성하고, 알림 버튼의 입력을 감지하는 코드를 작성 | ||
|
|
||
| 알림의 버튼이 눌리면 수신자 클래스가 MainActivity.kt에 있는 함수를 통해 액티비티를 변경함으로써 콜백 함수로 결과를 받을 수 있게 함 | ||
|
|
||
| 알림 관련 안드로이드 권한 설정 | ||
|
|
||
| 1. | ||
| notification.xml | ||
| strings에 단어들을 흩뿌려 두거나, 코틀린 파일에 하드코딩하기에 모양새가 안좋다 생각해 xml파일에 모아두었음 | ||
|
|
||
| 2. | ||
| NotificationReceiver.kt | ||
| 수신자 클래스 작성 | ||
| 알림의 버튼이 눌렸을때 다른 클래스의 코드를 실행해 독립성 유지할 것 | ||
|
|
||
| 3. | ||
| MainActivity.kt 및 MainActivity2.kt 코드 변경 | ||
|
|
||
| 4. | ||
| 피드백 수용 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,20 +1,166 @@ | ||
| package com.example.android_2026_1 | ||
|
|
||
| import android.Manifest | ||
| import android.app.NotificationChannel | ||
| import android.app.NotificationManager | ||
| import android.app.PendingIntent | ||
| import android.content.Context | ||
| import android.content.Intent | ||
| import android.content.pm.PackageManager | ||
| import android.os.Build | ||
| import android.os.Bundle | ||
| import android.widget.RemoteViews | ||
| import android.widget.Toast | ||
| import androidx.activity.enableEdgeToEdge | ||
| import androidx.activity.result.contract.ActivityResultContracts | ||
| import androidx.appcompat.app.AppCompatActivity | ||
| import androidx.core.app.NotificationCompat | ||
| import androidx.core.content.ContextCompat | ||
| import androidx.core.view.ViewCompat | ||
| import androidx.core.view.WindowInsetsCompat | ||
| import com.example.android_2026_1.databinding.ActivityMainBinding | ||
|
|
||
| class MainActivity : AppCompatActivity() { | ||
|
|
||
| private lateinit var binding: ActivityMainBinding | ||
| private var count: Int = 0 | ||
|
|
||
| private val activityResultLauncher = registerForActivityResult( | ||
| ActivityResultContracts.StartActivityForResult() | ||
| ) { result -> | ||
| if (result.resultCode == RESULT_OK) { | ||
| count = result.data?.getIntExtra(EXTRA_RETURN_COUNT, 0) ?: 0 | ||
| binding.textViewCount.text = count.toString() | ||
| } | ||
| } | ||
|
|
||
| private val requestPermissionLauncher = registerForActivityResult( | ||
| ActivityResultContracts.RequestPermission() | ||
| ) { isGranted -> | ||
| if (isGranted) { | ||
| showNotificationWithCount() | ||
| } else { | ||
| Toast.makeText(this, getString(R.string.permission_denied), Toast.LENGTH_SHORT).show() | ||
| } | ||
| } | ||
|
|
||
| override fun onCreate(savedInstanceState: Bundle?) { | ||
| super.onCreate(savedInstanceState) | ||
| enableEdgeToEdge() | ||
| setContentView(R.layout.activity_main) | ||
| ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets -> | ||
| binding = ActivityMainBinding.inflate(layoutInflater) | ||
| setContentView(binding.root) | ||
|
|
||
| createNotificationChannel() | ||
|
|
||
| ViewCompat.setOnApplyWindowInsetsListener(binding.main) { v, insets -> | ||
| val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) | ||
| v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) | ||
| insets | ||
| } | ||
|
|
||
| binding.buttonCount.setOnClickListener { | ||
| count++ | ||
| binding.textViewCount.text = count.toString() | ||
| } | ||
|
|
||
| binding.buttonToast.setOnClickListener { | ||
| Toast.makeText(this, getString(R.string.toast_message), Toast.LENGTH_SHORT).show() | ||
| } | ||
|
|
||
| binding.buttonRandom.setOnClickListener { | ||
| if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { | ||
| if (ContextCompat.checkSelfPermission( | ||
| this, | ||
| Manifest.permission.POST_NOTIFICATIONS | ||
| ) == PackageManager.PERMISSION_GRANTED | ||
| ) { | ||
| showNotificationWithCount() | ||
| } else { | ||
| requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS) | ||
| } | ||
| } else { | ||
| showNotificationWithCount() | ||
| } | ||
| } | ||
|
|
||
| handleIntent(intent) | ||
| } | ||
|
|
||
| override fun onNewIntent(intent: Intent) { | ||
| super.onNewIntent(intent) | ||
| setIntent(intent) | ||
| handleIntent(intent) | ||
| } | ||
|
|
||
| private fun handleIntent(intent: Intent?) { | ||
| if (intent?.action == ACTION_LAUNCH_MAIN2) { | ||
| val countExtra = intent.getIntExtra(EXTRA_INTENT_COUNT, 0) | ||
| val main2Intent = Intent(this, MainActivity2::class.java).apply { | ||
| putExtra(EXTRA_INTENT_COUNT, countExtra) | ||
| } | ||
| activityResultLauncher.launch(main2Intent) | ||
| } | ||
| } | ||
|
|
||
| private fun createNotificationChannel() { | ||
| if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { | ||
| val name = getString(R.string.channel_name) | ||
| val importance = NotificationManager.IMPORTANCE_DEFAULT | ||
| val channel = NotificationChannel(CHANNEL_ID, name, importance) | ||
| val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager | ||
| notificationManager.createNotificationChannel(channel) | ||
| } | ||
| } | ||
|
|
||
| private fun showNotificationWithCount() { | ||
| val notificationBinding = com.example.android_2026_1.databinding.NotificationBinding.inflate(layoutInflater) | ||
| val remoteViews = RemoteViews(packageName, R.layout.notification).apply { | ||
| setTextViewText(notificationBinding.tvTitle.id, getString(R.string.notification_title)) | ||
| setTextViewText(notificationBinding.tvContent.id, getString(R.string.notification_content, count)) | ||
|
|
||
|
|
||
| val moreIntent = Intent(this@MainActivity, NotificationReceiver::class.java).apply { | ||
| action = ACTION_MORE | ||
| putExtra(EXTRA_INTENT_COUNT, count) | ||
| } | ||
| val morePendingIntent = PendingIntent.getBroadcast( | ||
| this@MainActivity, | ||
| 0, | ||
| moreIntent, | ||
| PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE | ||
| ) | ||
| setOnClickPendingIntent(notificationBinding.btnMore.id, morePendingIntent) | ||
|
|
||
| val closeIntent = Intent(this@MainActivity, NotificationReceiver::class.java).apply { | ||
| action = ACTION_CLOSE | ||
| putExtra(EXTRA_NOTIFICATION_ID, NOTIFICATION_ID) | ||
| } | ||
| val closePendingIntent = PendingIntent.getBroadcast( | ||
| this@MainActivity, | ||
| 1, | ||
| closeIntent, | ||
| PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE | ||
| ) | ||
| setOnClickPendingIntent(notificationBinding.btnClose.id, closePendingIntent) | ||
| } | ||
|
|
||
| val builder = NotificationCompat.Builder(this, CHANNEL_ID) | ||
| .setSmallIcon(R.drawable.ic_launcher_foreground) | ||
| .setStyle(NotificationCompat.DecoratedCustomViewStyle()) | ||
| .setCustomBigContentView(remoteViews) | ||
|
|
||
| val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager | ||
| notificationManager.notify(NOTIFICATION_ID, builder.build()) | ||
| } | ||
|
|
||
| companion object { | ||
| const val CHANNEL_ID = "notification_channel" | ||
| const val NOTIFICATION_ID = 1 | ||
| const val ACTION_MORE = "ACTION_MORE" | ||
| const val ACTION_CLOSE = "ACTION_CLOSE" | ||
| const val ACTION_LAUNCH_MAIN2 = "ACTION_LAUNCH_MAIN2" | ||
| const val EXTRA_NOTIFICATION_ID = "NOTIFICATION_ID" | ||
| const val EXTRA_INTENT_COUNT = "INTENT_COUNT" | ||
| const val EXTRA_RETURN_COUNT = "RETURN_COUNT" | ||
| } | ||
|
Comment on lines
+156
to
165
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. MainActivity.kt에서 선언한 상수를 MainActivity2.kt에서도 사용되는데, 이럴 경우 두 클래스 사이에 결합도가 높아집니다. |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| package com.example.android_2026_1 | ||
|
|
||
| import android.content.Intent | ||
| import android.os.Bundle | ||
| import androidx.activity.OnBackPressedCallback | ||
| import androidx.activity.enableEdgeToEdge | ||
| import androidx.appcompat.app.AppCompatActivity | ||
| import androidx.core.view.ViewCompat | ||
| import androidx.core.view.WindowInsetsCompat | ||
| import com.example.android_2026_1.databinding.ActivityMain2Binding | ||
| import kotlin.random.Random | ||
|
|
||
| class MainActivity2 : AppCompatActivity() { | ||
|
|
||
| private lateinit var binding: ActivityMain2Binding | ||
| private var resultCount: Int = 0 | ||
|
|
||
| override fun onCreate(savedInstanceState: Bundle?) { | ||
| super.onCreate(savedInstanceState) | ||
| enableEdgeToEdge() | ||
| binding = ActivityMain2Binding.inflate(layoutInflater) | ||
| setContentView(binding.root) | ||
|
|
||
| ViewCompat.setOnApplyWindowInsetsListener(binding.main2) { v, insets -> | ||
| val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) | ||
| v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) | ||
| insets | ||
| } | ||
|
|
||
| val count = intent.getIntExtra(MainActivity.EXTRA_INTENT_COUNT, 0) | ||
|
|
||
| binding.textViewGuide.text = getString(R.string.random_message, count) | ||
|
|
||
| resultCount = Random.nextInt(0, count + 1) | ||
|
|
||
| binding.textViewRandomResult.text = resultCount.toString() | ||
|
|
||
| onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { | ||
| override fun handleOnBackPressed() { | ||
| val intent = Intent() | ||
| intent.putExtra(MainActivity.EXTRA_RETURN_COUNT, resultCount) | ||
| setResult(RESULT_OK, intent) | ||
| finish() | ||
| } | ||
| }) | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tvTitle, tvContent 모두 R.id로 대체 가능해 보입니다.