web-dev-qa-db-ja.com

プログラムで作成したコンテンツビューでアクティビティにフラグメントを追加する方法

プログラムでレイアウトを実装するActivityにFragmentを追加したいです。 Fragmentのドキュメントを見ましたが、必要なものを説明している例はあまりありません。これは私が書き込もうとしたコードの種類です。

public class DebugExampleTwo extends Activity {

    private ExampleTwoFragment mFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        FrameLayout frame = new FrameLayout(this);
        if (savedInstanceState == null) {
            mFragment = new ExampleTwoFragment();
            FragmentTransaction ft = getFragmentManager().beginTransaction();
            ft.add(frame.getId(), mFragment).commit();
        }

        setContentView(frame);
    }
}

...

public class ExampleTwoFragment extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, 
                             ViewGroup container, 
                             Bundle savedInstanceState) {
        Button button = new Button(getActivity());
        button.setText("Hello There");
        return button;
    }
}

このコードはコンパイルされますが、起動時にクラッシュします。おそらく、私のFragmentTransaction.add()が正しくないためです。これを行う正しい方法は何ですか?

217
Tony Wong

そのコードには複数の問題があることがわかりました。フラグメントをそのように宣言することはできません。アクティビティと同じJavaファイルの内部では宣言できませんが、パブリック内部クラスとしては宣言できません。フレームワークは、フラグメントのコンストラクタ(パラメータなし)がパブリックで可視であることを期待しています。フラグメントを内部クラスとしてActivityに移動するか、フラグメント用の新しいJavaファイルを作成することで問題を解決できます。

2つ目の問題は、この方法でフラグメントを追加するときは、フラグメントを含むビューへの参照を渡す必要があり、そのビューにはカスタムIDが必要であるということです。デフォルトのIDを使用するとアプリがクラッシュします。これが更新されたコードです。

public class DebugExampleTwo extends Activity {

    private static final int CONTENT_VIEW_ID = 10101010;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        FrameLayout frame = new FrameLayout(this);
        frame.setId(CONTENT_VIEW_ID);
        setContentView(frame, new LayoutParams(
            LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));

        if (savedInstanceState == null) {
            Fragment newFragment = new DebugExampleTwoFragment();
            FragmentTransaction ft = getFragmentManager().beginTransaction();
            ft.add(CONTENT_VIEW_ID, newFragment).commit();
        }
    }

    public static class DebugExampleTwoFragment extends Fragment {
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            EditText v = new EditText(getActivity());
            v.setText("Hello Fragment!");
            return v;
        }
    }
}
184
Tony Wong

これが私が読んだ後に思いついたものです Tony Wongのコメント

public class DebugExampleTwo extends BaseActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addFragment(Android.R.id.content,
                    new DebugExampleTwoFragment(),
                    DebugExampleTwoFragment.FRAGMENT_TAG);
    }

}

...

public abstract class BaseActivity extends Activity {

    protected void addFragment(@IdRes int containerViewId,
                               @NonNull Fragment fragment,
                               @NonNull String fragmentTag) {
        getSupportFragmentManager()
                .beginTransaction()
                .add(containerViewId, fragment, fragmentTag)
                .disallowAddToBackStack()
                .commit();
    }

    protected void replaceFragment(@IdRes int containerViewId,
                                   @NonNull Fragment fragment,
                                   @NonNull String fragmentTag,
                                   @Nullable String backStackStateName) {
        getSupportFragmentManager()
                .beginTransaction()
                .replace(containerViewId, fragment, fragmentTag)
                .addToBackStack(backStackStateName)
                .commit();
    }

}

...

public class DebugExampleTwoFragment extends Fragment {

    public static final String FRAGMENT_TAG = 
        BuildConfig.APPLICATION_ID + ".DEBUG_EXAMPLE_TWO_FRAGMENT_TAG";

    // ...

}

コトリン

Kotlinを使っているのなら、Googleによる Kotlin拡張 が何を提供しているのか、あるいは自分で書いたものを必ず見てください。

59
JJD
    public class Example1 extends FragmentActivity {

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
          DemoFragment fragmentDemo = (DemoFragment) 
          getSupportFragmentManager().findFragmentById(R.id.frame_container);
          //above part is to determine which fragment is in your frame_container
          setFragment(fragmentDemo);
                       (OR)
          setFragment(new TestFragment1());
        }

        // This could be moved into an abstract BaseActivity 
        // class for being re-used by several instances
        protected void setFragment(Fragment fragment) {
            FragmentManager fragmentManager = getSupportFragmentManager();
            FragmentTransaction fragmentTransaction = 
                fragmentManager.beginTransaction();
            fragmentTransaction.replace(Android.R.id.content, fragment);
            fragmentTransaction.commit();
        }
    }

フラグメントをActivityまたはFramentActivityに追加するにはContainerが必要です。そのコンテナはxmlに含めることができる "Framelayout"であるべきです。そうでなければ "Android.R.id.content"のようなデフォルトのコンテナを使ってActivity内のフラグメントを削除するか置き換えることができます。

main.xml

<RelativeLayout
    Android:layout_width="match_parent"
    Android:layout_height="match_parent" >
 <!-- Framelayout to display Fragments -->
   <FrameLayout
        Android:id="@+id/frame_container"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent" />

    <ImageView
        Android:id="@+id/imagenext"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:layout_alignParentBottom="true"
        Android:layout_alignParentRight="true"
        Android:layout_margin="16dp"
        Android:src="@drawable/next" />
</RelativeLayout>
30
anand krish

すべての回答を読んだ後、私はエレガントな方法を思い付きました:

public class MyActivity extends ActionBarActivity {

 Fragment fragment ;

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

    FragmentManager fm = getSupportFragmentManager();
    fragment = fm.findFragmentByTag("myFragmentTag");
    if (fragment == null) {
        FragmentTransaction ft = fm.beginTransaction();
        fragment =new MyFragment();
        ft.add(Android.R.id.content,fragment,"myFragmentTag");
        ft.commit();
    }

}

基本的にあなたはあなたのフラグメントのコンテナとしてframeLayoutを追加する必要はありません代わりにあなたはAndroidルートViewコンテナに直接フラグメントを追加することができます

重要:onrereationの間にフラグメント変数インスタンスの状態を失うことを気にしないのでない限り、ここに示されているアプローチのほとんどとしてreplace fragmentを使用しないでください。プロセス。

26
Xenione
public abstract class SingleFragmentActivity extends Activity {

    public static final String FRAGMENT_TAG = "single";
    private Fragment fragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
        if (savedInstanceState == null) {
            fragment = onCreateFragment();
           getFragmentManager().beginTransaction()
                   .add(Android.R.id.content, fragment, FRAGMENT_TAG)
                   .commit();
       } else {
           fragment = getFragmentManager().findFragmentByTag(FRAGMENT_TAG);
       }
   }

   public abstract Fragment onCreateFragment();

   public Fragment getFragment() {
       return fragment;
   }

}

つかいます

public class ViewCatalogItemActivity extends SingleFragmentActivity {
    @Override
    public Fragment onCreateFragment() {
        return new FragmentWorkShops();
    }

}
5
user2212515

APIレベル17以上の場合、 View.generateViewId() がこの問題を解決します。ユーティリティメソッドは、ビルド時には使用されない一意のIDを提供します。

4
Sfseyhan