전자액자 만들기 (2) - 액티비티 생명주기

2022. 12. 16. 14:04Android

이번에는 사진을 가지고 화면을보여주기때문에 Activtiy랑 레이아웃을 하나더만들어보겟습니다.

 

  • PhotoFrameActivity.kt
package com.example.actionmovie

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity

class PhotoFrameActivity: AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_photoframe)
    }

}

메인액티비에 만들어준다. onCreate함수를 실행하려면  레이아웃도만들어줘야하고 매니페스트에도 이름을 추가해줘야한다.

  • AndroidManifest.xml
<activity android:name=".PhotoFrameActivity"/>
  • layout -> new -> Layout Resource File 에  <파일이름: activity_photoframe 만들자.>
  • activity_photoframe.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

</androidx.constraintlayout.widget.ConstraintLayout>
  • PhotoFrameActivity 레이아웃
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/backgroundPhotoImageView"
        android:background="@color/black"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        android:scaleType="center"
        app:layout_constraintTop_toTopOf="parent"/>


    <ImageView
        android:id="@+id/photoImageView"
        android:background="@color/black"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        android:scaleType="center"
        app:layout_constraintTop_toTopOf="parent"/>




</androidx.constraintlayout.widget.ConstraintLayout>

 

  • MainPhotoFrameActivity.kt
package com.example.actionmovie

import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.ImageView
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat
import com.example.actionmovie.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    private val addphotoButton: Button by lazy {
        binding.addPhotoButton
    }
    private val startphotoFrameModeButton: Button by lazy {
        binding.startPhotoFrameModeButton
    }
    private val imageViewList: List<ImageView> by lazy {
        mutableListOf<ImageView>().apply {
            add(binding.imageView11)
            add(binding.imageView12)
            add(binding.imageView13)
            add(binding.imageView21)
            add(binding.imageView22)
            add(binding.imageView23)
        }
    }
    private val imageUriList: MutableList<Uri> = mutableListOf()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        initaddPhotoButton()
        initstartPhotoFrameModeButton()
    }

    private fun initaddPhotoButton() {
        binding.addPhotoButton.setOnClickListener {
            binding.addPhotoButton.text = "사진이 추가되엇습니다!"
            when {
                //todo 파일 접근권한이 부여됫는지 확인하고 사진을 선택하는 기능
                ContextCompat.checkSelfPermission(
                    this,
                    android.Manifest.permission.READ_EXTERNAL_STORAGE
                ) == PackageManager.PERMISSION_GRANTED -> {
                    navigatePhotos()
                }
                //todo 권한을 명시적으로 거부한 경우 나 처음보거나 다시 묻지 않음을 선택한 경우
                shouldShowRequestPermissionRationale(
                    android.Manifest.permission.READ_EXTERNAL_STORAGE
                ) -> {
                    //todo 팝업 확인 후 권한 팝업을 띄우는 기능
                    showPermissionContextPopup()
                }
                else -> {
                    //todo 처음 봣을때 띄워주는 코드
                    requestPermissions(
                        arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE),
                        1000
                    )
                }
            }
        }
    }

    private fun initstartPhotoFrameModeButton() {
        binding.startPhotoFrameModeButton.setOnClickListener {
            binding.startPhotoFrameModeButton.text = "전자액자가 실행되엇습니다."
            val intent = Intent(this, PhotoFrameActivity::class.java)
            imageUriList.forEachIndexed { index, uri ->
                intent.putExtra("photo$index", uri.toString())
            }
            intent.putExtra("photoListSize", imageUriList.size)
            startActivity(intent)
        }
    }

    //todo 권한을 허락하거나 거부햇을때 코드를 구현
    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray,
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        when (requestCode) {
            1000 -> {
                if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    //todo 권한이 잘부여된것
                    navigatePhotos()
                }
            }
        }
    }

    private fun navigatePhotos() {
        //사진 목록 출력
        val intent = Intent(Intent.ACTION_GET_CONTENT)
        intent.type = "image/*"
        startActivityForResult(intent, 2000)
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        if (resultCode != Activity.RESULT_OK) {
        Toast.makeText(this,"잘못된 접근입니다.",Toast.LENGTH_SHORT).show()
            return
        }
        when (requestCode) {
            2000 -> {
                val selectedImageUri: Uri? = data?.data

                if (selectedImageUri != null) {

                    if (imageUriList.size == 6) {
                        Toast.makeText(this, "이미 사진이 꽉 찻습니다.", Toast.LENGTH_SHORT).show()
                        return
                    }

                    imageUriList.add(selectedImageUri)
                    imageViewList[imageUriList.size - 1].setImageURI(selectedImageUri)
                }
            }
        }
    }

    private fun showPermissionContextPopup() {
        AlertDialog.Builder(this)
            .setTitle("권한이 필요합니다")
            .setMessage("전자액자에 앱에서 사진을 불러오기 위해 권한이 필요합니다")
            .setPositiveButton("동의하기") { _, _ ->
                requestPermissions(arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE), 1000)
            }
            .setNegativeButton("취소하기") { _, _ -> }
            .create()
            .show()
    }
}

 

  • timer함수를이용
  • 5초마다 사진이 바뀌는걸볼수잇다.
