我目前在叠加层中有一个片段。这是用于登录该服务。在手机应用程序中,我想在叠加层中显示的每个步骤都是他们自己的屏幕和活动。登录过程有3个部分,每个部分都有自己的活动,使用startActivityForResult()调用。
现在我想使用片段和叠加来做同样的事情。叠加层将显示与每个活动相对应的片段。问题是这些片段托管在Honeycomb API中的一个活动中。我可以让第一个片段工作,但后来我需要startActivityForResult(),这是不可能的。是否有类似于startFragmentForResult()的内容,我可以启动一个新的片段,当它完成后,它会将结果返回到前一个片段?
答案 0 :(得分:54)
如果您愿意,可以使用一些方法在Fragments之间进行通信,
setTargetFragment(Fragment fragment, int requestCode)
getTargetFragment()
getTargetRequestCode()
您可以使用这些回调。
Fragment invoker = getTargetFragment();
if(invoker != null) {
invoker.callPublicMethod();
}
答案 1 :(得分:46)
所有碎片都存在于活动中。为结果启动片段没有多大意义,因为包含它的Activity始终可以访问它,反之亦然。如果Fragment需要传递结果,它可以访问其Activity并设置其结果并完成它。在单个Activity中交换Fragments的情况下,两个Frags仍然可以访问Activity,并且所有消息传递都可以通过Activity进行。
请记住,您始终在片段及其活动之间进行通信。开始和完成结果是活动之间的通信机制 - 活动可以将任何必要的信息委托给它们的碎片。
答案 2 :(得分:9)
最近,Google刚刚为FragmentManager
添加了一项新功能,使FragmentManager
能够充当片段结果的中央存储。我们可以轻松地在Fragment之间来回传递数据。
起始片段。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Use the Kotlin extension in the fragment-ktx artifact
setResultListener("requestKey") { key, bundle ->
// We use a String here, but any type that can be put in a Bundle is supported
val result = bundle.getString("bundleKey")
// Do something with the result...
}
}
我们想要返回结果的片段。
button.setOnClickListener {
val result = "result"
// Use the Kotlin extension in the fragment-ktx artifact
setResult("requestKey", bundleOf("bundleKey" to result))
}
该摘录摘自Google的官方文档。 https://developer.android.com/training/basics/fragments/pass-data-between#kotlin
在撰写此答案之日,此功能仍处于alpha
状态。您可以使用此依赖性进行尝试。
androidx.fragment:fragment:1.3.0-alpha05
答案 3 :(得分:4)
我的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;
}
}
答案 4 :(得分:1)
在您的片段中,您可以调用getActivity()。这将使您可以访问创建片段的活动。从那里,您可以调用自定义方法来设置值或传递值。
答案 5 :(得分:0)
有一个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));
答案 6 :(得分:0)
最简单的传回数据的方法是setArgument()。例如,您有fragment1调用fragment2,而fragment1调用fragment3,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");
}
答案 7 :(得分:0)
使用接口(和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()
}
最后,在您的父级中实现此功能以接收回调(在本例中为您的Activity):
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)
}
}
}
答案 8 :(得分:0)
根据您的体系结构,您可以做的另一件事是在片段之间使用共享的ViewModel。因此,在我的情况下,FragmentA是表单,而FragmentB是项目选择视图,用户可以在其中搜索和选择项目,并将其存储在ViewModel中。然后,当我回到FragmentA时,信息已存储!
答案 9 :(得分:0)
我们可以在片段之间简单地共享相同的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"
}
}
答案 10 :(得分:-1)
您可以使用EventBus。它简化了活动,片段,线程,服务等之间的通信。代码更少,质量更高。