일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- GIT
- table
- SSL
- plugin
- hadoop
- Eclipse
- react
- Spring
- tomcat
- es6
- mybatis
- Python
- R
- Java
- SPC
- 공정능력
- vaadin
- Kotlin
- Express
- 보조정렬
- Android
- xPlatform
- Sqoop
- mapreduce
- IntelliJ
- JavaScript
- MSSQL
- SQL
- NPM
- window
- Today
- Total
DBILITY
안드로이드 정리 2 본문
사진을 찍으면 내부 저장소에 저장되고 미디어데이터베이스에도 정보가 저장된다. Contents Provider(앱의 데이터 접근을 다른 앱에 허용하는 콤포넌트)를 사용해 다른 앱에 공개될 수 있다.
안드로이드 주요 콤포넌트는 다음과 같다고
- Activity : 화면을 구성
- Contents Provider : 데이터베이스,파일,네트워크의 데이터를 다른 앱에 공유
- Broadcast Receiver : 앱이나 기기가 발송하는 방송(?)을 수신
- Service : 화면이 없는 백그라운드 작업용
안드로이드 저장소
- 내부 저장수 : OS설치영역으로 시스템영역,앱이 사용하는 정보와 데이터베이스가 저장
- 외부 저장소 : 컴퓨터에 디바이스를 연결하면 저장소로 인식, 유저영역. 사진,동영상은 여기에 저장
저장소 접근을 위해서 AndroidManifest 에 권한을 부여해야 한다.
<uses-permission
android:name="android.permission.READ_MEDIA_IMAGES"
android:minSdkVersion="33" />
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
접근권한도 버전에 따라 다르게 정의 된다.android.Manifest 패키지의 permission을 확인하자.
Manifest.permission.READ_MEDIA_IMAGES( 33이상), Manifest.permission.READ_EXTERNAL_STORAGE 등등
실행시점에 권한이 있는지 체크를 해야하는데 이럴땐 ContextCompat(ActivityCompat).checkSelfPermisstion()을 사용한다.
https://developer.android.com/training/permissions/requesting?hl=ko
스토리지를 읽는 방법도 버전마다 다르다. MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL), MediaStore.Images.Media.EXTERNAL_CONTENT_URI(29미만) 등등
다음을 참고하자.
https://developer.android.com/training/data-storage/shared/media?hl=ko
class MainActivity : AppCompatActivity() {
private val binding by lazy {
ActivityMainBinding.inflate(layoutInflater)
}
//읽기 권한
private val permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
Manifest.permission.READ_MEDIA_IMAGES
} else {
Manifest.permission.READ_EXTERNAL_STORAGE
}
//스토리지 URI
private val contentUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL)
} else {
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
}
private val requestPermissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
Log.d("RequestPermission", isGranted.toString())
if (isGranted) {
getAllPhotos(contentUri)
} else {
AlertDialog.Builder(this).apply {
setTitle("경고")
setMessage("권한 설정을 거부하여 접근할 수 없습니다")
setPositiveButton("종료") { _, _ ->
Handler(mainLooper).postDelayed({
finishAndRemoveTask()
exitProcess(0)
}, 100)
}
}.show()
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
//requestCode를 직접관리하는 경우 구현
when (requestCode) {
1 -> {
if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
getAllPhotos(contentUri)
} else {
AlertDialog.Builder(this).apply {
setTitle("경고")
setMessage("권한 설정을 거부하여 접근할 수 없습니다")
setPositiveButton("종료") { _, _ ->
Handler(Looper.getMainLooper()).postDelayed({
finishAndRemoveTask()
exitProcess(0)
}, 100)
}
}.show()
}
}
else -> {
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
//권한이 있는지 확인
if (ContextCompat.checkSelfPermission(this, permission)
!= PackageManager.PERMISSION_GRANTED
) {
//권한 요청을 거부한 적이 있는 경우
if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) {
AlertDialog.Builder(this).apply {
setTitle("권한요청")
setMessage("사진 정보를 얻으면 외부 저장소 권한이 필요합니다.")
setPositiveButton("수락") { _, _ ->
//requestPermissionLauncher.launch(permission) // 시스템이 requestCode 코드를 관리
ActivityCompat.requestPermissions(this@MainActivity, arrayOf(permission), 1) // 직접 requestCode 관리
}
setNegativeButton("거부", null)
}.show()
} else {
//requestPermissionLauncher.launch(permission)
ActivityCompat.requestPermissions(this@MainActivity, arrayOf(permission), 1)
}
return
}
getAllPhotos(contentUri)
}
private fun getAllPhotos(collection: Uri) {
Log.d("MainActivity", "getAllPhotos $collection")
val uris = mutableListOf<Uri>()
contentResolver.query(
collection,
null,
null,
null,
"${MediaStore.Images.ImageColumns.DATE_TAKEN} DESC"
)?.use { cursor ->
while (cursor.moveToNext()) {
val id =
cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID))
val contentUri =
ContentUris.withAppendedId(collection, id)
uris.add(contentUri)
}
}
Log.d("MainActivity", "getAllPhotos -----> ${uris}")
}
}
AlertDialog도 평이하다. builder에 themeResId를 적용할 수 있다. 예쁘게?
this.onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
Log.d("handleOnBackPressed", dateFormat.format(Date()))
AlertDialog.Builder(this@MainActivity,android.R.style.Theme_DeviceDefault_Light_Dialog_NoActionBar_MinWidth).apply {
setTitle("Information")
setMessage("terminate?")
setPositiveButton("Yes") { dialog, which ->
Log.d("handleOnBackPressed Yes", "${dialog.toString()} $which")
}
setNegativeButton("No") { dialog, which ->
Log.d("handleOnBackPressed No", "$dialog $which")
}
}.show()
}
})
사용법을 참고하자.
https://developer.android.com/guide/topics/ui/dialogs?hl=ko
프래드먼트(Fragment)는 말 그대로 조각, 액티비티를 구성하는 인터페이스의 모음이다.음..그냥 액티비티에 여러 요소를 배치할때 분할하기 위해 필요하다고 생각하자. 그런데 이건 생명주기도 따로 있고, 재사용이 가능하다. 콤포넌트군
https://developer.android.com/guide/components/fragments?hl=ko#Lifecycle
Activity처럼 보통 하나의 xml과 소스파일로 구성된다. parcel을 해석하면 쉽다. 뭔가 생성시점에 보내는 객체(소포)겠군..호출자,피호출자 사이에 데이터 전달(?)에 필요하겠다. 그러나 Activity처럼 화면에 바로 나타나는게 아니다.
아래는 두개의 Fragment를 작성하고 MainActivity에는 각각을 호출하는 버튼과 Fragment가 보여질 FrameLayout(FragmentContainerView가 Fragemnt 전용이라고)을 위치 시켜 테스트한 코드와 화면이다. gradle dependency에 androidx.fragment:fragment-ktx:1.6.2를 추가했다.
fragment끼리 값을 주고 받을 때는 setFragmentResult, setFragmentResultListener를 사용한다고 함
fragmentManager는 다음을 참고하자.
https://developer.android.com/guide/fragments/fragmentmanager?hl=ko
class MainActivity : AppCompatActivity() {
private val binding by lazy {
ActivityMainBinding.inflate(layoutInflater)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
binding.run {
btnFirstFragment.setOnClickListener {
setFragment(FirstFragment())
}
btnSecondFragment.setOnClickListener {
setFragment(SecondFragment())
}
}
}
private fun setFragment(fragment: Fragment) {
supportFragmentManager.commit {
replace(binding.frameLayout.id, fragment)
setReorderingAllowed(true)
addToBackStack("")
}
}
}
Image를 로딩할때는 bitmap에 coil library(사진 로딩에 특화되어 메모리절약,부드러운 로딩)를 사용해서 load한다. 그게 메모리관리나 성능면에서 좋다고
ViewPager2는 프래그먼드를 슬라이드하는 Adapter를 구현하는 view다. FragmentStateAdapter를 상속받아 구현된 adapter를 연결해야한다.
'android > kotlin' 카테고리의 다른 글
firebase block request... (0) | 2024.01.26 |
---|---|
안드로이드 정리 3 (0) | 2024.01.23 |
android avd path change ( 경로 변경 ) (0) | 2024.01.16 |
android bmi (0) | 2024.01.11 |
안드로이드 정리 1 (0) | 2023.09.15 |