AndroidのFragmentのバグ解決

5602 ワード

最近、2回目のインタフェースに入ると、次の詳細なlog情報のような奇妙なバグが発生します.
10-01 13:36:23.549: E/AndroidRuntime(14188): Process: com.android.settings, PID: 14188
10-01 13:36:23.549: E/AndroidRuntime(14188): android.view.InflateException: Binary XML file line #43: Error inflating class fragment
10-01 13:36:23.549: E/AndroidRuntime(14188): 	at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:713)
10-01 13:36:23.549: E/AndroidRuntime(14188): 	at android.view.LayoutInflater.rInflate(LayoutInflater.java:755)
10-01 13:36:23.549: E/AndroidRuntime(14188): 	at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
10-01 13:36:23.549: E/AndroidRuntime(14188): 	at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
10-01 13:36:23.549: E/AndroidRuntime(14188): 	at com.android.settings.accessibility.ToggleCaptioningPreferenceFragment.onCreateView(ToggleCaptioningPreferenceFragment.java:69)
10-01 13:36:23.549: E/AndroidRuntime(14188): 	at android.app.Fragment.performCreateView(Fragment.java:1700)
10-01 13:36:23.549: E/AndroidRuntime(14188): 	at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:890)
10-01 13:36:23.549: E/AndroidRuntime(14188): 	at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1062)
10-01 13:36:23.549: E/AndroidRuntime(14188): 	at android.app.BackStackRecord.run(BackStackRecord.java:698)
10-01 13:36:23.549: E/AndroidRuntime(14188): 	at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1447)
10-01 13:36:23.549: E/AndroidRuntime(14188): 	at android.app.FragmentManagerImpl$1.run(FragmentManager.java:443)
10-01 13:36:23.549: E/AndroidRuntime(14188): 	at android.os.Handler.handleCallback(Handler.java:808)
10-01 13:36:23.549: E/AndroidRuntime(14188): 	at android.os.Handler.dispatchMessage(Handler.java:103)
10-01 13:36:23.549: E/AndroidRuntime(14188): 	at android.os.Looper.loop(Looper.java:193)
10-01 13:36:23.549: E/AndroidRuntime(14188): 	at android.app.ActivityThread.main(ActivityThread.java:5333)
10-01 13:36:23.549: E/AndroidRuntime(14188): 	at java.lang.reflect.Method.invokeNative(Native Method)
10-01 13:36:23.549: E/AndroidRuntime(14188): 	at java.lang.reflect.Method.invoke(Method.java:515)
10-01 13:36:23.549: E/AndroidRuntime(14188): 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:824)
10-01 13:36:23.549: E/AndroidRuntime(14188): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:640)
10-01 13:36:23.549: E/AndroidRuntime(14188): 	at dalvik.system.NativeStart.main(Native Method)
10-01 13:36:23.549: E/AndroidRuntime(14188): Caused by: java.lang.IllegalArgumentException: Binary XML file line #43: Duplicate id 0x7f0b0034, tag null, or parent id 0xffffffff with another fragment for com.android.settings.accessibility.CaptionPropertiesFragment
10-01 13:36:23.549: E/AndroidRuntime(14188): 	at android.app.Activity.onCreateView(Activity.java:4912)
10-01 13:36:23.549: E/AndroidRuntime(14188): 	at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:689)
上記のlog情報から分かるように、Duplicate(Duplicate)重複するFragment(CaptionPropertiesFragment)がロードされている.問題はコードに問題はないはずです!具体的には、私のコードを見てください.
public class ToggleCaptioningPreferenceFragment extends Fragment {
    private static final float DEFAULT_FONT_SIZE = 48f;

    private CaptionPropertiesFragment mPropsFragment;
    private SubtitleView mPreviewText;
    private CaptioningManager mCaptioningManager;


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

        mCaptioningManager = (CaptioningManager) getActivity()
                .getSystemService(Context.CAPTIONING_SERVICE);
    }

    @Override
    public View onCreateView(
            LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
	

        final View rootView = inflater.inflate(R.layout.captioning_preview, container, false);

        // We have to do this now because PreferenceFrameLayout looks at it
        // only when the view is added.
        if (container instanceof PreferenceFrameLayout) {
            ((PreferenceFrameLayout.LayoutParams) rootView.getLayoutParams()).removeBorders = true;
        }


        return rootView;
    }

エラーメッセージからエラーコードがわかります:final View rootView=inflater.inflate(R.layout.captioning_preview, container, false);
では、エラーメッセージは重複するFragment(CaptionPropertiesFragment)がロードされたと言います.実はこの繰り返しのFragmentはこのlayoutファイルの中でレイアウトされています:R.layout.captioning_preview.
明らかに、初めてこのインタフェースに入って、また退出する時、この使ったFragment(CaptionPropertiesFragment)はremoveが落ちていません!2つの問題が発生しました.
(1)なぜこのFragment(CaptionPropertiesFragment)にremoveがないのか、
(2)この問題をどう解決するか!
Activityで異なるframent間のアイテムを置き換える場合、FragmentManagerはremoveとaddというframentしかできませんが、これらのframentの中に自分でロードしたframent(ここでは私たちのCaptionPropertiesFragment)はremoveされていません.明らかにこれは欠陥です!後のframent(C a p t ionPropertiesFragment)は明らかに彼の父framentに依存しているので、同時に再帰すべきremove.
では、この問題をどう解決すればいいのでしょうか.このframent(T o g g g g l e C a p t ioningPreferenceFragment)を使わないうちに彼の中にロードされたframentをremoveに落とすのは明らかだ.この操作はToggle CaptioningPreferenceFragmentのonDestroyView()で問題を解決できます!次のコードがあります.
	@Override
	public void onDestroyView() {
		super.onDestroyView();

	 	if(mPropsFragment != null){
			FragmentManager f = getFragmentManager();
			if(f != null && !f.isDestroyed()){
				final FragmentTransaction ft = f.beginTransaction();
				if(ft != null){
					ft.remove(mPropsFragment).commit();
				}
			}
	 	}
	}
ここではf.isDestroyed()に注意して、このFragmentManagerがDestroyedにあるかどうかを判断します.
注意:この問題に対して、ネット上にはいろいろな無効な解決方法があります.