web-dev-qa-db-ja.com

Android:フラグメントの重複の問題

私はタブを切り替えてフラグメントをタブビューに添付するとフラグメントが重複するという問題に直面しています私のコードは助けてください

public class FragmentManage extends Fragment implements ActionBar.TabListener {

    private Fragment mFragment;

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

        View v = inflater.inflate(R.layout.fragment_manage, container, false);

        OnClickListener clickListener = new OnClickListener() { 
            public void onClick(View v) {
                FragmentTransaction ft = getFragmentManager().beginTransaction();
                switch(v.getId()) {
                    case R.id.imageBtnCategory:
                        if (mFragment == null){
                            mFragment = new FragmentCategory();
                        }
                        ft.replace(Android.R.id.content, mFragment);
                        break;
                    case R.id.imageBtnManageKey:
                        if (mFragment == null){
                            mFragment = new FragmentKeys();
                        }
                        ft.replace(Android.R.id.content, mFragment);
                        break;
                    case R.id.imageBtnChangePswd:
                        if (mFragment == null){
                            mFragment = new FragmentChangePwd();
                        }
                        ft.replace(Android.R.id.content, mFragment);
                        break;
                }
                ft.commit();
             }
        };

        ImageButton imageBtnCategory = (ImageButton) v.findViewById(R.id.imageBtnCategory);
        ImageButton imageBtnManageKey = (ImageButton) v.findViewById(R.id.imageBtnManageKey);
        ImageButton imageBtnChangePswd = (ImageButton) v.findViewById(R.id.imageBtnChangePswd);

        imageBtnCategory.setOnClickListener(clickListener);
        imageBtnManageKey.setOnClickListener(clickListener);
        imageBtnChangePswd.setOnClickListener(clickListener);

        return v;
    }

    public void onTabSelected(Tab tab, FragmentTransaction ft) {
        mFragment = new FragmentManage();
        ft.add(Android.R.id.content, mFragment);
        ft.attach(mFragment);
    }

    public void onTabUnselected(Tab tab, FragmentTransaction ft) {
        ft.remove(mFragment);
    }

    public void onTabReselected(Tab tab, FragmentTransaction ft) {

    }
}
32
girishawate

XMLファイルで<fragment />に背景色を設定するだけです。

問題を解決します。

84
kvh

私はこの質問に答えるのが非常に遅いかもしれません。

注:

この答えは上記の質問とは関係ないかもしれませんが、それが一部の人に役立つことを願っています。

時々、異なるタイプのフラグメントを使用しようとすると、フラグメントのオーバーラップ問題が発生します(つまり、いくつかのフラグメントでサポートフラグメントを使用し、他のフラグメントで通常のフラグメントを使用する)

最近、ナビゲーションドロワーで同じ問題に直面しました。誤って、1つのフラグメントで「import Android.support.v4.app.Fragment;」を使用し、他のいくつかの「import Android.app.Fragment;」を使用しました断片。

これが誰かに役立つことを願っています。

15
Roshan

フラグメントはまだメモリを消費する可能性があるアクティビティスタック内にあるため、フラグメントの背景色を適切に設定することは解決策ではありません。

解決策は、新しいフラグメントを追加する前に、フレームレイアウトからすべてのビューを削除することです。

private void changeFragment(Fragment fr){
    FrameLayout fl = (FrameLayout) findViewById(R.id.mainframe);
    fl.removeAllViews();
    FragmentTransaction transaction1 = getSupportFragmentManager().beginTransaction();
    transaction1.add(R.id.mainframe, fr);
    transaction1.commit();
}
10
Sufiyan Ansari

フラグメントマネージャーは、置き換えられる前のすべてのフラグメントのスタックを維持します

  fragmentManager.popBackStack(); 

動作します。これをループで実行して、スタック内のすべてのフラグメントをポップすることができます。ハッピーコーディング:)

10
Syed Raza Mehdi

別の問題は、Android.R.id.contentコンテナとして。 FrameLayoutを作成し、そこからidを使用しました。

4
irudyak

これは私がそれを修正した方法です..

