티스토리 뷰

반응형

Stack Overflow에 자주 검색, 등록되는 문제들과 제가 개발 중 찾아 본 문제들 중에서 나중에도 찾아 볼 것 같은 문제들을 정리하고 있습니다.

Stack Overflow에서 가장 먼저 확인하게 되는 가장 높은 점수를 받은 Solution과 현 시점에 도움이 될 수 있는 가장 최근에 업데이트(최소 점수 확보)된 Solution을 각각 정리하였습니다.

 

아래 word cloud를 통해 이번 포스팅의 주요 키워드를 미리 확인하세요.

Duplicate ID, tag null, or parent id with another fragment for com.google.android.gms.maps.MapFragment

com.google.android.gms.maps.MapFragment에 대해 중복된 ID, null 태그 또는 다른 프래그먼트와의 부모 ID가 있습니다.

 문제 내용 

I have an application with three tabs.

저는 세 개의 탭을 가진 애플리케이션이 있습니다.

 

Each tab has its own layout .xml file. The main.xml has its own map fragment. It's the one that shows up when the application first launches.

각각의 탭에는 자신만의 레이아웃 .xml 파일이 있습니다. main.xml에는 자체적인 맵 프래그먼트가 있습니다. 이것은 애플리케이션이 처음 실행될 때 나타납니다.

 

Everything works fine except for when I change between tabs. If I try to switch back to the map fragment tab, I get this error. Switching to and between other tabs works just fine.

이것은 애플리케이션이 처음 시작될 때 나타납니다. 다른 탭으로 전환하는 것은 문제가 없지만, 맵 프래그먼트 탭으로 다시 전환하려고하면이 오류가 발생합니다.

 

What could be wrong here?

여기서 무엇이 잘못될 수 있을까요?

 

This is my main class and my main.xml, as well as a relevant class that I use ( you will also find the error log at the bottom )

이것은 내 Main 클래스와 main.xml, 그리고 내가 사용하는 관련 클래스 (아래에서 오류 로그를 찾을 수 있습니다)입니다.

 

main class

package com.nfc.demo;

import android.app.ActionBar;
import android.app.ActionBar.Tab;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.widget.Toast;

public class NFCDemoActivity extends Activity {

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ActionBar bar = getActionBar();
        bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
        bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);

        bar.addTab(bar
                .newTab()
                .setText("Map")
                .setTabListener(
                        new TabListener<MapFragment>(this, "map",
                                MapFragment.class)));
        bar.addTab(bar
                .newTab()
                .setText("Settings")
                .setTabListener(
                        new TabListener<SettingsFragment>(this, "settings",
                                SettingsFragment.class)));
        bar.addTab(bar
                .newTab()
                .setText("About")
                .setTabListener(
                        new TabListener<AboutFragment>(this, "about",
                                AboutFragment.class)));

        if (savedInstanceState != null) {
            bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
        }
        // setContentView(R.layout.main);

    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("tab", getActionBar().getSelectedNavigationIndex());
    }

    public static class TabListener<T extends Fragment> implements
            ActionBar.TabListener {
        private final Activity mActivity;
        private final String mTag;
        private final Class<T> mClass;
        private final Bundle mArgs;
        private Fragment mFragment;

        public TabListener(Activity activity, String tag, Class<T> clz) {
            this(activity, tag, clz, null);
        }

        public TabListener(Activity activity, String tag, Class<T> clz,
                Bundle args) {
            mActivity = activity;
            mTag = tag;
            mClass = clz;
            mArgs = args;

            // Check to see if we already have a fragment for this tab,
            // probably from a previously saved state. If so, deactivate
            // it, because our initial state is that a tab isn't shown.
            mFragment = mActivity.getFragmentManager().findFragmentByTag(mTag);
            if (mFragment != null && !mFragment.isDetached()) {
                FragmentTransaction ft = mActivity.getFragmentManager()
                        .beginTransaction();
                ft.detach(mFragment);
                ft.commit();
            }
        }

        public void onTabSelected(Tab tab, FragmentTransaction ft) {
            if (mFragment == null) {
                mFragment = Fragment.instantiate(mActivity, mClass.getName(),
                        mArgs);
                ft.add(android.R.id.content, mFragment, mTag);
            } else {
                ft.attach(mFragment);
            }
        }

        public void onTabUnselected(Tab tab, FragmentTransaction ft) {
            if (mFragment != null) {
                ft.detach(mFragment);
            }
        }

        public void onTabReselected(Tab tab, FragmentTransaction ft) {
            Toast.makeText(mActivity, "Reselected!", Toast.LENGTH_SHORT)
                         .show();
        }
    }

}

 

