일일 회고
팀이 바뀌고 숙련 주차가 시작되었다.
강의를 듣고 과제를 해보는데 확실히 이전보다 어려워졌다.
차근차근히 공부해봐야겠다.
오늘의 키워드
- 뷰 바인딩
- 어댑터 뷰
- 프래그먼트
- 다이얼로그
- 알림
ViewBinding
viewBinding vs findViewById
findViewById는 human error의 가능성(선언할 때 잘못된 id를 넣을 수 있다.) 때문에 Null Safe 하지 않다.
-> viewBinding은 레이아웃에 대한 바인딩 클래스를 만들어 레이아웃안의 모든 뷰를 인스턴스화 시킨다.
-> 레이아웃에 아직 생성되지 않은 뷰의 참조를 얻어(null상태)해당 뷰의 속성을 사용하려 할 때 발생하는 NPE를 방지 한다는 것이다.
viewBinding은 findViewById보다 성능적으로 좋다.
-> findViewById는 ViewGroup 밑에 있는 모든 뷰들을 전부 한 번씩 순회하며 id 값을 비교한다. (트리 순회를 한다. xml이 트리구조)
->viewBinding은 바인딩 클래스에서 모든 뷰들이 미리 변환되어진다.
사용법
app수준의 gradle에 선언한다.
viewBinding {
enabled true
}
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.myButton.setOnClickListener{
binding.myTextView.text = "바인딩!"
}
}
}
AdapterView
- 어댑터 뷰는 여러개의 항목을 다양한 형식으로 나열하고 선택 할 수 있는 기능을 제공하는뷰
- 리스트뷰(ListView)는 항목을 수직으로 나열시키는 방식
- 그리드뷰(GridView)는 항목을 격자 형태로 나열시키는 방식
- 어댑터 뷰는 표시할 항목 데이터를 직접 관리하지 않고, Adapter라는 객체로부터 공급받는다 --> 항목을 하드코딩을 하지 않아도 된다! --> 어댑터에 데이터를 바인딩 시킨다. 그러면 알아서 리스트로 보여준다!
Adapter
- 데이터를 관리하며 데이터 원본과 어댑터뷰(ListView, GridView) 사이의 중계 역할
- 어댑터뷰는 어떻게 데이터 항목을 표시할까? -- 기본적인 Adapter view 원리
- 어댑터뷰가 어댑터를 사용하기 위해서는 먼저 데이터 원본이 어댑터에 설정되어야 하고, 어댑터뷰에는 어댑터가 설정되어야 한다.
- 어댑터뷰는 항목을 표시하기 위해서 먼저 표시할 항목의 총 개수를 알 필요가 있다. 이 때, 어댑터 뷰는 어댑터의 getCount()란 메소드를 통해 현재 어뎁터가 관리하는 데이터 항목의 총 개수를 반환한다.
- 어댑터 뷰는 어댑터의 getView()란 메소드를 통해서 화면에 실제로 표시할 항목뷰를 얻고, 이를 화면에 표시한다.
AdapterView중 주로 사용하는 것엔 RecyclerView가 있다.
RecyclerView 안의 리스트 항목은 안드로이드의 기본적인 레이아웃을 적용시키는 것이 아니라 직접 다양한 뷰를 적용시킨 Custom Item(View)를 적용시킨다.
RecyclerView의 주의점 - 다른 어댑터와 다르게 RecyclerView Adapter에는 항목 클릭 시 이벤트가 발생하는 콜백 (클릭 리스너) 가 없다. 그래서 직접 정의해 사용해야한다.!!
RecyclerView의 설명은 포스팅으로 대체한다.
Fragment
- 액티비티 위에서 동작하는 모듈화된 사용자 인터페이스
- 액티비티와 분리되어 독립적으로 동작할 수 없음
- 여러 개의 프래그먼트를 하나의 액티비티에 조합하여 창이 여러 개인UI를 구축할 수 있으며,하나의 프래그먼트를 여러 액티비티에서 재 사용할 수 있음 --> bottomNavigationView에서 주로 사용됨
Acitivity와의 차이
--> 액티비티는 액티비티 매니저에 의해 인텐트로 데이터를 전달시키지만, 프래그먼트는액티비티의 프래그먼트 매니저에서 메소드로 프래그먼트간 데이터를 전달
--> 쓰는 이유: Activity로 화면을 계속 넘기는 것보다는 Fragment로 일부만 바꾸는 것이 자원 이용량이 적어 속도가 빠르기 때문
Fragment lifecycle
액티비티와 비슷하게 프래그먼트도 자신만의 라이프사이클이 존재한다.
프래그먼트로 라이프사이클에 따라 행동하므로 기능 구현을 할 때 라이프 사이클에 따라 잘 맞추어 기능 구현을 해주어야한다. 이거는 추후 포스팅으로 다루어 보겠다. (글이 길어질 것 같다..)
Dialog
- 다이얼로그는 사용자에게 결정을 내리거나 추가정보를 입력하라는 메시지를 표시하는 작은창이다. 추가적인 의사결정을 할 수 있다.
- 다이얼로그는 화면을 가득 채우지 않으며 보통은 사용자가 다음으로 계속 진행하기 전에 조치를 취해야 하는 모달 이벤트에 사용된다.
Dialog에는 기본적으로 제공되는 Dialog도 있고, 커스텀을 할 수도 있고, github를 좀 찾아보면 디자인이 잘된 오픈소스도 찾아볼 수 있다.
기본 다이얼로그
- AlertDialog (제일 기본)
- TimePickerDialog (시간 선택 다이얼로그)
- DatePickerDialog (날짜 선택 다이얼로그)
커스텀 다이얼로그
- AlertDialog에 setView 메서드에 직접 만든 layout을 지정하여 커스텀 할 수 있다.
val builder = AlertDialog.Builder(this)
builder.setTitle("커스텀 다이얼로그")
builder.setIcon(R.mipmap.ic_launcher)
val view = layoutInflater.inflate(R.layout.dialog, null)
builder.setView(view)
오픈소스 다이얼로그
Notification
notification 만들기
notification은 사용자에게 미리 알림을 주고 다른사람과 소통을 가능하게 하며
앱에서 보내는 기타 정보를 적시에 제공하기 위해 안드로이드가 앱의 UI 외부에 표시하는 메시지이다.
사용자는 notification을 탭하여 앱을 열거나 알림에서 바로 특정 작업을 할 수 있다. Notification클래스와 그 하위 클래스들을 사용하여 구현한다
val pendingIntent = PendingIntent.getActivity(this, type.id, intent, FLAG_UPDATE_CURRENT)
val notificationBuilder = NotificationCompat.Builder(this, CHANNEL_ID)
// notification 의 아이콘
.setSmallIcon(R.drawable.ic_notifications_24)
// notification의 제목
.setContentTitle(title)
// notification의 내용
.setContentText(msg)
// notification의 우선순위
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
// notification을 눌렀을떄 실행할 intent -- 추후 추가 기술
.setContentIntent(pendingIntent)
// notification 터치시 자동으로 notification 제거
.setAutoCancel(true)
NotificationCompat.Builder객체를 통하여 만든다.
- setPriorty: android 7.1이하에서 얼마나 강제적이여야하는지 결정 (8.0 이상의 경우 채널 중요도로 설정해야함)
- android 8.0이상에서는 notification을 제공하려면 반드시 앱의 notification channel을 구분지어야한다.
- 그래서, 앱의 notification channel을 먼저 앱에 등록해야한다.
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
CHANNEL_ID,
CHANNEL_NAME,
NotificationManager.IMPORTANCE_DEFAULT
)
channel.description = CHANNEL_DESCRIPTION
(getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager)
.createNotificationChannel(channel)
}
}
안드로이드 8.0(Oreo) 부터 channel을 적용해야하니 system sdk version을 확인한다.
그리고 NotificationChannel클래스로 NotificationChannel 객체를 만들고
NotificationManager의 createNotificationChannel메소드를 통해 채널을 생성한다.
이제, notification을 터치했을 때의 동작 설정에 대해 알아본다. notification을 터치하면 그에 따른 앱이 실행되거나 특정 작업을 수행해야 할 것이다. 이때, 앱이 켜지는 등 intent의 변화가 있을 것이다. 위의코드를 보면 pendingIntent로 넘겨주는 것을 볼 수 있는데,
notification의 특성을 보면 intent가 아닌 pendingIntent로 넘겨주는지 알 수 있다.
notification의 사용경로를 보면 푸시알림이 굉장히 많다. 만약, A 앱을 사용하는 중, B 앱에서 푸시알림이 왔다고 가정하자. 이때, 알림을 누르면 B앱으로 넘어가야 할 것이다. 그런데, 여기서 푸시알림의 intent 방식을 일반 intent로 해놓았다면 정상동작하지 않는다. A 앱으로 부터 B 앱의 intent로는 이동이 불가능하기 때문이다.
이때, pendingIntent를 사용하는데, 간단하게 설명하면 pendingIntent는 intent가 정의된 앱이 아닌, 다른 앱에서 intent를 실행하도록 하는 intent이다.
pendingIntent를 사용함으로써, 안전한 앱의 실행을 보장할 수 있다. (FLAG_UPDATE_CURRENT를 통해 pendingIntent를 하나만 유지하고 이전 intent는 변경해버린다.)
- notification 표시
NotificationManagerCompat.from(Context)
.notify(type.id, createNotification(type, title, msg))
NotificationManagerCompat의 notify를 통해 알림을 표시한다.
notification 스타일
-
- 일반 알림
- link 이 설정이 일반 알림이다.
- 확장형 알림, 커스텀 알림
- 공통: notificationBuilder.setStyle(param)을 통해 원하는 스타일을 추가한다.
- 확장형: setStyle()의 파라미터에 NotificationCompat.BigTextStyle().bigText(text)를 추가하여 알림창을 확대 시킬 수 있는 확장형 알림을 만들 수 있다.
- 커스텀: setStyle()의 파라미터에 NotificationCompat.DecoratedCustomViewStyle() 커스텀을 알리고, notificationBuilder에 setCustomContentView()를 추가하여 커스텀 레이아웃을 만들어 알림창에 띄울 수 있다.
- 일반 알림
setCustomContentView(
RemoteViews(
packageName,
R.layout.view_custom_notification
)
'내일배움캠프 7기 > TIL' 카테고리의 다른 글
내일배움캠프 7기 Android TIL 29일차 (2023.08.24) (0) | 2023.08.24 |
---|---|
내일배움캠프 7기 Android TIL 28일차 (2023.08.23) (0) | 2023.08.23 |
내일배움캠프 7기 Android TIL 26일차 (2023.08.21) (0) | 2023.08.21 |
내일배움캠프 7기 Android TIL 25일차 (2023.08.18) (0) | 2023.08.18 |
내일배움캠프 7기 Android TIL 24일차 (2023.08.17) (0) | 2023.08.17 |