태터데스크 관리자

도움말
닫기
적용하기   첫페이지 만들기

태터데스크 메시지

저장하였습니다.

다수의 프래그먼트 및 구글맵 프래그먼트를 사용할 때 자주 발생하는 오류 대처법

2014.04.07 02:04

프래그먼트를 사용하다 보면 생각치도 못한 곳에서 오류가 자주 발생하곤 합니다. 이 포스트에서는 프래그먼트를 사용하다 보면 자주 접할 수 있는 오류 두 가지를 소개하고, 각 오류에 대한 해결 방법에 대해 다룹니다.


1. duplicate id tag null or parent id with another fragment for com.google.android.gms.maps.mapfragment


구글맵을 사용하다 보면 빈번하게 접하는 오류입니다. 분명 잘못된 것이 없어 보이는데, 위와 같은 오류가 뜨면 참 난감하지요. 에러 로그는 일반적으로 다음과 유사한 형태입니다.


android.view.InflateException: Binary XML file line #7: 

     Error inflating class fragment

   at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:704)

   at android.view.LayoutInflater.rInflate(LayoutInflater.java:746)

   at android.view.LayoutInflater.inflate(LayoutInflater.java:489)

   at android.view.LayoutInflater.inflate(LayoutInflater.java:396)

   at com.nfc.demo.MapFragment.onCreateView(MapFragment.java:15)

   at android.app.Fragment.performCreateView(Fragment.java:1695)

   at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:885)

   at android.app.FragmentManagerImpl.attachFragment(FragmentManager.java:1255)

   at android.app.BackStackRecord.run(BackStackRecord.java:672)

   at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1435)

   at android.app.FragmentManagerImpl$1.run(FragmentManager.java:441)

   at android.os.Handler.handleCallback(Handler.java:725)

   at android.os.Handler.dispatchMessage(Handler.java:92)

   at android.os.Looper.loop(Looper.java:137)

   at android.app.ActivityThread.main(ActivityThread.java:5039)

   at java.lang.reflect.Method.invokeNative(Native Method)

   at java.lang.reflect.Method.invoke(Method.java:511)

   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)

   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)

   at dalvik.system.NativeStart.main(Native Method)


Caused by: java.lang.IllegalArgumentException: 

     Binary XML file line #7: Duplicate id 0x7f040005, tag null, or 

     parent id 0xffffffff with another fragment for 

     com.google.android.gms.maps.MapFragment

   at android.app.Activity.onCreateView(Activity.java:4722)

   at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:680)

   ... 19 more


이와 유사한 형태의 다른 에러를 하나 더 봅시다.


2. the specified child already has a parent. you must call removeview() on the child's parent first


이 에러도 프래그먼트를 사용하다 보면 접하기 쉬운데, 주로 여러 프래그먼트를 전환하는 구성을 사용할 때 발생하기 쉽습니다. (FragmentTransaction.replace(), add(), remove() 등을 사용하여 한 액티비티 내에서 선택한 메뉴에 따라 다른 프래그먼트를 보여주는 경우가 대표적인 예)


위에서 본 두 사례의 원인은 모두 '프래그먼트를 구성하는 뷰(View)를 중복해서 레이아웃 내에 추가하려 했기 때문' 입니다. 프래그먼트가 화면에 표시되는 과정에서, 프래그먼트가 표시되는 뷰(컨테이너 뷰)에 프래그먼트의 뷰가 추가되는데, 이 상테에서 다시 프래그먼트를 추가하면 뷰가 중복되어 오류가 발생하는 것입니다.


이를 방지하려면, 프래그먼트가 화면에서 사라질 때 프래그먼트의 뷰를 컨테이너 뷰에서 제거해주면 됩니다. 일반적으로 다음과 프래그먼트의 코드 내에 onDestroyView()를 다음과 같이 오버라이드 하면 됩니다. 프래그먼트가 화면에서 사라질 때, 컨테이너 뷰(parent)에서 프래그먼트 뷰(v)를 제거하여 이후에 중복 추가되는 것을 방지하는 원리입니다.

static View v; // 프래그먼트의 뷰 인스턴스
@Override
public void onDestroyView() {
    super.onDestroyView();
    if(v!=null){
        ViewGroup parent = (ViewGroup)v.getParent();
        if(parent!=null){
            parent.removeView(v);
        }
    }
}

간혹, 구글맵(MapFragment, SupportMapFragment)을 사용하는 프래그먼트의 경우 위 코드를 적용해도 inflate시 에러가 발생하는 경우가 있습니다. 이를 방지하려면 아래 코드를 onCreateView()에 추가하면 됩니다.

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
        try{
            v = inflater.inflate(R.layout.fragment_nearby, container, false);
        }catch (InflateException e){
            // 구글맵 View가 이미 inflate되어 있는 상태이므로, 에러를 무시합니다.
        }
        // 이후 메서드 구현 계속
}


저작자 표시 비영리 변경 금지
신고

