Androidアプリ開発 Fragment onAttachメソッドのdeprecated対応

2016年05月04日(編集2016年05月04日)
このエントリーをはてなブックマークに追加

Androidアプリ開発で、UI等に利用するFragmentのonAttachメソッドの仕様が変更されました。この変更により、onAttachメソッドが呼ばれない事象が発生しました。

この記事は、FragmentのonAttachメソッドの仕様と実装方法を記載した記事です。
環境はAndroid 6.0 (API level 23) です。

環境

  • android sdk 23
  • Build Tools, Revision 23.0.3
  • Android Studio 2.1.0

難易度

初心者向け

onAttach

Fragmentで用意されているonAttach(Activity)メソッドは、一度fragmentで呼び出されると、activityと関連付きます。

一般的にAPI 23以前は、以下のように利用していました。

{project_folder}/app/{package}/ui/SampleFragment.java
public class SampleFragment extends Fragment {

    public interface OnListFragmentInteractionListener {
        void onListFragmentInteraction(Main item);
    }

    private OnListFragmentInteractionListener mListener;

    @Override  
    public void onAttach(Activity activity) {  
        super.onAttach(activity);  
  
        if (activity instanceof OnListFragmentInteractionListener) {
            mListener = (OnListFragmentInteractionListener) activity;
        } else {
            throw new RuntimeException(activity.toString()
                    + " must implement OnListFragmentInteractionListener");
        } 
    }
}
        

上記のコードは、FragmentからActivityにコールバックする必要がある場合の処理です。
Fragmentはメモリが不足すると、システムによって破棄され、必要な時に再生成されます。すると、コールバックが受け取れなってしまう場合があります。
この対応として、Activity自体にリスナーを実装します。

{project_folder}/app/{package}/ui/SampleActivity.java
public class SampleActivity extends AppCompatActivity
        implements SampleFragment.OnListFragmentInteractionListener {

    @Override
    public void onListFragmentInteraction(Main item) {
        // something
    }
}
        

API 23の仕様変更

API 23でonAttach(Activity)メソッドは、deprecatedになりました。

android.app/FragmentState
    /**
     * @deprecated Use {@link #onAttach(Context)} instead.
     */
    @Deprecated
    public void onAttach(Activity activity) {
        mCalled = true;
    }
        

代わりに

onAttach(Context)
        

を使います。

修正方法

新たに追加されたonAttach(Context)メソッドは、API 23(Android6.0)からの利用となります。なので、以前のandroidにも対応する場合は、両方のメソッドを呼び出す必要があります。

{project_folder}/app/{package}/ui/SampleFragment.java
public class SampleFragment extends Fragment {

    public interface OnListFragmentInteractionListener {
        void onListFragmentInteraction(Main item);
    }

    private OnListFragmentInteractionListener mListener;

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        +if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) return;
        if (activity instanceof OnListFragmentInteractionListener) {
            mListener = (OnListFragmentInteractionListener) activity;
        } else {
            throw new RuntimeException(activity.toString()
                    + " must implement OnListFragmentInteractionListener");
        }
    }

    +@Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof OnListFragmentInteractionListener) {
            mListener = (OnListFragmentInteractionListener) context;
        } else {
            throw new RuntimeException(context.toString()
                    + " must implement OnListFragmentInteractionListener");
        }
    }
}
        

上記のコードでは、API 23(android6.0)以上の場合、onAttach(Context context)が呼び出され、それ以外はonAttach(Activity activity)が呼びだされます。

さらなる実装のヒント

コールバックのメソッドを呼ぶときは、nullチェックをするべきです。

if (null != mListener) {
    mListener.onListFragmentInteraction(holder.mItem);
}
        

nullチェックをすることで、NullPointerExceptionによるアプリの停止を防ぐことができます。

まとめ

通常のFragmentのonAttachメソッドだけでなく、サポートライブラリのonAttachメソッドも仕様が変更されています。

android6.0未満の端末の対応も必要な場合は、実装方法に注意しましょう。

関連記事

タグ検索で調べてみよう

Android6.0 バグ修正