我试图在程序中的两个fragmens之间传递数据。它只是一个存储在List中的简单字符串。 List在片段A中公开,当用户点击列表项时,我需要它显示在片段B中。内容提供者似乎只支持ID,因此不起作用。有什么建议吗?
答案 0 :(得分:57)
我认为片段之间的沟通应该通过活动来完成。片段和活动之间的通信可以这样做: https://developer.android.com/training/basics/fragments/communicating.html https://developer.android.com/guide/components/fragments.html#CommunicatingWithActivity
答案 1 :(得分:21)
如果您使用Roboguice,您可以使用Roboguice中的EventManager来传递数据,而无需将Activity用作界面。这是相当干净的IMO。
如果您不使用Roboguice,您也可以使用Otto作为活动总线:http://square.github.com/otto/
更新20150909 :您现在也可以使用绿色机器人事件总线甚至RxJava。取决于您的用例。
答案 2 :(得分:17)
来自Fragment
documentation:
通常,您会希望一个片段与另一个片段进行通信,例如根据用户事件更改内容。所有Fragment-to-Fragment通信都是通过相关的Activity完成的。两个碎片永远不应该直接沟通。
所以我建议您查看文档中的basic fragment training docs。他们非常全面,有一个例子和一个演练指南。
答案 3 :(得分:15)
为什么不使用Bundle。从您的第一个片段开始,以下是如何设置它:
Fragment fragment = new Fragment();
Bundle bundle = new Bundle();
bundle.putInt(key, value);
fragment.setArguments(bundle);
然后在第二个片段中,使用以下方法检索数据:
Bundle bundle = this.getArguments();
int myInt = bundle.getInt(key, defaultValue);
Bundle为许多数据类型设置了方法。请参阅ALTER TABLE without locking the table?
答案 4 :(得分:11)
因此,假设您拥有控制Frag A和Fragment B的Activity AB。 在Fragment A中你需要一个Activity AB可以实现的接口。 在示例android代码中,他们有:
private Callbacks mCallbacks = sDummyCallbacks;
/ *包含此片段的所有活动必须实现的回调接口。此机制允许活动通知项目选择。 * /
public interface Callbacks {
/*Callback for when an item has been selected. */
public void onItemSelected(String id);
}
/*A dummy implementation of the {@link Callbacks} interface that does nothing. Used only when this fragment is not attached to an activity. */
private static Callbacks sDummyCallbacks = new Callbacks() {
@Override
public void onItemSelected(String id) {
}
};
Callback接口放在你的一个片段中(让我们说片段A)。我认为这个Callbacks接口的目的就像Frag A中的嵌套类,任何Activity都可以实现。因此,如果片段A是电视,则CallBacks是允许片段A被活动AB使用的电视遥控器(接口)。我可能错了细节,因为我是一个菜鸟,但我确实让我的程序在所有屏幕尺寸上完美运行,这就是我使用的。
因此在Fragment A中,我们有: (我从Android的示例程序中获取了这个)
@Override
public void onListItemClick(ListView listView, View view, int position, long id) {
super.onListItemClick(listView, view, position, id);
// Notify the active callbacks interface (the activity, if the
// fragment is attached to one) that an item has been selected.
mCallbacks.onItemSelected(DummyContent.ITEMS.get(position).id);
//mCallbacks.onItemSelected( PUT YOUR SHIT HERE. int, String, etc.);
//mCallbacks.onItemSelected (Object);
}
在Activity AB中,我们覆盖了onItemSelected方法:
public class AB extends FragmentActivity implements ItemListFragment.Callbacks {
//...
@Override
//public void onItemSelected (CATCH YOUR SHIT HERE) {
//public void onItemSelected (Object obj) {
public void onItemSelected(String id) {
//Pass Data to Fragment B. For example:
Bundle arguments = new Bundle();
arguments.putString(“FragmentB_package”, id);
FragmentB fragment = new FragmentB();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction().replace(R.id.item_detail_container, fragment).commit();
}
因此,在Activity AB中,你基本上把所有东西都扔进了Bundle并将它传递给B.如果你不确定如何使用Bundle,请查看该类。
我基本上按照Android提供的示例代码进行操作。带有DummyContent的东西。当您制作新的Android应用程序包时,它就是名为MasterDetailFlow的那个。
答案 5 :(得分:7)
1-第一种方法是定义一个接口
public interface OnMessage{
void sendMessage(int fragmentId, String message);
}
public interface OnReceive{
void onReceive(String message);
}
2-在你的活动中实现OnMessage接口
public class MyActivity implements OnMessage {
...
@Override
public void sendMessage(int fragmentId, String message){
Fragment fragment = getSupportFragmentManager().findFragmentById(fragmentId);
((OnReceive) fragment).sendMessage();
}
}
3-在您的片段中实现OnReceive接口
public class MyFragment implements OnReceive{
...
@Override
public void onReceive(String message){
myTextView.setText("Received message:" + message);
}
}
这是处理片段之间传递消息的样板版本。
在片段之间处理数据通道的另一种方法是使用事件总线。
1-注册/注销事件总线
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
2-定义事件类
public class Message{
public final String message;
public Message(String message){
this.message = message;
}
}
3-在您的应用程序的任何位置发布此活动
EventBus.getDefault().post(new Message("hello world"));
4-订阅该事件以在片段中接收
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessage(Message event){
mytextview.setText(event.message);
}
关于事件总线模式的更多details, use cases, and an example project。
答案 6 :(得分:2)
在我的情况下,我必须从FragmentB-> FragmentA向后发送数据,因此Intents不是一个选项,因为片段已经初始化尽管所有的以上答案< / strong>听起来不错需要大量的锅炉板代码来实现,所以我选择了更简单的方法使用 LocalBroadcastManager ,它确切地说上面所说但没有令人讨厌的样板代码。下面分享一个例子。
发送片段(片段B)
public class FragmentB {
private void sendMessage() {
Intent intent = new Intent("custom-event-name");
intent.putExtra("message", "your message");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
}
在收到消息的片段中(片段A)
public class FragmentA {
@Override
public void onCreate(Bundle savedInstanceState) {
...
// Register receiver
LocalBroadcastManager.getInstance(this).registerReceiver(receiver,
new IntentFilter("custom-event-name"));
}
// This will be called whenever an Intent with an action named "custom-event-name" is broadcasted.
private BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String message = intent.getStringExtra("message");
}
};
}
希望它有助于某人
答案 7 :(得分:1)
这取决于片段的结构。如果您可以将Fragment Class B上的某些方法设置为静态,并将目标TextView对象设置为静态,则可以直接在Fragment Class A上调用该方法。这比侦听器更好,因为该方法是即时执行的,我们不会需要有一个额外的任务,在整个活动中执行监听。见下面的例子:
Fragment_class_B.setmyText(String yourstring);
在片段B上,您可以将方法定义为:
public static void setmyText(final String string) {
myTextView.setText(string);
}
不要忘记将myTextView设置为Fragment B上的static,并在Fragment A上正确导入Fragment B类。
刚刚在我的项目上完成了这个程序并且它有效。希望有所帮助。
答案 8 :(得分:1)
你可以阅读这个文档。这个概念在这里得到了很好的解释http://developer.android.com/training/basics/fragments/communicating.html
答案 9 :(得分:1)
我正在开展一个类似的项目,我猜我的代码可能会对上述情况有所帮助
以下是我正在做的事情的概述
我的项目有两个片段叫做“ FragmentA ”和“FragmentB ”
- FragmentA 当您单击 FragmentA 中的项目时,包含一个列表视图使用Communicator界面将INDEX传递给 FragmentB
我正在使用MainActivity的参考从 FrgamentA 触发响应()接口方法。
接口通信器在fragmentA中定义,这是为通信器接口提供最少的访问权限。
下面是我的完整工作代码
<强> FragmentA.java 强>
public class FragmentA extends Fragment implements OnItemClickListener {
ListView list;
Communicator communicater;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
return inflater.inflate(R.layout.fragmenta, container,false);
}
public void setCommunicator(Communicator c){
communicater=c;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
communicater=(Communicator) getActivity();
list = (ListView) getActivity().findViewById(R.id.lvModularListView);
ArrayAdapter<?> adapter = ArrayAdapter.createFromResource(getActivity(),
R.array.items, android.R.layout.simple_list_item_1);
list.setAdapter(adapter);
list.setOnItemClickListener(this);
}
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int index, long arg3) {
communicater.respond(index);
}
public interface Communicator{
public void respond(int index);
}
}
<强> fragmentB.java 强>
public class FragmentA extends Fragment implements OnItemClickListener {
ListView list;
Communicator communicater;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
return inflater.inflate(R.layout.fragmenta, container,false);
}
public void setCommunicator(Communicator c){
communicater=c;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
communicater=(Communicator) getActivity();
list = (ListView) getActivity().findViewById(R.id.lvModularListView);
ArrayAdapter<?> adapter = ArrayAdapter.createFromResource(getActivity(),
R.array.items, android.R.layout.simple_list_item_1);
list.setAdapter(adapter);
list.setOnItemClickListener(this);
}
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int index, long arg3) {
communicater.respond(index);
}
public interface Communicator{
public void respond(int index);
}
}
<强> MainActivity.java 强>
public class MainActivity extends Activity implements FragmentA.Communicator {
FragmentManager manager=getFragmentManager();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentA fragA=(FragmentA) manager.findFragmentById(R.id.fragmenta);
fragA.setCommunicator(this);
}
@Override
public void respond(int i) {
// TODO Auto-generated method stub
FragmentB FragB=(FragmentB) manager.findFragmentById(R.id.fragmentb);
FragB.changetext(i);
}
}
答案 10 :(得分:1)
基本上实现接口以在Activity和fragment之间进行通信。
1)主要活动
public class MainActivity extends Activity implements SendFragment.StartCommunication
{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public void setComm(String msg) {
// TODO Auto-generated method stub
DisplayFragment mDisplayFragment = (DisplayFragment)getFragmentManager().findFragmentById(R.id.fragment2);
if(mDisplayFragment != null && mDisplayFragment.isInLayout())
{
mDisplayFragment.setText(msg);
}
else
{
Toast.makeText(this, "Error Sending Message", Toast.LENGTH_SHORT).show();
}
}
}
2)发件人片段(片段到活动)
public class SendFragment extends Fragment
{
StartCommunication mStartCommunicationListner;
String msg = "hi";
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View mView = (View) inflater.inflate(R.layout.send_fragment, container);
final EditText mEditText = (EditText)mView.findViewById(R.id.editText1);
Button mButton = (Button) mView.findViewById(R.id.button1);
mButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
msg = mEditText.getText().toString();
sendMessage();
}
});
return mView;
}
interface StartCommunication
{
public void setComm(String msg);
}
@Override
public void onAttach(Activity activity) {
// TODO Auto-generated method stub
super.onAttach(activity);
if(activity instanceof StartCommunication)
{
mStartCommunicationListner = (StartCommunication)activity;
}
else
throw new ClassCastException();
}
public void sendMessage()
{
mStartCommunicationListner.setComm(msg);
}
}
3)接收器片段(活动到片段)
public class DisplayFragment extends Fragment
{
View mView;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
mView = (View) inflater.inflate(R.layout.display_frgmt_layout, container);
return mView;
}
void setText(String msg)
{
TextView mTextView = (TextView) mView.findViewById(R.id.textView1);
mTextView.setText(msg);
}
}
我使用此链接获得相同的解决方案,我希望有人会发现它很有用。 非常简单和基本的例子。
http://infobloggall.com/2014/06/22/communication-between-activity-and-fragments/
答案 11 :(得分:0)
片段A类
public class CountryListFragment extends ListFragment{
/** List of countries to be displayed in the ListFragment */
ListFragmentItemClickListener ifaceItemClickListener;
/** An interface for defining the callback method */
public interface ListFragmentItemClickListener {
/** This method will be invoked when an item in the ListFragment is clicked */
void onListFragmentItemClick(int position);
}
/** A callback function, executed when this fragment is attached to an activity */
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try{
/** This statement ensures that the hosting activity implements ListFragmentItemClickListener */
ifaceItemClickListener = (ListFragmentItemClickListener) activity;
}catch(Exception e){
Toast.makeText(activity.getBaseContext(), "Exception",Toast.LENGTH_SHORT).show();
}
}
片段B类
public class CountryDetailsFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
/** Inflating the layout country_details_fragment_layout to the view object v */
View v = inflater.inflate(R.layout.country_details_fragment_layout, null);
/** Getting the textview object of the layout to set the details */
TextView tv = (TextView) v.findViewById(R.id.country_details);
/** Getting the bundle object passed from MainActivity ( in Landscape mode ) or from
* CountryDetailsActivity ( in Portrait Mode )
* */
Bundle b = getArguments();
/** Getting the clicked item's position and setting corresponding details in the textview of the detailed fragment */
tv.setText("Details of " + Country.name[b.getInt("position")]);
return v;
}
}
用于在片段之间传递数据的主要活动类
public class MainActivity extends Activity implements ListFragmentItemClickListener {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
/** This method will be executed when the user clicks on an item in the listview */
@Override
public void onListFragmentItemClick(int position) {
/** Getting the orientation ( Landscape or Portrait ) of the screen */
int orientation = getResources().getConfiguration().orientation;
/** Landscape Mode */
if(orientation == Configuration.ORIENTATION_LANDSCAPE ){
/** Getting the fragment manager for fragment related operations */
FragmentManager fragmentManager = getFragmentManager();
/** Getting the fragmenttransaction object, which can be used to add, remove or replace a fragment */
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
/** Getting the existing detailed fragment object, if it already exists.
* The fragment object is retrieved by its tag name *
*/
Fragment prevFrag = fragmentManager.findFragmentByTag("in.wptrafficanalyzer.country.details");
/** Remove the existing detailed fragment object if it exists */
if(prevFrag!=null)
fragmentTransaction.remove(prevFrag);
/** Instantiating the fragment CountryDetailsFragment */
CountryDetailsFragment fragment = new CountryDetailsFragment();
/** Creating a bundle object to pass the data(the clicked item's position) from the activity to the fragment */
Bundle b = new Bundle();
/** Setting the data to the bundle object */
b.putInt("position", position);
/** Setting the bundle object to the fragment */
fragment.setArguments(b);
/** Adding the fragment to the fragment transaction */
fragmentTransaction.add(R.id.detail_fragment_container, fragment,"in.wptrafficanalyzer.country.details");
/** Adding this transaction to backstack */
fragmentTransaction.addToBackStack(null);
/** Making this transaction in effect */
fragmentTransaction.commit();
}else{ /** Portrait Mode or Square mode */
/** Creating an intent object to start the CountryDetailsActivity */
Intent intent = new Intent("in.wptrafficanalyzer.CountryDetailsActivity");
/** Setting data ( the clicked item's position ) to this intent */
intent.putExtra("position", position);
/** Starting the activity by passing the implicit intent */
startActivity(intent);
}
}
}
Detailde acitivity class
public class CountryDetailsActivity extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/** Setting the layout for this activity */
setContentView(R.layout.country_details_activity_layout);
/** Getting the fragment manager for fragment related operations */
FragmentManager fragmentManager = getFragmentManager();
/** Getting the fragmenttransaction object, which can be used to add, remove or replace a fragment */
FragmentTransaction fragmentTransacton = fragmentManager.beginTransaction();
/** Instantiating the fragment CountryDetailsFragment */
CountryDetailsFragment detailsFragment = new CountryDetailsFragment();
/** Creating a bundle object to pass the data(the clicked item's position) from the activity to the fragment */
Bundle b = new Bundle();
/** Setting the data to the bundle object from the Intent*/
b.putInt("position", getIntent().getIntExtra("position", 0));
/** Setting the bundle object to the fragment */
detailsFragment.setArguments(b);
/** Adding the fragment to the fragment transaction */
fragmentTransacton.add(R.id.country_details_fragment_container, detailsFragment);
/** Making this transaction in effect */
fragmentTransacton.commit();
}
}
数据库数组
public class Country {
/** Array of countries used to display in CountryListFragment */
static String name[] = new String[] {
"India",
"Pakistan",
"Sri Lanka",
"China",
"Bangladesh",
"Nepal",
"Afghanistan",
"North Korea",
"South Korea",
"Japan",
"Bhutan"
};
}
有关详细信息,请访问此链接[http://wptrafficanalyzer.in/blog/itemclick-handler-for-listfragment-in-android/]。有完整的例子..
答案 12 :(得分:0)
getParentFragmentManager().setFragmentResultListener
是实现这一目标的2020年方法。您唯一的限制是使用捆绑包传递数据。查看docs以获得更多信息和示例。
其他方式
getActivity()
并将其强制转换为片段之间的共享活动,然后将其用作传递数据的桥梁。强烈建议不要使用此解决方案,因为它需要在活动和片段之间进行繁琐的修饰,但是在KitKat时代,它曾经是最受欢迎的解决方案... FragmentManager
相比,它的好处在于它不仅限于捆绑软件。但是,不利的一面是,当片段管理器处于保存状态或活动被破坏时,您可能会遇到一些极端情况的错误,从而弄乱了活动的生命周期并获得了IllegalStateException
之类的异常。另外,它不支持跨处理通信。答案 13 :(得分:-2)
基本上我们在这里处理片段之间的通信。片段之间的通信永远不可能直接实现。它涉及在两个片段都被创建的上下文中的活动。
您需要在发送片段中创建一个接口,并在活动中实现该接口,该接口将重新缓存消息并传输到接收片段。