권한 설정하기
1. manifest.xml에 저장소 이용 권한 설정
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
2. 권한 허용 체크 후 필요에 따라 요청하기
/* 권한 가져오기 */
private fun checkPermission(){
val permissionCheck = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
if(permissionCheck != PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), REQUEST_CODE)
}else{
getPhotos() // 갤러리에서 이미지 가져오기
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if(REQUEST_CODE == requestCode){
if(grantResults.all { it == PackageManager.PERMISSION_GRANTED }){ // GRANTED
getPhotos() // 갤러리에서 이미지 가져오기
}else{ // DENIED
Snackbar.make(binding.root, "권한을 허용해야 사진을 가져올 수 있습니다.", Snackbar.LENGTH_INDEFINITE)
.setAction("재시도"){ checkPermission() }
}
}
}
갤러리 모든 이미지 가져오기
: MediaStore에 접근해서 모든 이미지의 절대 경로를 담은 리스트 리턴
fun loadImagesfromSDCard(activity: Activity): ArrayList<String> {
val uri: Uri = android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val cursor: Cursor?
val column_index_data: Int
val column_index_folder_name: Int
val listOfAllImages = ArrayList<String>()
var absolutePathOfImage: String? = null
val projection = arrayOf(MediaStore.MediaColumns.DATA, MediaStore.Images.Media.BUCKET_DISPLAY_NAME)
cursor = activity.contentResolver.query(uri, projection, null, null, null)
column_index_data = cursor!!.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA)
column_index_folder_name = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.BUCKET_DISPLAY_NAME)
while (cursor.moveToNext()) {
absolutePathOfImage = cursor.getString(column_index_data)
listOfAllImages.add(absolutePathOfImage)
}
return listOfAllImages
}
리사이클러뷰에서 이미지 뿌려주기
: Glide 이용
fun bind(url: String){
Glide.with(context).load(url).into(binding.itemGridIv)
}
더보기
리사이클러뷰 코드 전문
package com.softsquared.gridge_test.android.instagram_challenge.ui.post
import android.content.Context
import android.net.Uri
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.softsquared.gridge_test.android.instagram_challenge.data.dto.Post
import com.softsquared.gridge_test.android.instagram_challenge.data.dto.PostContent
import com.softsquared.gridge_test.android.instagram_challenge.databinding.ItemGridBinding
import com.softsquared.gridge_test.android.instagram_challenge.databinding.ItemPhotoBinding
import com.softsquared.gridge_test.android.instagram_challenge.ui.main.home.HomePostRVAdpater
import com.softsquared.gridge_test.android.instagram_challenge.utils.getDeviceWidth
import com.softsquared.gridge_test.android.instagram_challenge.utils.setHeight
import com.softsquared.gridge_test.android.instagram_challenge.utils.setWidth
import java.io.File
class PostGridRVAdapter(val context: Context): RecyclerView.Adapter<PostGridRVAdapter.ViewHolder>() {
private val fileList = arrayListOf<String>()
private val imageList: HashMap<Int, String> = hashMapOf()
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
val binding = ItemGridBinding.inflate(LayoutInflater.from(viewGroup.context), viewGroup, false)
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(position, fileList[position])
holder.binding.root.setOnClickListener {
if(imageList.containsKey(position)){
imageList.remove(position)
}else{
imageList.put(position, fileList[position])
}
myItemClickListener.selectImage(fileList[position], imageList.size)
notifyItemChanged(position)
}
}
override fun getItemCount(): Int = fileList.size
inner class ViewHolder(val binding: ItemGridBinding): RecyclerView.ViewHolder(binding.root){
fun bind(position: Int, url: String){
if(imageList.containsKey(position)){
binding.itemGridSelectedV.visibility = View.VISIBLE
}else{
binding.itemGridSelectedV.visibility = View.GONE
}
val width = getDeviceWidth()/4
binding.itemGridIv.setWidth(width)
binding.itemGridIv.setHeight(width)
Glide.with(context).load(url).into(binding.itemGridIv)
}
}
/* 아이템 추가, 삭제 */
fun addImages(list: ArrayList<String>){
fileList.clear()
fileList.addAll(list)
notifyDataSetChanged()
}
fun setSelectedPhoto(photoList: ArrayList<String>){
imageList.clear()
fileList.forEach { file ->
photoList.forEach { photo ->
if(file == photo){
imageList.put(fileList.indexOf(file), photo)
}
}
}
notifyDataSetChanged()
}
fun selectedSize(): Int{
return imageList.size
}
/* 클릭 이벤트 관리 */
interface MyItemClickListener{
fun selectImage(url: String, size: Int)
}
private lateinit var myItemClickListener: MyItemClickListener
fun setMyItemClickListener(myItemClickListener: MyItemClickListener) {
this.myItemClickListener = myItemClickListener
}
}
※ open failed: EACCES (Permission denied) 에러
: 절대 경로로 파일에 접근할 수 없다는 에러, 모든 권한을 허용해야 한다
1. manifest.xml에 저장소 이용 권한 설정
2. manifest.xml의 <application> 태그에 requestLegacyExternalStorage 속성 설정
android:requestLegacyExternalStorage="true"
3. 사용자로부터 권한 승인 받기
구현 화면
: 받아온 이미지를 상단은 뷰페이저, 하단은 리사이클러뷰에 뿌려주어 인스타그램 사진 선택과 동일한 화면을 만들었다
<참고>
'💻 Android' 카테고리의 다른 글
[Android] Android CI/CD 구축하기 (1) - Firebase App Distribution, Play store 테스트 트랙 (0) | 2024.05.25 |
---|---|
[Android] Android 13 마이그레이션 (0) | 2024.03.09 |
[Android/IOS] 인앱 리뷰 기능 추가하기 (2) | 2023.09.23 |
[Android] 인스타그램 DM으로 공유하기 기능 만들기 (0) | 2023.09.23 |
[Android/MySQL] 안드로이드에서 JDBC 사용하기 (0) | 2022.11.08 |