web-dev-qa-db-ja.com

リスナーをカスタムフラグメントにAndroid=

アプリでビューページャーを作成し、その上でFragmentを拡張するクラスを使用しています。インスタンスを作成するとき、すべての要素(画像、テキストなど)を渡して、それをBundleに格納し、onCreateで使用できます。しかし、フラグメントのボタンのリスナーを格納できません。これが私のクラスです:

public class RegWizardFragmentInfo extends Fragment {

private static final String IMAGE = "image";
private static final String TEXT = "text";
private static final String BUTTON = "buttonText";
private View.OnClickListener buttonCallBack;

private Button button;
private int image;
private int text;
private int buttonText;


public RegWizardFragmentInfo newInstance(int image, int text, int buttonText, View.OnClickListener callback) {

    RegWizardFragmentInfo fragment = new RegWizardFragmentInfo();
    Bundle bundle = new Bundle();
    bundle.putInt(IMAGE, image);
    bundle.putInt(BUTTON, buttonText);
    bundle.putInt(TEXT, text);
    fragment.setArguments(bundle);
    fragment.setRetainInstance(true);
    return fragment;

}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    super.onActivityCreated(savedInstanceState);
    this.image = getArguments().getInt(IMAGE);
    this.text = (getArguments() != null) ? getArguments().getInt(TEXT)
            : -1;
    this.buttonText = (getArguments() != null) ? getArguments().getInt(BUTTON)
            : -1;
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    ViewGroup rootView = (ViewGroup) inflater.inflate(
            R.layout.fragment, container, false);
    //Extract all the views and add the image and texts

    return rootView;

}

では、取得したリスナーをnewInstanceに保存して、onCreateViewメソッドのボタンに追加するにはどうすればよいでしょうか。

助けてくれてありがとう。

Fragmentでコールバックを使用できます:

public class RegWizardFragmentInfo extends Fragment {

    private Button button;

    private OnClickCallback callback;

    public interface OnClickCallback {
        void onClick();
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        callback = (OnClickCallback) context;
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        return super.onCreateView(inflater, container, savedInstanceState);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                callback.onClick();
            }
        });
    }
}

この新しいインターフェイスを親に実装しますActivity

他の答えは、リスナーをonAttachに割り当てます。これは機能しますが、呼び出し側のActivity(匿名クラスなどではなく)がインターフェースを実装する必要があります。さらに、Contextで指定されたonAttachをインターフェイスのインスタンスにキャストする必要があります。これは、クラッシュを引き起こす可能性があり、一般に不正な形式と見なされます。代わりに、Fragment内にリスナーを設定するメソッドを作成できます。

public class RegWizardFragmentInfo extends Fragment {

    private OnClickListener mListener;

    public interface OnClickListener {
        void onClick();
    }

    /**
     * Call at any time after this fragment has been constructed.
     */
    public void setListener(OnClickListener listener) {
        mListener = listener;
    }

    /* ...other stuff... */
}

このアプローチには3つの欠点があると思います。

  1. Fragmentをインスタンス化するたびに、追加のメソッドを呼び出す必要があります。
  2. mListenerがいつでも設定されることを保証することはできません。 Fragmentコードにnullチェックを付ける必要がある場合があります。
  3. 画面の回転などのライフサイクルイベント後もリスナーが設定されたままになるように注意する必要があります。
4
Jack Meister

さまざまな異なるリスナーでFragmentを再利用したいと思います。したがって、Bundleを使用できないため、アプローチは理想的ではありません。より良いアプローチは、コールバック設計パターンを使用することです。

_public class RegWizardFragmentInfo extends Fragment {

    public interface RegWizardCallback {
        void onClick();
    }
}
_

あなたのActivityはそのインターフェースを実装します。 Fragmentはアクティビティ内にのみ存在するため、ライフサイクルメソッドonAttach()を使用して、アクティビティからコールバックインスタンスを取得できます。このようになります

_public class RegWizardFragmentInfo extends Fragment {
    private RegWizardCallback callback;

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            callback = (RegWizardCallback) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement RegWizardCallback ");
        }
    }

    public interface RegWizardCallback {
        void onClick();
    }
}
_

これで、Buttonのリスナー内で_callback.onClick_を呼び出すだけです。

2
Murat Karagöz