FragmentおよびActivityに対するstartActivityForResultの動作を理解する

startActivityForResultとonActivityResult全体では、送信元アクティビティと送信先アクティビティの間の双方向通信が許可されます。 その流れは下の図のようになります。

以下のフローから、OnActivityResultのソースアクティビティからデスティネーションアクティビティへの流れを簡単に理解できます

ソースアクティビティコールは、リクエストコードと一緒にインテントをAndroid SDKに送信することにより、startActivityForResult。

Android SDKは、インテントに記載されているように、アクティビティを開きます。
宛先アクティビティがジョブを終了すると、発信者アクティビティに戻ります。

resultCodeとintentを送信することで、setResultを使用して結果を送り返すことができます

ここでいくつかの注意事項:

resultCodeは、宛先アクティビティによって使用され、

要求コードは、どの宛先アクティビティが呼び出しを返しているかを知るために、送信元アクティビティによって使用されます。

宛先アクティビティに要求コードが表示されていないことがわかりました。

文書化されていないstartActivityForResultフラグメントフロー

フラグメントには、呼び出すstartActivityForResult関数と、オーバーライドするonActivityResult関数もあります。

これはいくつかの質問を提起します…例えば、それはどのように動作しますか? アクティビティのstartActivityForResultおよびonActivityResultと同じですか? 彼らはどのように関連していますか?
短い答えは、それらは似ているが微妙に異なるということである。 混乱の頻繁な原因、およびバグ。 そのため、類似性と相違点を理解することが重要です。

フラグメントフローを図に示します。

以下は、それがすべて一緒にどのように動作するかを明確に示している図です。 ActivityのstartActivityForResultフローとonActivityResultフローとの違いは赤で表示されます。

それについてもっと詳しく説明しましょう。

フラグメントのstartActivityForResultを呼び出すとき(注:activityではありませんか?.startActivityForResult)、宛先アクティビティの作成は同じです。 ただし、違いはonActivityResultです。

startActivityForResult()fragmentから処理する必要がありますonActivityForResult()

getActivity().startActivityForResult() activityonActivityForResult()

から処理する必要がありますfragmentにいて、fragmentの結果を処理する場合はonActivityForResult()を使用し、それ以外の場合は、フラグメントのactivityから処理する場合はgetActivity.startActivityForResult()

Android SDKがonActivityResultを返すと、要求コードが変更されています。 元のrequestCodeに0xp0000が追加されます。

P値は1から始まり、onActivityResultごとにインクリメントされ、同じ宛先フラグメントから呼び出されます。 (別の宛先フラグメントが呼び出されると、P値がリセットされます)。たとえば、元のrequestCodeが0xFF(つまり255)の場合、requestCodeは最初に0x100FFになります。 2回目の戻りrequestCodeは0x200FFになります。

ソースアクティビティのonActivityResultに戻ると、superを呼び出す必要があります。FragmentActivity(AppCompatActivityの親)にあるonActivityResult

FragmentActivityのonActivityResultは、P値を抽出します(requestCode>>16を使用)。 Pは、ソースフラグメントが格納されている配列のインデックスです。 (例えば、requestCodeが0x200ffの場合、0x200ff>> 16 = 2)

P値を使用すると、以下の手順9で使用されるソースフラグメントにアクセスできるようになりました。ここで、元の要求コードに戻るために(requestCode&0xffffを使用して)requestCodeからP値を取り除きます(例: requestCodeが0x200FFの場合、0x200FF&0xffff=0xFF)

ソースフラグメントが作成した元の要求コードを取得すると、元の要求コードでソースフラグメントのonActivityResultを呼び出

いくつかの基本的なポイントを知りたいです。A.ActivityのstartActivityForResultの動作は、FragmentのstartActivityForResult

とは異なりますFragmentでは、activity?.startActivityForResult(...)を呼び出すと、FragmentのonActivityResultは自動的に呼び出されません。

b.アクティビティのonActivityResultをオーバーライドする場合は、superがあることを確認してください。onActivityResultの代わりに

ソースアクティビティのonActivityResultをオーバーライドしたが、super.onActivityResultを忘れた場合、FragmentのonActivityResultは呼び出されません。ActivityのonActivityResultに見られるrequestCodeは、Android SDKがrequestCodePを追加したため、activityのonActivityResultでは、そこに同じrequestCodeを取得することはありません。 これは、コードをデバッグするときに開発者に混乱を引き起こすことがあります。

D.アクティビティが状態から復元されたとき(つまり、onStateInstance!=null)、そのフラグメントの再作成を避ける必要があります。

onActivityResultが呼び出されると、元のフラグメントを取得しようとしました。 これは、killされた状態から復元されたアクティビティに対しても実行されます(たとえば、Don’t Keep Activityを使用してエミュレートされます)。

したがって、onCreateが呼び出されるたびに開発者がフラグメントを再作成すると(復元された状態であるかどうかに関係なく)、復元された元のフラグメントは破棄され、呼び出し元のonActivityResultは不思議なことにフラグメントは呼び出されません。

これは、多くの経験豊富な開発者や現場でリリースされたアプリにとっても落とし穴であり、特定されたバグには非常に困難です(毎回発生していないため、より複雑なフローをトリガする必要があります)。

読んでくれてありがとう…