main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <fragment
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/mapFragment"
        android:name="com.google.android.gms.maps.MapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

 

relevant class ( MapFragment.java )

적절한 클래스(MapFragment.java)
package com.nfc.demo;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class MapFragment extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);
        return inflater.inflate(R.layout.main, container, false);
    }

    public void onDestroy() {
        super.onDestroy();
    }
}

 

error

오류
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

 

 

 높은 점수를 받은 Solution 

The answer Matt suggests works, but it causes the map to be recreated and redrawn, which isn't always desirable. After lots of trial and error, I found a solution that works for me:

Matt가 제안한 답변은 작동하지만, 지도가 재생성되고 다시 그려지기 때문에 항상 바람직하지는 않습니다. 많은 시행 착오 끝에, 나에게 작동하는 해결책을 찾았습니다.
private static View view;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    if (view != null) {
        ViewGroup parent = (ViewGroup) view.getParent();
        if (parent != null)
            parent.removeView(view);
    }
    try {
        view = inflater.inflate(R.layout.map, container, false);
    } catch (InflateException e) {
        /* map is already there, just return view as it is */
    }
    return view;
}

 

For good measure, here's "map.xml" (R.layout.map) with R.id.mapFragment (android:id="@+id/mapFragment"):

참고로, "map.xml"이라는 레이아웃 파일에는 "R.id.mapFragment"이라는 아이디가 있습니다 (android:id="@+id/mapFragment").
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/mapLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <fragment xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/mapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        class="com.google.android.gms.maps.SupportMapFragment" />
</LinearLayout>

 

I hope this helps, but I can't guarantee that it doesn't have any adverse effects.

이것이 도움이 되기를 바라며, 이것이 부작용이 없는지 보장할 수는 없습니다.

 

Edit: There were some adverse effects, such as when exiting the application and starting it again. Since the application isn't necessarily completely shut down (but just put to sleep in the background), the previous code i submitted would fail upon restarting the application. I've updated the code to something that works for me, both going in & out of the map and exiting and restarting the application, I'm not too happy with the try-catch bit, but it seem to work well enough. When looking at the stack trace it occurred to me that I could just check if the map fragment is in the FragmentManager, no need for the try-catch block, code updated.

수정: 일부 부작용이 있었는데, 예를 들어 애플리케이션을 종료하고 다시 시작할 때입니다. 애플리케이션이 완전히 종료되지는 않고 (배경에서 대기 중), 이전에 제출한 코드는 애플리케이션을 다시 시작할 때 실패할 것입니다. 나는 내가 잘 작동하는 코드로 업데이트했는데, try-catch 부분은 그다지 좋아하지 않지만, 충분히 잘 작동하는 것 같다. 스택 추적을 보면 MapFragment가 FragmentManager에 있는지만 확인하면 try-catch 블록이 필요하지 않다는 것이 떠올랐다. 코드가 업데이트되었다.

 

More edits: It turns out that you need that try-catch after all. Just checking for the map fragment turned out not to work so well after all. Blergh.

추가 수정사항: 결국 try-catch가 필요하다는 것을 알게 되었습니다. 맵 프래그먼트를 확인하는 것만으로는 잘 작동하지 않았습니다. 아쉽습니다.

 

 

 

 가장 최근 달린 Solution 

You are returning or inflating layout twice, just check to see if you only inflate once.

레이아웃을 두 번 반환하거나 인플레이트하고 있습니다. 인플레이트는 한 번만 하는지 확인하세요.

 

 

 

출처 : https://stackoverflow.com/questions/14083950/duplicate-id-tag-null-or-parent-id-with-another-fragment-for-com-google-androi

반응형
댓글
공지사항
최근에 올라온 글