Fragmentのいくつかの穴

6117 ワード

インスタンスの作成


一般的にFragmentを作成するには、次のような方法があります.
OneFragment fragment = new OneFragment();

作成時にパラメータを渡す必要がある場合は
OneFragment fragment = new OneFragment(xxx);

これなら普通は大丈夫ですが、特殊な場合には問題が発生します.例えば の場合、Activityは Activity、Activityに依存するFragmentもついてくる 、Fragmentはデフォルトの を呼び出すので、実行できなくなる 初期化作業を行います.
解決策:newInstanceの方法でFragmentインスタンスを作成し、作成時に Bundleの中に入れ、setArguments()を入れてonCreate()の中から取り出す.このように上記のような特殊な場合であっても、onCreate()メソッドで を取り出して初期化作業を行うことができる.
public static OneFragment newInstance(int args){
     OneFragment oneFragment = new OneFragment();

    Bundle bundle = new Bundle();
    bundle.putInt("someArgs", args);

    oneFragment.setArguments(bundle);
    return oneFragment;
}

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

    Bundle bundle = getArguments();
    int args = bundle.getInt("someArgs");
}

つうしんモード


通常、3つの通信シーンがあります.
  • Activity操作内蔵Fragment
  • Fragment操作宿主Activity
  • Fragment操作同級のFragment
  • 一般的な場合:
  • 私たちがActivityで作成したFragmentなので、自然に持っているFragment 、あるいはfindFragmentById()findFragmentByTag()のいずれの方法でも入手できるFragment なので、Fragmentまで操作できる.
  • FragmentはgetActivity()方法で入手可能 Activity 、さらに可能 宿主Activity.
  • getActivity()方法でActivityが得られる以上、自然にできる その他Fragment
  • 問題:上記の方法で全ての通信問題を解決できるが、 の場合、 ・のプログラミング思想に合致しない.Fragmentは自分のことをよくすればいい.Fragment間の制御表示などの操作は、Activityが統一的に管理しなければならない.
    解決方法:外部にインタフェースの形式を開放することによって、FragmentのActivityに対するいくつかの操作をActivityによって管理する.Fragment操作Activityに相当しますが、Fragmentは1つのインタフェースしか提供しておらず、ActivityがFragmentの操作が必要な方法を自覚的に入れるようにしています.
    実装方法は次のとおりです.
    public class OneFragment extends Fragment implements View.OnClickListener{
    
        public interface IOneFragmentClickListener{
            void onOneFragmentClick();
        }
    
        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            View contentView = inflater.inflate(R.layout.fragment_one, null);
            contentView.findViewById(R.id.edt_one).setOnClickListener(this);
            return contentView;
        }
    
        @Override
        public void onClick(View v) {
            if (getActivity() instanceof IOneFragmentClickListener){
                 ((IOneFragmentClickListener) getActivity()).onOneFragmentClick();
            }
        }
    
    }
    

    Fragmentが定義した対外インタフェースIOneFragmentClickListenerをホストActivityで実現すれば、FragmentがActivityを呼び出す機能を実現できる.
    次のようにすることもできます.
    public class OneFragment extends Fragment implements View.OnClickListener{
        
        private IOneFragmentClickListener clickListener;
    
        public interface IOneFragmentClickListener{
            void onOneFragmentClick();
        }
    
        public void setClickListener(IOneFragmentClickListener clickListener) {
            this.clickListener = clickListener;
        }
    
        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            View contentView = inflater.inflate(R.layout.fragment_one, null);
            contentView.findViewById(R.id.edt_one).setOnClickListener(this);
            return contentView;
        }
    
        @Override
        public void onClick(View v) {
            clickListener.onOneFragmentClick();
        }
    
    }
    

    原理は同じですが、最初の方法と比較して、ホストActivityにリスニング設定を追加する必要があります.
    oneFragment.setClickListener(this);
    

    Fragment重複問題


    理由:
  • ケース1:重複作成例による重複一般的な場合はActivityonCreate()またはFragmentonCreateView()にFragmentをロードし、もし の場合(例えば画面の回転、メモリの回収、フォントの交換などの場合に強殺されて再起動)に遭遇した場合は、システムの により自動的に手伝ってくれる Fragment 、その後再起動してくれる 、しかし、私たちのonCreate()またはonCreateView()メソッド内でまた addになったので .
  • ケース2:mHidden状態が保存されていないためオーバーラップするmHiddenパラメータは保存に使用するFragment(mHidden=tureは非表示、mHidden=falseは表示)例えば2つのFragmentがあり、1つがture状態、1つがfalse状態である場合、インタフェースが再起動する場合、システムは 手伝ってあげる この場合mHidden状態 FragmentすべてのFragmentデフォルトmHiddenはfalse(すなわち )なので となります.

  • ケース2はv 4-24.00+で始まり、上記mHiddenが保存されていない問題を公式に修復したので、24.00+のv 4パッケージを使用している場合は、ケース2の問題を考慮しないことができます.でも!もしあなたがV 4パックのFragmentではなくandroidを使っていたら.app.FragmentパッケージのFragmentでは、問題は依然として存在します!
    解決策:
  • ケース1:FragmentのonCreate()に直接判断を加える:
  • // , 
    if (savedInstanceState == null){
        // 
    }
    
  • ケース2:変数mSupportHiddenを手動で保守し、各Fragmentの表示状態を保存するため、ケース1、2に係る解決策コード:
  • public class BaseFragment extends Fragment {
        private static final String STATE_SAVE_IS_HIDDEN = "STATE_SAVE_IS_HIDDEN";
    
        @Override
        public void onCreate(@Nullable Bundle savedInstanceState) {
        ...
        if (savedInstanceState != null) {
            boolean isSupportHidden = savedInstanceState.getBoolean(STATE_SAVE_IS_HIDDEN);
    
            FragmentTransaction ft = getFragmentManager().beginTransaction();
            if (isSupportHidden) {
                ft.hide(this);
            } else {
                ft.show(this);
            }
            ft.commit();
        }
    
        @Override
        public void onSaveInstanceState(Bundle outState) {
            ...
            outState.putBoolean(STATE_SAVE_IS_HIDDEN, isHidden());
        }
    }
    

    remove()メソッドはスタックから出られません


    まだピットを踏む必要があります...

    getActivity()空のポインタ


    まだピットを踏む必要があります...

    複数のFragmentが同時にスタックを出る深いピットBUG


    まだピットを踏む必要があります...

    深坑Fragmentターンフィールドアニメーション(v 4パッケージのFragmentのみを解析)


    まだピットを踏む必要があります...
    参考Fragment全解析シリーズ(一):年に踏んだ穴