[Android] java.lang.RuntimeException: Unable to start activity ComponentInfo{…} java.lang.IllegalStateException: Fragment not attached to a context. 에러

알린·2024년 2월 27일
0

TroubleShooting

목록 보기
23/25

에러 상황

카카오맵 API를 사용해 프래그먼트에 현위치를 기반으로 지도를 불러오는 코드 작성 중,
해당 프래그먼트 화면에 진입하지 못하고 이전 액티비티로 다시 돌아가며 아래와 같은 에러 메세지가 떴다.

java.lang.RuntimeException: Unable to start activity ComponentInfo{…} java.lang.IllegalStateException: Fragment not attached to a context.

이 때 코드에서 Fragment에서는 this를 사용할 수 없으니, context를 사용해야 할 곳에 다음 코드처럼 모두 requireContext()를 사용했다.

val locationProvider = LocationProvider(requireContext())
    
Toast.makeText(requireContext(), error.message, Toast.LENGTH_SHORT).show()

에러 원인 및 해결

에러 원인

에러 메세지에서 확인할 수 있듯이, Fragment가 아직 액티비티에 연결되어 있지 않은 상태에서 requireContext() 메서드를 호출하였기 때문에 발생한 에러이다.
즉, 이 에러는 Fragment가 부모 Activity에 더 이상 연결되어 있지 않은 상태에서 Fragment의 컨텍스트(context)에 접근하려고 할 때 발생한다.

에러 해결

Fragment가 액티비티에 연결되어 있는지 확인한 후,
해당 메서드나 컨텍스트 관련 작업을 수행애햐 한다.

    private val startZoomLevel = 15
    private lateinit var startPosition: LatLng

    val locationProvider = LocationProvider(requireContext())
    val uLatitude = locationProvider.getLocationLatitude()
    val uLongtitude = locationProvider.getLocationLongitude()
    
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentHomeBinding.inflate(layoutInflater)

        // 현재 로그인한 사용자 가져오기
        user = Firebase.auth.currentUser
        Log.d("MyTag", "HomeFragment user info: ${user}")

        checkAllPermissions()

        return binding.root
    }

위의 코드는 requireContext()를 사용한 수정 전 코드이고, 현재 문제 해결에 필요한 코드만 부분으로 잘라왔다. 이를 다음과 같이 수정한다.

mActivity를 전역변수로 선언 후,
onAttach()에서 인자로 넘겨진 context를 사용해
mActivity를 초기화하여 requireContext()를 mActivity로 수정해준다.

    private lateinit var mActivity: MainActivity
    
    val locationProvider = LocationProvider(mActivity)

    override fun onAttach(context: Context) {
        super.onAttach(context)
        mActivity = context as MainActivity
    }

💡 onAttach()
Fragment의 생명주기 중, onAttach() 콜백 메소드는 FragmentManager에 추가가되고 이후에 주인 Activity에 attach 될 때 호출된다.
이 시점에서 프래그먼트는 활성화되고 FragmentManager가 프레그먼트의 생명주기 state를 관리한다.
또한 findFragmentById()같은 FragmentMaanger 메소드가 프레그먼트를 반환한다.
인자로 context가 주어진다.

수정한 코드

    private lateinit var mActivity: MainActivity
    
    private val startZoomLevel = 15
    private lateinit var startPosition: LatLng

    val locationProvider = LocationProvider(mActivity)
    val uLatitude = locationProvider.getLocationLatitude()
    val uLongtitude = locationProvider.getLocationLongitude()

    override fun onAttach(context: Context) {
        super.onAttach(context)
        mActivity = context as MainActivity
    }
    
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentHomeBinding.inflate(layoutInflater)

        // 현재 로그인한 사용자 가져오기
        user = Firebase.auth.currentUser
        Log.d("MyTag", "HomeFragment user info: ${user}")

        checkAllPermissions()

        return binding.root
    }
profile
Android 짱이 되고싶은 개발 기록 (+ ios도 조금씩,,👩🏻‍💻)

0개의 댓글