背景を設定すると、レイアウトが画面いっぱいに一致する場合にのみ、画面から重複する効果が削除されます

ボタンのクリックで置き換えられた新しいフラグメントは、tab_selectedまたはtab changeアクションで置き換えられませんでした

次のコードは私のためにそれを修正しました

    public void onTabUnselected(Tab tab, FragmentTransaction ft) {
    // This is required since button click replaces fragment whose link is lost hence overlapping isuee was occuring
    ft.replace(Android.R.id.content, mFragment); 
    // On Tab Change remove old fragment views
    ft.remove(mFragment);
}
4
girishawate

また、フラグメントオーバーラップの問題に直面しました。これをどのように解決しましたか-

1)addToBackStackで最初のフラグメントを追加して、スタックに保持する必要があります-

FirstFragment firstFragment = new FirstFragment();
getFragmentManager().beginTransaction().add(R.id.fragment_container, firstFragment).addToBackStack("first frag").commit();

2)2番目のフラグメントを追加するときに、最初のフラグメントを追加するのではなく置き換えます。最初のフラグメントは既にスタックに追加されているため、2番目のフラグメントから押し戻すと存在します。

SecondFragment secondFragment= new SecondFragment();
getFragmentManager().beginTransaction().replace(R.id.fragment_container, secondFragment).addToBackStack("second frag").commit();

3)バックプレスの処理方法を次に示します。親アクティビティに以下のコードが存在する必要があります-

 public void onBackPressed(){
    if(getFragmentManager().getBackStackEntryCount() <= 1){
       super.onBackPressed();
    } else {
       getFragmentManager().popBackStack();
    }
 }
3
Sunita

XMLをチェックして、メインレイアウトがフレームレイアウトであるかどうかを確認しましたか?そうでない場合は、代わりにフレームレイアウトを使用します。これにより、重複する問題が解決されます。それが修正する唯一の方法です。この問題の解決策を探しているときに「受け入れられた」答えを試しましたが、うまくいきませんでした。

2
David Dimalanta
private void changeFragment(Fragment fr){
FrameLayout fl = (FrameLayout) findViewById(R.id.mainframe);
fl.removeAllViews();
FragmentTransaction transaction1 =getSupportFragmentManager().beginTransaction();
transaction1.add(R.id.mainframe, fr);
transaction1.commit();}
1
Mohit Taparia

私は時々同じ問題を抱えていますが、私の問題は異なるフラグメントマネージャー(getSupportFragmentManager()getFragmentManager())とは関係ありません。さらに別の問題があると思います。私の場合、ナビゲーションドロワーを開くと、すべてのメニューオプションで古いフラグメントが常に削除されます。たとえば、

Fragment calendarFragment = context.getSupportFragmentManager().findFragmentByTag(FragmentTag.CALENDAR.name());
if (calendarFragment != null)
{
    context.getSupportFragmentManager().beginTransaction().remove(calendarFragment).commit();
}

ナビゲーションドロワーなしでサブメニューに入ることはできないため、基本的には常にフラグメントが削除されます。場合によっては、アクティビティ内でフラグメントを削除して再度追加した後、別の(前の)フラグメントと突然重複しますか?!しかし、フラグメントマネージャが突然以前のフラグメントを見つけるのはなぜですか?これは、フラグメントマネージャにバグがあり、古いフラグメントが削除されないか、他の何かが壊れていることを意味します。
私の考えは、Android Studioまたはそれに使用される他のadb開発ツールのせいだと思います。なぜだと思うのは、Android Studioは、実行中のアプリのインスタンスを失うことがあります。おそらく、この問題は同じ問題に何らかの関係があると思われます: Android Studioがアプリに変更を展開していない 。私が知っているのは、Android Studioでアプリを再起動した後は再現できないため、プログラミングの問題にはなり得ないことです。アクティビティ、フラグメント、フラグメントマネージャーなどの複数のインスタンスが発生します。さらに、これはこのバグだけではありません。 IDEによる)。

0
Bevor

重複フラグメントがある場合、フラグメントの背景が透明である可能性があるため、フラグメントプロパティ内にAndroid:background = "@ color/white" 'を配置する必要があります。

<FrameLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:tools="http://schemas.Android.com/tools"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:background="@color/white"

残りのフォルダーのcolors.xml #FFFFFF内に配置する必要がある白。

便利かもしれませんが、白い背景を実装することは安全な解決策ではないと思います。基本的に、フラグメントマネージャーがどのフラグメントをポップするかについて混乱しているため、問題が発生します。

backstackはこのように見え、frag 4 1-> 2、2-> 3、3-> 4であると考えますが、実際には何らかの理由でfrag 6であるため、popbackstackは行きます

remove(4)add(3)<-これで3(new)と6(left behind)がブレンドされました

ナビゲーションをより適切に制御するために、現在/以前のフラグメントを追跡し、次のように置き換えます。これにより、アプリでフラグメントナビゲーションを制御できます。

if ( !(currentFragment instanceof Settings)) {
        FragmentManager fragmentManager = getFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.replace(R.id.fragment_container, settings);
        fragmentTransaction.addToBackStack(null);
        previousFrag = currentFragment;
        currentFragment = settings;
        fragmentTransaction.commit();
    }

第二に、fragmentmanager.replace()メソッドがより良い代替手段であると信じています。その時点でOPがそれを利用できるかどうかはわかりません。

第三に、Androidのネイティブバックプレスを処理するには、無期限にスクロールバックできる必要があります。多くの人は、この行を使用しないことで、最初のフラグメントをバックスタックに追加しないことを推奨しています。

fragmentTransaction.addToBackStack(null);

ただし、その場合は、アプリが初めて読み込まれたかどうかを確認する必要があります。そうでなく、この行を除外すると、このフラグメントをナビゲートするたびにアプリにこれらの問題が発生します。そのままにしておき、代わりに次の操作を行います。

これが良い解決策であるかどうかはわかりませんが、非常にうまく機能します。

1-バックスタックカウントを取得する2-既存のすべてのフラグメントを削除する3-フラグメントオブジェクトを追跡する4-ユーザーが終了したいスタック内の最後のフラグメントである場合、メインアクティビティをバックスタックに追加したため、ダブルポップする必要がある

@Override
public void onBackPressed() {

int num = getFragmentManager().getBackStackEntryCount();


        fl.removeAllViews();
        super.onBackPressed();

        if  (currentFragment != previousFrag) {
            currentFragment = previousFrag;
        }else{
            currentFragment = null;
        }

        if (num == 1){
           super.onBackPressed();
        }
0
cagney

それはすべてreplaceおよびaddToBackStackメソッドの背後にあるエンジニアリングに関係しています。

Replaceメソッドは実際に2つのことを行います。既存のフラグメントを非表示にし(Aとしましょう)、コンテナに新しいフラグメント(Bとしましょう)を追加します。

そのトランザクションをバックスタックに追加すると、逆のことが行われます。 Bを削除してAを追加します。

だから、あなたの問題の解決策は
1。 addToBackStackメソッドを使用します。
2。フラグメントの逆置換が正しい順序であることを確認してください

2番目の提案は本当に重要です。なぜなら、ある時点で現在のフラグメントが削除されずに別のフラグメントが追加され、2つのフラグメントが同時に表示されることがよくあるためです。

0
ichalos

シンプルでクリーンなソリューションを見つけました。私にとっては、アクティビティのonCreate()の呼び出しごとにフラグメントトランザクションの実行に問題がありました。現在、savedInstanceState == nullの場合にのみトランザクションを実行します

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        if (savedInstanceState == null) {
        // replace fragment 
        }
    }
0
Ivan Syabro

背景色を白にすることも私にとっては解決しました。これはバグまたはAndroidフラグメントマネージャーの実装の問題だと思います。replaceとpopBackStack()を正しく実装していました。

0
daniekpo

このような問題が発生したとき、childFragmentManagerで1つのフラグメントを追加し、親のfragmentManagerで別のフラグメントを追加しているように見えたので、同じタイプのフラグメントマネージャを使用していることを確認してください。

0
Olga Sokol