728x90
이번에는 포스팅을 업로드하는 PostCreate 부분에 대해서 리뷰를 해보자.
이 기능은 EditTextView 뿐만 아니라 이미지 또한 스마트폰 갤러리에서 선택하여 파이어베이스 저장소에 저장해야
전체코드
class PostCreateActivity : AppCompatActivity() {
lateinit var binding: ActivityPostCreateBinding
private val viewModel: PostCreateViewModel by viewModels()
private val fileChooserContract =
registerForActivityResult(ActivityResultContracts.GetContent()) { imageUri ->
if (imageUri != null) {
viewModel.selectImage(imageUri)
} else if (viewModel.uiState.value.selectedImage == null && viewModel.uiState.value.isCreating) {
finish()
}
}
companion object {
fun getIntent(
context: Context,
postContent: String,
postImage: String,
postUuid: String
): Intent {
return Intent(context, PostCreateActivity::class.java)
.putExtra("content", postContent)
.putExtra("image", postImage)
.putExtra("uuid", postUuid)
}
}
@RequiresApi(Build.VERSION_CODES.O)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityPostCreateBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.postBackButton.setOnClickListener {
finish()
}
val glide = Glide.with(this)
val contentEditText = binding.imageExpression
val imageView = binding.addImage
val backButton = binding.postBackButton
val postButton = binding.postButton
val postContent = intent.getStringExtra("content")
val postImage = intent.getStringExtra("image")
val postUuid = intent.getStringExtra("uuid")
val storage: FirebaseStorage =
FirebaseStorage.getInstance("~~~~")
val storageReference = storage.reference
if (postContent != null && postImage != null && postUuid != null) {
viewModel.changeToEditMode()
val postReference = postImage.let { storageReference.child(it) }
postReference.downloadUrl.addOnSuccessListener { uri ->
glide
.load(uri)
.into(binding.addImage)
}
binding.toolbarTitle.text = getString(R.string.post_edit)
binding.postButton.text = getString(R.string.post_editting)
contentEditText.setText(postContent)
} else {
showImagePicker()
}
postButton.setOnClickListener {
if (!viewModel.uiState.value.isCreating) {
viewModel.editContent(postUuid.toString(), contentEditText.text.toString())
} else {
viewModel.uploadContent(contentEditText.text.toString())
}
}
imageView.setOnClickListener {
showImagePicker()
}
backButton.setOnClickListener {
finish()
}
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect(::updateUi)
}
}
}
private fun updateUi(uiState: PostCreateUiState) {
if (uiState.selectedImage != null) {
binding.addImage.setImageURI(uiState.selectedImage)
}
if (uiState.userMessage != null) {
showSnackBar(getString(uiState.userMessage))
viewModel.userMessageShown()
}
if (uiState.successToUpload) {
Toast.makeText(this, "게시글 업로드에 성공했습니다.", Toast.LENGTH_LONG).show()
setResult(RESULT_OK)
finish()
}
binding.postButton.apply {
isEnabled = !uiState.isLoading
alpha = if (uiState.isLoading) 0.5F else 1.0F
}
}
private fun showImagePicker() {
if (!viewModel.uiState.value.isLoading) {
fileChooserContract.launch("image/*")
}
}
private fun showSnackBar(message: String) {
val root = binding.postingRoot
Snackbar.make(root, message, Snackbar.LENGTH_LONG).show()
}
}
중요 부분에 대해서만 짧게 리뷰를 해보자.
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect(::updateUi)
}
}
이 코드는 코루틴과 Android LifeCycle을 활용하여 UI업데이트를 관찰하는 부분이다.
만약 UiState에서 변경점이 생긴다면 STARTED 상태일 때마다 해당 상태에 따라 Ui를 업데이트하는 작업을 비동기적으로 수행한다.
이를 통해서 사용자의 선택결과를 실시간으로 Toast나 Message 형태로 UI에 업데이트 할 수 있을 뿐만 아니라 안전하게 UI를 업데이트 할 수 있다.
private val fileChooserContract =
registerForActivityResult(ActivityResultContracts.GetContent()) { imageUri ->
if (imageUri != null) {
viewModel.selectImage(imageUri)
} else if (viewModel.uiState.value.selectedImage == null && viewModel.uiState.value.isCreating) {
finish()
}
}
이 코드는 Android에서 제공하는 Activity Result API를 사용하여 파일(이미지)을 선택하는 작업을 처리하는 부분이다.
- fileChooserContract는 Activity Result API에서 제공하는 GetContent 계약을 사용하여 파일(이미지)을 선택하는 동작을 처리한다.
- registerForActivityResult 함수를 사용하여 계약을 등록하고, 이 계약에 따라 작동할 콜백을 정의한다.
- 콜백은 파일(이미지) 선택 결과를 처리하고 선택된 이미지의 URI가 imageUri로 전달된다.
- imageUri가 null이 아닌 경우, viewModel.selectImage(imageUri)를 호출하여 선택된 이미지를 ViewModel에 전달한다.
- 그렇지 않고, 이미지가 선택되지 않았고, 동시에 ViewModel이 현재 게시물을 생성 중인 상태인 경우(viewModel.uiState.value.isCreating), 현재의 액티비티를 종료한다(finish()).
728x90
'Android > Study' 카테고리의 다른 글
[Android] 포스팅 업로드 구현 (3) - 화면 XML (0) | 2024.02.26 |
---|---|
[Android] 포스팅 업로드 구현 (2) - ViewModel (0) | 2024.02.26 |
[Android] 로그인 기능 구현 (4) - Repository (0) | 2024.02.09 |
[Android] 로그인 기능 구현 (3) - ViewModel (0) | 2024.01.21 |
[Android] ktlint, detekt를 적용해보기 (0) | 2024.01.20 |