将 Fragment 之间的数据传递给 Activity
Posted
技术标签:
【中文标题】将 Fragment 之间的数据传递给 Activity【英文标题】:Passing Data Between Fragments to Activity 【发布时间】:2013-01-04 14:01:47 【问题描述】:我需要在 5 个 fragments
到一个 Activity
之间传递数据,当我到达第 5 个 fragment
时,那些 fragments
一个接一个地发送数据,然后我需要存储所有 5 个 fragments
数据如何我们可以这样做吗?任何想法都很棒。
【问题讨论】:
【参考方案1】:将数据从每个片段传递给活动,当活动获取所有数据然后处理它。 您可以使用接口传递数据。
片段:
public class Fragment2 extends Fragment
public interface onSomeEventListener
public void someEvent(String s);
onSomeEventListener someEventListener;
@Override
public void onAttach(Activity activity)
super.onAttach(activity);
try
someEventListener = (onSomeEventListener) activity;
catch (ClassCastException e)
throw new ClassCastException(activity.toString() + " must implement onSomeEventListener");
final String LOG_TAG = "myLogs";
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
View v = inflater.inflate(R.layout.fragment2, null);
Button button = (Button) v.findViewById(R.id.button);
button.setOnClickListener(new OnClickListener()
public void onClick(View v)
someEventListener.someEvent("Test text to Fragment1");
);
return v;
活动:
public class MainActivity extends Activity implements onSomeEventListener
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Fragment frag2 = new Fragment2();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(R.id.fragment2, frag2);
ft.commit();
@Override
public void someEvent(String s)
Fragment frag1 = getFragmentManager().findFragmentById(R.id.fragment1);
((TextView)frag1.getView().findViewById(R.id.textView)).setText("Text from Fragment 2:" + s);
【讨论】:
Hey Kalyanganov Alexey 能否通过一个简单的示例向我详细说明如何使用接口传递数据... 舒尔。谷歌有很好的例子developer.android.com/training/basics/fragments/… 但如果我在最后一个片段中只有一个按钮,我该怎么做? ***.com/questions/32953477/pass-data-to-fragment【参考方案2】:以下链接解释了片段之间的通信设计。
Communicating with Other Fragments
要允许 Fragment 与其 Activity 进行通信,您可以在 Fragment 类中定义一个接口并在 Activity 中实现它。 Fragment 在其 onAttach() 生命周期方法期间捕获接口实现,然后可以调用接口方法以与 Activity 通信。
以下是 Fragment 到 Activity 通信的示例:
public class HeadlinesFragment extends ListFragment
OnHeadlineSelectedListener mCallback;
// Container Activity must implement this interface
public interface OnHeadlineSelectedListener
public void onArticleSelected(int position);
@Override
public void onAttach(Activity activity)
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try
mCallback = (OnHeadlineSelectedListener) activity;
catch (ClassCastException e)
throw new ClassCastException(activity.toString()
+ " must implement OnHeadlineSelectedListener");
...
现在片段可以通过使用 OnHeadlineSelectedListener 接口的 mCallback 实例调用 onArticleSelected() 方法(或接口中的其他方法)将消息传递给 Activity。
例如,当用户单击列表项时,会调用片段中的以下方法。 Fragment 使用回调接口将事件传递给父 Activity。
@Override
public void onListItemClick(ListView l, View v, int position, long id)
// Send the event to the host activity
mCallback.onArticleSelected(position);
实现接口
为了从片段接收事件回调,承载它的活动必须实现片段类中定义的接口。
例如,以下活动实现了上例中的接口。
public static class MainActivity extends Activity
implements HeadlinesFragment.OnHeadlineSelectedListener
...
public void onArticleSelected(int position)
// The user selected the headline of an article from the HeadlinesFragment
// Do something here to display that article
向片段传递消息
宿主Activity可以通过findFragmentById()捕获Fragment实例,将消息传递给Fragment,然后直接调用Fragment的公共方法。
例如,假设上面显示的活动可能包含另一个片段,用于显示上述回调方法中返回的数据指定的项目。在这种情况下,Activity 可以将回调方法中接收到的信息传递给将显示该项目的另一个 Fragment:
public static class MainActivity extends Activity
implements HeadlinesFragment.OnHeadlineSelectedListener
...
public void onArticleSelected(int position)
// The user selected the headline of an article from the HeadlinesFragment
// Do something here to display that article
ArticleFragment articleFrag = (ArticleFragment)
getSupportFragmentManager().findFragmentById(R.id.article_fragment);
if (articleFrag != null)
// If article frag is available, we're in two-pane layout...
// Call a method in the ArticleFragment to update its content
articleFrag.updateArticleView(position);
else
// Otherwise, we're in the one-pane layout and must swap frags...
// Create fragment and give it an argument for the selected article
ArticleFragment newFragment = new ArticleFragment();
Bundle args = new Bundle();
args.putInt(ArticleFragment.ARG_POSITION, position);
newFragment.setArguments(args);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack so the user can navigate back
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
【讨论】:
我确实喜欢这样,当我点击时,iPhone 在那个片段中我有一些按钮并编辑文本,然后当我提交时我正在进入主屏幕。当我再次单击列表项的其余部分时,我在最后执行相同的操作时单击所有信息然后我需要将 iPhone、BlackBerry、Android、诺基亚数据发送到不同的活动。我不知道该怎么做。(***.com/questions/14439941/…) 您能否详细说明您面临的问题?你想达到什么目的?【参考方案3】:我尝试了以上所有方法,但对我没有用。这就是我让它工作的方式。我使用接口作为将数据从片段发送到活动的手段。
FragmentToActivity.java
public interface FragmentToActivity
void communicate(String comm);
FragmentOne
public class FragmentOne extends Fragment
private FragmentToActivity mCallback;
@Override
public void onAttach(Context context)
super.onAttach(context);
try
mCallback = (FragmentToActivity) context;
catch (ClassCastException e)
throw new ClassCastException(context.toString()
+ " must implement FragmentToActivity");
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
View v = inflater.inflate(R.layout.fragment_login, container,
false);
sendData("Andrews");
return v;
@Override
public void onDetach()
mCallback = null;
super.onDetach();
public void onRefresh()
Toast.makeText(getActivity(), "Fragment : Refresh called.",
Toast.LENGTH_SHORT).show();
private void sendData(String comm)
mCallback.communicate(comm);
活动一
public class Account extends AppCompatActivity implements
FragmentToActivity
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
@Override
public void communicate(String s)
Log.d("received", s);
【讨论】:
我尝试了很多方法,但都没有奏效。你的方法奏效了。非常感谢:) 在 sendData() 处出现空指针异常。顺便说一句,您正在将数据发送回使该片段膨胀的活动。对吗?【参考方案4】:您必须将信息返回到片段的活动。并且您的 Activity 将信息调度到其片段:
// In fragment A
((ParentActivity)getActivity()).dispatchInformations("test");
// In ParentActivity
public void dispatchInformations(String mesg)
fragmentB.sendMessage(mesg);
这是一个基本的例子
【讨论】:
【参考方案5】:您可以使用上述答案中解释的 Communicator 模式。 另外,您可以使用RxJava2. 以获得更好的解耦和效率。
1- 创建总线:
public final class RxBus
private static final BehaviorSubject<Object> behaviorSubject
= BehaviorSubject.create();
public static BehaviorSubject<Object> getSubject()
return behaviorSubject;
2- 发送者活动或片段
//the data to be passed
MyData data =getMyData();
RxBus.getSubject().onNext(data) ;
3-接收者活动或片段
private Subscription subscription;
public onCreate(Bundle savedInstanceState)
subscription = RxBus.getSubject()
.subscribe(new Subscriber<Object>()
@Override
public void onNext(Object o)
if (o instanceof MyData)
Log.d("tag", (MyData)o.getData();
@Override
public void onError(Throwable e)
@Override
public void onComplete()
);
4-取消订阅以避免内存泄漏:
@Override
protected void onDestroy()
super.onDestroy();
if(subscription!=null)
subscription.unsubscribe();
【讨论】:
我已经尝试过您的解决方案。基本上它可以工作,但需要一些修改【参考方案6】:有一种非常简单的方法可以将数据从 Fragment 传递到另一个不是其容器的 Activity。
1) 在 Fragment 中:当您启动 Activity 时,例如 onButtonClick,将您想要传递的数据作为额外的数据传递到您的意图中,如下所示:
Intent intent = new Intent(getActivity(), MapsActivity.class);
intent.putExtra("data", dataString);
startActivity(intent);
2)在接收Activity中:在你的onCreate方法中,创建一个Bundle来获取传递过来的信息,如下:
Bundle extras = getIntent().getExtras();
if (extras != null)
receivingString = extras.getString("data");
else
// handle case
希望它有所帮助:)
【讨论】:
【参考方案7】:我一直在寻找将数据从片段传递到活动的解决方案。我就是这样做的,我发现它最适合我的需要。
我发现最好使用全局 shared ViewModel
共享和更新数据
在共享 ViewModel 中,我使用可变实时数据存储和更新数据,并将其范围限定为 MainActivity。 ViewModel 是一个单例,在活动生命周期结束之前一直保留在内存中。
class SharedViewModel: ViewModel()
private val selectedItems: MutableLiveData<List<Product>> =
MutableLiveData<List<Product>>(listOf())
fun getItems(): LiveData<List<Product>>
return selectedItems
fun sendSelectedItems(items: MutableList<Product>)
selectedItems.postValue(items)
MainActivity: AppCompactActivity()
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
// scope shared view model to MainActivity
// I can access and update data from here
val model = ViewModelProvider(this).get(SharedViewModel::class.java)
class MyFragment1: Fragment()
// I'm able to get and update data in the SharedViewModel in fragment
// to activity
private val sharedModel: SharedViewModel by activityViewModels()
此外,您可以向主活动添加回调。您可以使用接口。
interface IAddListener
fun sendItems(items: MutableList<Product>?)
class MyFragment: Fragment()
override fun onAttach(context: Context)
super.onAttach(context)
if (context is IAddListener)
mCallback = context
private var mCallback: IAddListener? = null
class MainActivity: AppCompactActivity(), IAddToPrintQueueListener
override fun sendItems(items: MutableList<Product>?)
// update something
这是关于共享数据的文档的链接documentation
【讨论】:
以上是关于将 Fragment 之间的数据传递给 Activity的主要内容,如果未能解决你的问题,请参考以下文章
如何在通过广播接收器将 JobIntentService 之间的数据传递给活动时防止 TransactionTooLarge 异常
导航架构组件 - 使用 Fragment 将参数数据传递给 startDestination