timer(period = 5 * 1000)

 

 

  •  액티비티 생명주기를 마지막으로 완성도를 높이도록하겟습니다.
  •  사진을추가하고 전자액자실행버튼을누르면 OnCreate -> OnStart -> OnResume첫 화면실행시 호출됨.
override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_photoframe)
        Log.d("PhotoFrame", "OnCreate!!")
    
override fun onStart() {
        super.onStart()
        Log.d("PhotoFrame", "OnStart!! timer start")
        startTimer()
          
override fun onResume() {
        super.onResume()
        Log.d("PhotoFrame", "OnResume!! timer start

override fun onPause() {
        super.onPause()
        Log.d("PhotoFrame", "OnPause!! timer Pause")
        timer?.cancel()
    }
        
override fun onStop() {
        super.onStop()
        Log.d("PhotoFrame", "OnStop!! timer cancel")
        timer?.cancel()
    }
override fun onDestroy() {
        super.onDestroy()
        Log.d("PhotoFrame", "OnDestroy!! 앱이 종료되었습니다")
        timer?.cancel()
    }
}

 

  • 백그라운드시 OnPasue ->  Onstop 순으로 함수가호출되고. 다시 앱을 실행하면 OnResume OnStart함수가 호출됨
  • 앱을 종료시키면 OnStop -> OnDestroy 함수가호출됩니다.

 

  • 전체코드
package com.example.actionmovie

import android.icu.text.Transliterator.Position
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity
import com.example.actionmovie.databinding.ActivityMainBinding
import com.example.actionmovie.databinding.ActivityPhotoframeBinding
import java.util.Timer
import kotlin.concurrent.timer

class PhotoFrameActivity : AppCompatActivity() {
    
    private var mainBinding: ActivityPhotoframeBinding? = null
    private val binding get() = mainBinding!!

    private val photoList = mutableListOf<Uri>()
    private var Position = 0
    private var timer: Timer? = null

    private val photoImageView: ImageView by lazy {
        binding.photoImageView
    }
    private val backgroundPhotoImageView: ImageView by lazy {
        binding.backgroundPhotoImageView
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        mainBinding = ActivityPhotoframeBinding.inflate(layoutInflater)
        setContentView(binding.root)
        Log.d("PhotoFrame", "OnCreate!!")
        getphotoUriFromIntent()

    }

    private fun getphotoUriFromIntent() {
        val size = intent.getIntExtra("photoListSize", 0)
        for (i in 0..size) {
            intent.getStringExtra("photo$i")?.let {
                photoList.add(Uri.parse(it))
            }
        }
    }

    private fun startTimer() {
        timer = timer(period = 5 * 1000) {
            runOnUiThread {
                Log.d("PhotoFrame", "5초가지나감!!!!!!")
                val current = Position
                val next = if (photoList.size <= Position + 1) 0 else Position + 1
                binding.backgroundPhotoImageView.setImageURI(photoList[current])
                binding.photoImageView.alpha = 0f
                binding.photoImageView.setImageURI(photoList[next])
                binding.photoImageView.animate().alpha(1.0f).setDuration(1000).start()
                Position = next
            }
        }
    }

    // 액티비티 생명주기

    override fun onStop() {
        super.onStop()
        Log.d("PhotoFrame", "OnStop!! timer cancel")

        timer?.cancel()
    }

    override fun onStart() {
        super.onStart()
        Log.d("PhotoFrame", "OnStart!! timer start")
        startTimer()
    }


    override fun onResume() {
        super.onResume()
        Log.d("PhotoFrame", "OnResume!! timer start")
        startTimer()
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.d("PhotoFrame", "OnDestroy!! 앱이 종료되었습니다")
        timer?.cancel()
    }
}

 

  • 결과화면