現在、オーバーレイにフラグメントがあります。これは、サービスにサインインするためのものです。電話アプリでは、オーバーレイに表示する各ステップは、独自の画面とアクティビティです。サインインプロセスには3つの部分があり、それぞれにstartActivityForResult()で呼び出された独自のアクティビティがありました。
次に、フラグメントとオーバーレイを使用して同じことを行いたいと思います。オーバーレイには、各アクティビティに対応するフラグメントが表示されます。問題は、これらのフラグメントがHoneycomb APIのアクティビティでホストされていることです。最初のフラグメントを機能させることはできますが、それからstartActivityForResult()を実行する必要がありますが、これは不可能です。 startFragmentForResult()の行に沿って、新しいフラグメントを開始し、完了したら前のフラグメントに結果を返すものがありますか?
すべてのフラグメントはアクティビティ内に存在します。結果のフラグメントを開始することはあまり意味がありません。なぜなら、それを格納するアクティビティは常にそれにアクセスできるからです。フラグメントが結果を渡す必要がある場合、アクティビティにアクセスし、結果を設定して終了できます。単一のアクティビティでフラグメントを交換する場合、アクティビティは両方のフラグメントからアクセス可能であり、メッセージの受け渡しはすべてアクティビティを通過するだけです。
フラグメントとそのアクティビティの間には常にコミュニケーションがあることに注意してください。結果の開始と結果の終了は、アクティビティ間の通信のメカニズムです。アクティビティは必要な情報をフラグメントに委任できます。
必要に応じて、フラグメント間の通信にはいくつかの方法があります。
setTargetFragment(Fragment fragment, int requestCode)
getTargetFragment()
getTargetRequestCode()
これらを使用してコールバックできます。
Fragment invoker = getTargetFragment();
if(invoker != null) {
invoker.callPublicMethod();
}
私の2セント。
Hideとshow/add(existing/new)を使用して、古いフラグメントを新しいフラグメントと交換することにより、フラグメントを切り替えます。この答えは、私と同じようにフラグメントを使用する開発者向けです。
次に、onHiddenChanged
メソッドを使用して、古いフラグメントが新しいフラグメントから切り替えられたことを確認します。以下のコードを参照してください。
新しいフラグメントを残す前に、グローバルパラメータに結果を設定して、古いフラグメントによってクエリを実行します。これは非常に単純なソリューションです。
@Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
if (hidden) return;
Result result = Result.getAndReset();
if (result == Result.Refresh) {
refresh();
}
}
public enum Result {
Refresh;
private static Result RESULT;
public static void set(Result result) {
if (RESULT == Refresh) {
// Refresh already requested - no point in setting anything else;
return;
}
RESULT = result;
}
public static Result getAndReset() {
Result result = RESULT;
RESULT = null;
return result;
}
}
フラグメント間で単純に同じ ViewModel を共有できます
SharedViewModel
import Android.Arch.lifecycle.MutableLiveData
import Android.Arch.lifecycle.ViewModel
class SharedViewModel : ViewModel() {
val stringData: MutableLiveData<String> by lazy {
MutableLiveData<String>()
}
}
FirstFragment
import Android.Arch.lifecycle.Observer
import Android.os.Bundle
import Android.Arch.lifecycle.ViewModelProviders
import Android.support.v4.app.Fragment
import Android.view.LayoutInflater
import Android.view.View
import Android.view.ViewGroup
class FirstFragment : Fragment() {
private lateinit var sharedViewModel: SharedViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activity?.run {
sharedViewModel = ViewModelProviders.of(this).get(SharedViewModel::class.Java)
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_first, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
sharedViewModel.stringData.observe(this, Observer { dateString ->
// get the changed String
})
}
}
SecondFragment
import Android.Arch.lifecycle.ViewModelProviders
import Android.os.Bundle
import Android.support.v4.app.Fragment
import Android.view.LayoutInflater
import Android.view.View
import Android.view.ViewGrou
class SecondFragment : Fragment() {
private lateinit var sharedViewModel: SharedViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activity?.run {
sharedViewModel = ViewModelProviders.of(this).get(SharedViewModel::class.Java)
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_first, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
changeString()
}
private fun changeString() {
sharedViewModel.stringData.value = "Test"
}
}
フラグメントでは、getActivity()を呼び出すことができます。これにより、フラグメントを作成したアクティビティにアクセスできます。そこから、customizeメソッドを呼び出して、値を設定するか、値を渡すことができます。
EventBus を使用できます。これにより、アクティビティ、フラグメント、スレッド、サービスなどの間の通信が簡素化されます。コードが少なくなり、品質が向上します。
データを戻す最も簡単な方法は、setArgument()を使用することです。たとえば、fragment3を呼び出すfragment2を呼び出すfragment1、fragment1-> framgnet2-> fargment3があります。
Fragment1で
public void navigateToFragment2() {
if (fragmentManager == null) return;
Fragment2 fragment = Fragment2.newInstance();
String tag = "Fragment 2 here";
fragmentManager.beginTransaction()
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
.add(R.id.flContent, fragment, tag)
.addToBackStack(null)
.commitAllowingStateLoss();
}
Fragment2では、通常どおりfragment3を呼び出します
private void navigateToFragment3() {
if (fragmentManager == null) return;
Fragment3 fragment = new Fragment3();
fragmentManager.beginTransaction()
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
.replace(R.id.flContent, fragment, tag)
.addToBackStack(null)
.commit();
}
Fragment3でタスクを完了したら、次のように呼び出します。
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
if (fragmentManager == null) return;
fragmentManager.popBackStack();
Bundle bundle = new Bundle();
bundle.putString("bundle_filter", "data");
fragmentManager.findFragmentByTag("Fragment 2 here").setArguments(bundle);
Fragment2では、引数を簡単に呼び出すことができます
@Override
public void onResume() {
super.onResume();
Bundle rgs = getArguments();
if (args != null)
String data = rgs.getString("bundle_filter");
}
Androidライブラリ- FlowR があり、結果のフラグメントを開始できます。
結果のフラグメントを開始します。
Flowr.open(RequestFragment.class)
.displayFragmentForResults(getFragmentId(), REQUEST_CODE);
呼び出しフラグメントの結果を処理します。
@Override
protected void onFragmentResults(int requestCode, int resultCode, Bundle data) {
super.onFragmentResults(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
demoTextView.setText("Result OK");
} else {
demoTextView.setText("Result CANCELED");
}
}
}
フラグメントに結果を設定します。
Flowr.closeWithResults(getResultsResponse(resultCode, resultData));
アーキテクチャに応じてできるもう1つのことは、フラグメント間で共有ViewModelを使用することです。したがって、私の場合、FragmentAはフォームで、FragmentBはユーザーがアイテムを検索して選択し、ViewModelに保存するアイテム選択ビューです。その後、FragmentAに戻ると、情報はすでに保存されています!
インターフェイス(およびKotlin)を使用したソリューション。コアとなるアイデアは、コールバックインターフェイスを定義し、アクティビティに実装してから、フラグメントから呼び出すことです。
まず、インターフェイスActionHandler
を作成します。
interface ActionHandler {
fun handleAction(actionCode: String, result: Int)
}
次に、これをあなたの子供(この場合はあなたのフラグメント)から呼び出します:
companion object {
const val FRAGMENT_A_CLOSED = "com.example.fragment_a_closed"
}
fun closeFragment() {
try {
(activity as ActionHandler).handleAction(FRAGMENT_A_CLOSED, 1234)
} catch (e: ClassCastException) {
Timber.e("Calling activity can't get callback!")
}
dismiss()
}
最後に、コールバック(この場合はアクティビティ)を受け取るために、親にこれを実装します:
class MainActivity: ActionHandler {
override fun handleAction(actionCode: String, result: Int) {
when {
actionCode == FragmentA.FRAGMENT_A_CLOSED -> {
doSomething(result)
}
actionCode == FragmentB.FRAGMENT_B_CLOSED -> {
doSomethingElse(result)
}
actionCode == FragmentC.FRAGMENT_C_CLOSED -> {
doAnotherThing(result)
}
}
}