Bescottee苦しいときは伸びてるとき、楽なときは伸びていないとき

5 Android FragmentからのActivity呼び出し方法


FragmentからActivity呼び出し方法のメイン画像

以前のエントリの「 1apkでAndroidタブレット向けとスマートフォン向けアプリを実現する方法 その3」の「FragmentとActivityの役割分担」でFragmentとActivityの関係について記載し、上の図のように Fragment が導入されたからといっても、Fragment はActivityに依存しないように機能をモジュール化できる機能であり、以下の図のように他のActivityと依存関係を持たせることは良くないため避けるべきと記載をしました。

それについて、FragmentのAPIで依存しないような機能が提供されていることが判明しました。それについて記載したいと思います。以下で解説を行うAPIは、compatibility v4ベースで行います。Fragment クラスのAPIとして以下の2つのAPIが提供されています。Androidアプリ開発者にはなじみ深いAPIだと思います。

 void	startActivity(Intent intent)
          Call Activity#startActivity(Intent) on the fragment's containing Activity.
 void	startActivityForResult(Intent intent, int requestCode)
          Call Activity#startActivityForResult(Intent, int) on the fragment's containing Activity.

Fragment.java で提供される API

Fragment.java のソースコードは、(Windowsの場合)以下にあります。Linux, MAC の方はそれぞれの環境に読みかえてください。存在しない場合は、SDK Tool で Compatibility Package をダウンロードしてください。

...\android-sdk-windows\extras\android\compatibility\v4\src\java\android\support\v4\app\Fragment.java

Fragment.java の startActivity()メソッドとstartActivityForResult()メソッドをそれぞれ具体的に見ていきたいと思います。
それぞれのメソッドの抜粋が以下のようなものです。

    /**
     * Call {@link Activity#startActivity(Intent)} on the fragment's
     * containing Activity.
     */
    public void startActivity(Intent intent) {
        if (mActivity == null) {
            throw new IllegalStateException("Fragment " + this + " not attached to Activity");
        }
        mActivity.startActivityFromFragment(this, intent, -1);
    }
    /**
     * Call {@link Activity#startActivityForResult(Intent, int)} on the fragment's
     * containing Activity.
     */
    public void startActivityForResult(Intent intent, int requestCode) {
        if (mActivity == null) {
            throw new IllegalStateException("Fragment " + this + " not attached to Activity");
        }
        mActivity.startActivityFromFragment(this, intent, requestCode);
    }

上記の抜粋をみると、mActivityのメソッドを呼び出していることがわかります。
それ以外はただの初期化状態の確認(nullチェック)だけです。
ここで startActivityFromFragment()メソッドという見慣れないメソッドが呼び出されています。
これは何でしょうか?それを探るために、mAcitivyt が何者かを調査します。

FragmentActivity.java で提供される API

    // Activity this fragment is attached to.
    FragmentActivity mActivity;

すると、225行目で mActivity の宣言がありました。ここから FragmentActivity クラスということがわかりました。
続いて、Fragment.java と同じディレクトリにある FragmentActivity.java の中身を見ていきます。

FragmentActivity.java の643行目に startActivityFromFragment() メソッドがありました。

    /**
     * Called by Fragment.startActivityForResult() to implement its behavior.
     */
    public void startActivityFromFragment(Fragment fragment, Intent intent,
            int requestCode) {
        if (requestCode == -1) {
            super.startActivityForResult(intent, -1);
            return;
        }
        if ((requestCode&0xffff0000) != 0) {
            throw new IllegalArgumentException("Can only use lower 16 bits for requestCode");
        }
        super.startActivityForResult(intent, ((fragment.mIndex+1)<<16) + (requestCode&0xffff));
    }

ここでの super は何かというと、FragmentActivity.java の class 宣言で以下のように記載があり、Activity クラスということがわかりました。
つまり、startActivityFromFragment() メソッドで行っていることは、Android開発では一般的な Activity の startActivityForResult()メソッドか startActivityForResult()メソッドを リクエストコード(requestCode)の有無によって、切り替えて実行していることがわかりました。

public class FragmentActivity extends Activity {
    private static final String TAG = "FragmentActivity";

    private static final String FRAGMENTS_TAG = "android:support:fragments";

結論

以前のエントリで Fragment から startActivity() すべきでないと書きましたが、よく分析してみると Fragment で startActivity()しても以下の図のように上位のActivity の startActivyt()メソッドが呼び出される仕組みがあるため、Fragment からでも実施して問題ありません。
FragmentからのActivity呼び出しの正しい方法

Honeycomb はソースコードが公開されておらずこのような調査・分析ができませんが、Compatibility package に関してはソースコードが公開されているのでこのように調査できることは大変有益だと思います。
Fragmentは、Honeycomb と Compatibility package のそれぞれで提供されているAPIが一部異なっているものがあります。
具体的には、ActivityとFragmentActivity や getFragmentMangaer() とgetSupportFragmentManager() などです。

それでも、本ソースコードと Honeycomb 内に実装が大きく異なっているとは考えづらいため、この Compativility package のソースコードから Honeycomb の実装が一部見えてくると思います。早くICSになってソースコードが公開されることを楽しみにしています!

5件のコメント »

  1. vvakame より:

    Android FragmentからのActivity呼び出し方法:
    以前のエントリの「 1apkでAndroidタブレット向けとスマートフォン向けアプリを実現する方法 その3」の「FragmentとActivityの役割… http://t.co/jMLYSaY

  2. gom より:

    Android Fragment から Activityを呼び出す正しい方法について記載 | Bescottee – http://andbrowser.com/develop...

  3. gom より:

    Android Fragment から Activityを呼び出す正しい方法について記載 | Bescottee – http://andbrowser.com/develop...

  4. azure_rin より:

    これかな・・・? http://t.co/vCo3tM3K

  5. AndroidWorld より:

    Android Fragment から Activityを呼び出す正しい方法について記載 | Bescottee – http://andbrowser.com/develop...

このコメント欄の RSS フィード トラックバック URL

コメントをどうぞ