커니 안드로이드 개발 팁/일반 , , , , , , , , , , , , , , , , , ,

  1. Blog Icon
    이정훈

    안녕하세요. 지금 현재 개발 중인 앱에 구글맵을 넣고 있는데요, 블로그 보면서 지도를 띄우는 것 까지는 했는데 맵의 위치를 이동시키고 싶어서 moveCamera를 썼는데요 GoogleMap으로 선언된 변수가 null이 더라고요

    FragmentManager fm = getChildFragmentManager();
    mSupportMap = (SupportMapFragment) fm.findFragmentById(R.id.map);
    if (mSupportMap == null) {
    mSupportMap = SupportMapFragment.newInstance();
    fm.beginTransaction().replace(R.id.map, mSupportMap).commit();
    }
    if (mGoogleMap == null) {
    mGoogleMap = mSupportMap.getMap();
    }
    이런식으로 맵데이터를 받아 오려고 하는데 mSupportMap.getMap()을 걸쳐도 mGoogleMap이 null이네요..
    맵 데이터 받아오는 방법좀 알려주세요..

  2. Blog Icon
    이정훈

    아 선언된 곳은 extends Fragment 클레스의 onCreateView 입니다.
    지금 보니 2번째 줄의 mSupportMap에서도 null이 네요ㅠㅠ

  3. 자세한 로직은 잘 모르겠습니다만, SupportMapFragment는 null이 아닌게 확실한가요? findFragmentById()에서 SupportMapFragment가 null이 되었다면 레이아웃에 있는 프래그먼트의 인스턴스를 가져오지 못했다는 말인데, 이 경우 새로 생성하는 것이 아니라 인스턴스를 받아오지 못한 원인을 분석하여 제대로 인스턴스를 받도록 수정해야 할 것으로 생각됩니다.

  4. Blog Icon
    이민구

    안녕하세요 현재 TAB을 클릭해서 프래그먼트를 replace 합니다 .
    그런데 하나는 listview Fragment 이고 하나는 Map Fragment 입니다 ( map 프래그먼트는 Fragment를 상속받아서 거기에서 XML을 inflater 시켜서 합니다. ( XML 에 SupportMapFragment 를 사용 했습니다)
    위 말씀하신 오류가 나서 ondestroy view 에서 사용해서 다 종료 했고 onCreateview에서 try - catch 문을 써서 했는데
    왔다갔다 하니 try에 걸려서 inflater을 시키지 않아 맵뷰가 나오지 않습니다 ;;
    왜이럴까요 ㅠ?

  5. Blog Icon
    이민구

    자답이네요
    이유는 커니님이 말씀하신거처럼 문제가 맞는거 같았고요
    저는 onDestroyView에서 커니님이 말씀하신 구문대신
    Fragment f = (Fragment)getFragmentManager().findFragmentById(R.id.map);
    if (f != null)
    getFragmentManager().beginTransaction().remove(f).commit();
    을 사용해서 프래그 먼트를 지우고
    if (mView != null) {
    ViewGroup parent = (ViewGroup) mView.getParent();
    if (parent != null)
    parent.removeView(mView);
    }
    이 부분을 onCreateView 에 inflater 시키기 전에 넣었더니 정상 작동하네요 ㅎㅎ
    커니님이 많은 도움이 됐습니다 감사합니다.

  6. Blog Icon
    이민구

    이렇게 하니 map Fragment 가 떠잇는 상태에서 뒤로 키로 종료 해버리면 오류가 발생하네요 ㅠㅠㅠ 하아 이런...

  7. 어떤 에러 로그가 나오는지 알 수 있을까요?

  8. Blog Icon
    shepherd

    안녕하세요 전 class 어트리뷰트를 MapFragment를 SupportMapFragment로 바꾸니까 되내요 두개의 차이점좀 알수있을까요?..;

  9. SupportMapFragment는 안드로이드 3.0 이하 단말기에서 사용하기 위한 클래스인데요, 단순히 지원하는 버전의 차이만 다를 뿐 기능상 차이점은 없습니다.

    제가 작업하는 프로젝트에선 SupportMapFragment를 사용하고 있는데도 동일하게 위 문제가 발생합니다. 만약 게속 안 나온다면 다행이지만, 근본적인 문제가 해결되지 않은 것이라면 나중에 동일한 현상이 발생할 가능성이 높습니다. (특히 다른 버전의 단말기에서)

  10. Blog Icon
    choihyenil

    Fragment를 사용하여서 구글 맵을 띄우고 위치정보를 사용하는 어플을 제작중인데 이 어플이 종료되지 않게 하는 방법이 있나요? service를 사용하려니까 entends를 2개해야되서 안되고 방법이 있나요?

  11. 안타깝게도 앱이 종료되지 않도록 하는 확실한 방법은 없습니다.

  12. Blog Icon
    mano

    안드로이드 스튜디오에서 blank Activity with Fragment으로 프래그먼트을 시작할려하는데 자바소스가 2개나오고 메인액티비티 자바소스에는 프라이스홀프래그먼트?그 것도없고 에드랑 콜밋도없는데 무슨 에러인지 고칠방법없나요?

  13. Blog Icon
    어플개발중인사람

    서비스를 목적으로 어플을 하나 개발하고 있던 중에,

    parent view를 remove하라는 에러가 계속 발목을 잡았습니다.

    커니님의 parent view 처리 방법을 통해서 문제를 해결할 수 있었습니다.

    너무 감사합니다.

    로직 전체를 바꿔야하나 고민이 많았는데 덕분에 쉽게 해결했습니다.

    앞으로도 좋은 글 부탁드립니다~!

  14. Blog Icon
    devmin

    정말 이 문제때문에 당황하고 있었는데 해결법공유해주셔서 너무감사합니다~~