책과는 달리 안드로이드 스튜디오 버전을 4 이상으로 설치하여 학습하는 사람들은 이 전자액자 챕터에서 당황했을 것이다. 물론 저자님의 깃헙에 변경점에 대한 정리가 잘 되어있지만, 어댑터 클래스 부분이 아직 업데이트가 안 된 것 같아서 개인적으로 공부한 뒤에 이 챕터9의 전자액자를 완성했다.
이 어댑터 부분을 혼자서 처리해보는 과정에서 뷰와 레이아웃에 대한 이해와 어댑터의 역할을 더 명확히 알게 되었다. 그래서 이 포스팅에서는 내가 학습한 내용을 잘 엮어서 전자액자 어플의 구성을 재학습하려고 한다.
[안드로이드 입문자인 만큼 틀린 내용이 있을 수도 있습니다. 혹시 오류를 발견하신 최고로 멋진 선생님께서는 댓글을 부탁드립니다.. >ㅅ< ]
먼저, 챕터9의 전자액자의 큰 구성은 이렇다.
[간단히 정리한 표다.]
메인 액티비티 | 프래그먼트 | 어댑터 |
MainActivity | PhotoFragment | MyPagerAdapter |
권한 허용 여부 확인과 요청 | lateinit var uri | 리스트 선언 <프래그먼트> |
권한 있을 경우 getAllPhotos() 호출 | fun onCreate | fun updateFragments(인자 리스트) =>인자로 넘어온 리스트의 내용을 여기서 선언한 리스트에 추가한다. |
fun getAllPhotos =>사진 정보 가져오기 =>Fragment 배열에 객체 생성 =>어댑터 연결 |
fun onCreateView =>프래그먼트 뷰를 반환(생성) |
fun getItemCount =>여기서 선언한 리스트.size 반환 |
fun onVeiwCreated =>뷰가 완성된 직후 호출 =>여기서 이미지를 로드 |
fun createFragment(position: Int) 리스트에서 해당 인덱스 프래그먼트반환 |
|
companion object fun newInstance =>arguments에 |
클래스별로 학습해보려고 한다. 이번 포스팅은
" 1탄, Fragment "
2,3탄은 어댑터랑 메인액티비티 예정
프래그먼트 - PhotoFragment 내용
package com.example.mygallery
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.bumptech.glide.Glide
import kotlinx.android.synthetic.main.fragment_photo.*
private const val ARG_URI = "uri"
class PhotoFragment : Fragment() {
private lateinit var uri: Uri
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.getParcelable<Uri>(ARG_URI)?.let {
uri = it
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_photo, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val descriptor = requireContext().contentResolver.openFileDescriptor(uri, "r")
descriptor?.use {
val bitmap = BitmapFactory.decodeFileDescriptor(descriptor.fileDescriptor)
Glide.with(this).load(bitmap).into(imageView)
}
}
companion object {
@JvmStatic
fun newInstance(uri: Uri) =
PhotoFragment().apply {
arguments = Bundle().apply {
putParcelable(ARG_URI, uri)
}
}
}
}
+ 선행 학습 추천
프래그먼트의 생명주기, 콜백 메서드 (+ 액티비티의 생명주기)
companion object(동반객체): 여기로
+ arguments(전달인자): 함수가 호출될 때 제공되는 값들을 말한다. 함수를 호출 할 때마다 값이 바뀔 수 있다. 매개변수는 호출된 함수가 받는 값이고, argument는 명령행에서 명령어에 주는 값(value)이다.
+ Bundle(): Fragment 또는 Activity에서 다른 Fragment로 데이터를 전달할 때 사용하는 것이 Bundle()이다. 새로운 Fragment를 생성할 때 arguments에 Bundle()을 넘겨줌으로써 데이터를 넘겨줄 수 있다. (출처: 여기)
그럼 PhotoFragment에 작성된 내용을 하나하나 살펴보자.
먼저 이 부분을 설명해보려고 한다.
newInstance() 메서드와 onCreate() 콜백 메서드
작성된 기능을 자세히 알고싶은 분들께..
Bundle은 뭐고 Parcelable은 뭐고.. 찬찬히 자세히 차근차근 알고싶다면 더보기를 클릭!
- arguments = Bundle() 부분은 뭘까?
출처: 여기
먼저 arguments = Bundle() . . . 에 대한 이해를 돕고자 하는 다른 예시를 가져왔다.
MyFragment의 arguments에 String데이터인 "value"를 키값 "KEY"를 설정해 넘겨주고 있다.
그럼 이제 챕터9 전자액자에 나온 코드를 보자. 위에서 가져온 예시와 같은 패턴이다.
PhotoFragment의 arguments에 Bundle()을 통해 Parcelable 객체를 넘겨주고 있다.
"Parcelable을 구현하는 Uri클래스 타입 ARG_URI 상수"를 putParcelable() 메서드를 통해 Bundle()에 넘겨주고 있는 것이다.
- Parcelable 인터페이스란? Uri 클래스란?
Uri 클래스는 'Parcelable 인터페이스'를 구현하고 있는 Subclass고, 불변의 URI 참조값이 들어있다.
이제 작성된 내용을 보자.
<상황설명>
PhotoFragment 클래스 외부에 상수 ARG_URI를 선언하고 있다.
PhotoFragment 클래스 내부에 늦은 초기화로 uri변수를 Uri 클래스 타입으로 선언한다.
일단 그렇기 때문에, 아래 사진에서 볼 수 있듯이, Uri 클래스 타입이 될 ARG_URI라는 상수를 putParcelable() 메서드를 이용하여 Bundle()에 넣어주고 있는 것이다.
Uri 객체를 넣을 때는, Uri 클래스가 Parcelable 인터페이스의 서브클래스이기 때문에 putParcelable()을 사용한다.
그럼 이때 Parcelable하다는 것이 뭘까?
"안드로이드에서 앱을 개발할 때 종종 하나의 액티비티에서 다른 액티비티로 데이터를 전달하기 위해 인텐트에 전달할 데이터를 추가한다. 복잡합 클래스의 객체를 이동하려는 경우 Serializable 또는 Parcelable을 사용하여 직렬화하여 인텐트에 추가한다." - 출처: 여기
<도움될만한 사이트1>
이 링크에서 Serializable과 Parcelable 설명을 아주 멋지게 해주신다. 궁금하신 분들은 꼭 참고하시길..
(ㄴ와! 이 글 작성하신 분 카카오 안드로이드 소프트웨어 엔지니어시다.. 나도 열심히 해서 이런 멋진 글도 쓰고 카카오도 가야지)
<도움될만한 사이트2>
그리고 이 링크에서는 Parelable의 설명을 멋지게 해주신다!! 진짜 최고니까 읽어보세요~! Parcelable한 클래스를 만드는 방법도 친절하게 나와있다.
다시 내 포스팅에도 정리해놓자면,
Parcel(소포,꾸러미): 즉, 여러 데이터가 하나의 꾸러미(Class) 안에 담겨 있다.
Parcelalbe: 그 데이터 꾸러미가 A액티비테에서 B액티비티로 한꺼번에 전달되고 받아볼 수 있도록 해주는 것이라는 의미.
이렇게 Parcelable을 통해 직렬화를 하여 편하게 데이터를 주고받을 수 있다.
그래서 이 전자액자 챕터에서도, Parcelable인 Uri클래스 타입인 ARG_URI 상수를 putParcelable 메서드를 통해 Bundle()에 넘겨주고 있는 것이다.
위와 같은 데이터 넘김의 내용을 정의해놓은 함수인 newInstance()는 동반 객체(companion object) 안에 정의되어있다. (동반 객체에 대한 내용: 여기)
즉, PhotoFragment 클래스 객체 생성 여부와는 관계 없이 Uri 상수를 arguments에 전달해놓을 수 있는 것이다.
그렇게 전달해놓은 Uri 상수는 PhotoFragment가 인스턴스화 되고나서 onCreate() 콜백이 호출될 때 uri 변수를 통해 참조가능하도록 만들어진다.
- onCreate()에 작성된 내용
이제 onCreate() 콜백 부분을 보자.
아까 Uri 상수 정보 꾸러미를 넘겨놓은 arguments에서 getParcelable하고 있다.
이 때, 저 it이 뭔지 궁금한 분이 있을 거다. 그냥 it부분에 마우스 올려놓으면 설명해준다. 그렇다고 한다. uri 변수가 해당 Uri객체를 참조하도록 하는 것이다.
여기까지 정독하셨으면 이제는 아래 작성 부분이 이해가 잘 갈 것이다.
.
.
이제 나머지 부분을 정리하겠다.
이 부분을 마저 설명하겠다.
onCreateView() 콜백 메서드 - 뷰를 생성
프래그먼트를 작성할 때 오버라이드가 필요한 메서드들을 추가하면 자동으로 작성되는 부분이다.
이 메서드의 반환 타입을 보면 View이다. 즉, View를 반환하는 메서드이다. 프래그먼트에 View를 생성한다고 보면 된다. 우리는 R.layout.fragment_photo.xml 레이아웃을 객체화해야 한다.
레이아웃 리소스의 객체화는 inflate() 메서드를 통해 이루어진다.
ㅇinflate() 메서드 : xml파일의 view(layout)의 내용를 실제 view객체로 만드는 역할을 한다.
inflater.inflate() 를 사용하기 위해서는 LayoutInflater 객체를 생성해야 하는데, inflater를 작성하면 LayoutInflater가 import된다(자동import설정). import LayoutInflater 사용 준비가 된 것이다.
나머지 설명은 아래 내용을 읽어보시길 바란다. (출처: www.crocus.co.kr/1584)
++ 우리는 LayoutInflater를 import했으므로 1,2번은 해결된 것이다.
이렇게 inflater하면 최상위 부모인 View에다가 해당 xml의 내용을 담을 수 있다.
onViewCreated() 메서드 - 완성된 뷰를 전달받아 이벤트 처리
onViewCreated() 메서드는 뷰가 완성된 직후에 호출된다.
바로 위에서 언급한 onCreatedView 콜백에서 원하는 레이아웃 리소스를 객체화하여 View를 반환하고, 레이아웃 뷰를 완성한 것을 기억해보자. 뷰를 완성만 하면 뭐하는가? 그렇게 완성된 레이아웃 뷰를 전달받아서 이벤트 처리를 하는 메서드도 필요할 것이다.
이때, onViewCreated() 메서드에서 그 View를 전달받아 이벤트 처리 등을 수행한다.
참고: onViewCreated()는 프래그먼트 생명주기에 포함되지는 않는다.
ㅡ requireContext()
ㅡ ContentResolver
[간단히 설명하자면]
- ContentProvider: 앱의 데이터 접근을 다른 앱에 허용하는 컴포넌트. 외부 앱이 각종 데이터에(DB, 파일, 메모리..) 접근할 수 있게 도와주는 인터페이스를 제공한다. 앱 간의 데이터 공유를 위해 사용된다. 데이터에 직접 접근할 수 없으므로 컨텐트 프로바이더를 통해 다른 앱의 데이터를 사용한다.
- ContentResolver 객체는 전달자 느낌으로, ContentProvider에게 데이터를 요청하여 데이터를 받아올 수 있다.
ㅡ openFileDescripter()
ㅡ 나머지:
비트맵 정보를 받아와서 Glide 라이브러리를 사용해 현재 프래그먼트의 뷰에 해당 비트맵을 부른다. Glide 라이브러리에 대한 설명은 따로 찾아보길 바란다.
'JAVA' 카테고리의 다른 글
Spring 학습 1일차 - 자바 웹 개발 첫경험을 위해 (0) | 2021.02.07 |
---|---|
안드로이드 - 챕터10, 지도와 GPS (0) | 2021.01.28 |
동반객체와 팩토리 패턴 | companion object, Factory Method Pattern (0) | 2021.01.24 |
[안드로이드 스튜디오] Layout 개념 기본 정리 / View binding (0) | 2021.01.20 |
안드로이드 - ViewPager2를 이용한 슬라이더 학습 (0) | 2021.01.19 |