17

Android アプリを新しいサポート ライブラリ (support-v4:21.0.0) に移植しようとしていますが、トランジションでフラグメントからアクティビティを開始するのに問題があります。

私のアクティビティでは、次のようなことをしています。

Bundle options = ActivityOptionsCompat.makeSceneTransitionAnimation(this).toBundle();
ActivityCompat.startActivityForResult(this, intent, REQUEST_SOMETHING, options);

これはアクティビティに適しています。ただし、フラグメントで同様のことをしようとすると、次のようになります。

Activity activity = getActivity();
Bundle options = ActivityOptionsCompat.makeSceneTransitionAnimation(activity).toBundle();
ActivityCompat.startActivityForResult(activity, intent, REQUEST_SOMETHING, options);

onActivityResult()Fragment に対して呼び出されるのではなく、それを囲む Activity に対してのみ呼び出されることがわかります。startActivityForResult()サポート ライブラリには、オプション バンドルをパラメータとして実際のフラグメントに渡し、そのフラグメントでコールバックするものは見つかりませんでしたonActivityResult()。これは可能ですか?

最も簡単な解決策はonActivityResult()、アクティビティ自体ですべての呼び出しを処理することですが、そのコールバックを受け取る可能性のあるフラグメントが大量にあるため、私はむしろそれを行いません。

助けていただければ幸いです。ありがとう!

4

4 に答える 4

14

残念ながら、ActivityCompat.startActivityForResult()うまく機能しませんFragments(Alex Lockwood の回答を参照)。数週間、GoogleActivityCompatが Fragment のstartActivityForResult(). 彼らは何を考えていた?! しかし、私はアイデアを思いつきました: メソッドが実際にどのように実装されているか見てみましょう。

実際のところ、startActivityForResult()Fragment は 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);
}

現在startActivityFromFragment()は次のようになっています (こちらを参照):

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));
}

Google は、リクエスト コードで奇妙なバイト シフトを使用して、呼び出し元の Fragment のみがonActivityResult()後で呼び出されるようにします。は何も提供してActivityCompatいないためstartActivityFromFragment()、残された唯一のオプションは自分で実装することです。パッケージのプライベート フィールドにアクセスするには、リフレクションが必要ですmIndex

public static void startActivityForResult(Fragment fragment, Intent intent,
                                          int requestCode, Bundle options) {
    if (Build.VERSION.SDK_INT >= 16) {
        if ((requestCode & 0xffff0000) != 0) {
            throw new IllegalArgumentException("Can only use lower 16 bits" +
                                               " for requestCode");
        }
        if (requestCode != -1) {
            try {
                Field mIndex = Fragment.class.getDeclaredField("mIndex");
                mIndex.setAccessible(true);
                requestCode = ((mIndex.getInt(this) + 1) << 16) + (requestCode & 0xffff);
            } catch (NoSuchFieldException | IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
        ActivityCompat.startActivityForResult(fragment.getActivity(), intent,
                                              requestCode, options);
    } else {
        fragment.getActivity().startActivityFromFragment(this, intent, requestCode);
    }
}

そのメソッドを好きな場所にコピーして、フラグメントから使用します。必要に応じonActivityResult()て呼び出されます。

更新:サポートライブラリv23.2がリリースされ、startActivityFromFragment(Fragment fragment, Intent intent, int requestCode, Bundle options)現在は機能しているようです:)

于 2015-02-26T14:51:05.637 に答える
2

メソッドは、アクティビティのメソッドActivityCompat#startActivityForResult()の単なるプロキシですstartActivityForResult(Intent, Bundle)。フラグメント クラス内からメソッドを呼び出しても、最終的に が呼び出されるFragmentわけではありません。onActivityResult()フレームワークには、呼び出し元のクラスを知る方法があります...この場合、唯一の正しい動作はActivityonActivityResult()メソッドを呼び出すことです。

onActivityResult()投稿で提案したように、アクティビティのメソッドですべてを処理するのが最善の選択肢のようです。

于 2014-11-18T22:07:54.620 に答える
0

簡単な方法:

フラグメントで:

 ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation();

 this.startActivityFromFragment(this, intent, requestCode, options);
于 2016-07-21T01:29:08.747 に答える