如何在片段之间传递数据

我试图在程序中的两个片段之间传递数据。它只是存储在 List 中的一个简单字符串。List 在片段 A 中公开,当用户单击一个列表项时,我需要它显示在片段 B 中。内容提供程序似乎只支持 ID,因此不会起作用。有什么建议吗?

169826 次浏览

如果您使用 Roboguice,您可以使用 Roboguice 的 EventManager 来传递数据,而无需使用 Activity 作为接口。这是相当干净的 IMO。

如果你不使用 Roboguice,你也可以使用 Otto 作为事件总线: http://square.github.com/otto/

更新20150909: 你现在也可以使用绿色机器人事件总线或者甚至 RxJava,这取决于你的用例。

来自 Fragment 文件:

通常,您希望一个片段与另一个片段通信,例如根据用户事件更改内容。所有的片段到片段的通信都是通过相关的活动完成的。两个碎片不应该直接交流。

所以我建议您在文档中查看 基本碎片训练文件。他们非常全面,包括一个例子和一个演练指南。

这取决于片段的结构。如果可以在片段类 B 静态和目标 TextView 对象静态上使用某些方法,则可以直接在片段类 A 上调用该方法。这比侦听器要好,因为方法是即时执行的,而且我们不需要在整个活动中执行侦听的额外任务。请看下面的例子:

Fragment_class_B.setmyText(String yourstring);

在片段 B 上,你可以将方法定义为:

public static void setmyText(final String string) {
myTextView.setText(string);
}

只是不要忘记在片段 B 上将 myTextView 设置为静态的,并正确导入片段 A 上的片段 B 类。

我最近刚做了一个手术,很有效,希望有帮助。

假设你有活动 AB 来控制片段 A 和片段 B。 在片段 A 内部,你需要一个活动 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)。我认为这个 Callback 接口的用途类似于在 Frag A 中嵌套的类,任何 Activity 都可以实现它。因此,如果片段 A 是一台电视,则 CallBacks 是允许活动 AB 使用片段 A 的 TV Remote (接口)。我可能错误的细节,因为我是一个菜鸟,但我没有得到我的程序工作在所有屏幕大小完美,这是我使用的。

所以在碎片 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 中,你基本上把所有的东西都放到一个包里,然后传给 B。如果您不确定如何使用 Bundle,请查找该类。

我基本上是按照 Android 提供的示例代码来做的。有傻瓜内容的那个。当你制作一个新的 Android 应用软件包时,它就是名为 MasterDetailFlow 的软件包。

你可以阅读这个文件。这个概念在这里解释得很好

我正在从事一个类似的项目,我想我的代码可能会在上述情况下有所帮助

这是我所做的概述

我的项目有两个片段称为“ 片段 A”和“ ”片段 B

- 片段 A包含一个列表视图,当您单击 片段 A中的一个项目时,它的 INDEX 通过通信器接口传递给 片段 B

  • 设计模式完全基于 Java 接口的概念 “ < strong > 接口引用变量可以引用子类对象”
  • 主要活动实现由 片段 A提供的接口(否则我们不能使接口引用变量指向 MainActivity)
  • 在下面的代码中,通信器对象使用 片段 A中的“ SetCommunicator (Communicatot c)”方法引用 “主要活动”对象。
  • 我正在使用 MainActivity 的引用从 FrgamentA触发接口的 回应()方法。

    接口通信器定义在片段 A 中,这是为了提供对 通讯器接口的最少访问优先权。

下面是我的完整工作代码

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);
}

}

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);
}






}

基本上,我们在这里处理的是碎片之间的通信。片段之间的通信永远不可能直接实现。它涉及在上下文中创建这两个片段的活动。

您需要在发送片段中创建一个接口,并在活动中实现该接口,该接口将缓存消息并传输到接收片段。

主要实现活动和片段之间的接口通信。

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/

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);
}
}
}

详细活动类别

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/]。有完整的例子. 。

为什么不使用一个 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 已经为许多数据类型提供了方法。请参见 http://developer.android.com/reference/android/os/Bundle.html

第一种方法是定义一个接口

public interface OnMessage{
void sendMessage(int fragmentId, String message);
}


public interface OnReceive{
void onReceive(String message);
}

在活动中实现 OnMessage 接口

public class MyActivity implements OnMessage {
...
@Override
public void sendMessage(int fragmentId, String message){
Fragment fragment = getSupportFragmentManager().findFragmentById(fragmentId);
((OnReceive) fragment).sendMessage();
}
}

在片段中实现 OnReceiveinterface

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();
}

定义一个事件类

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);
}

了解更多关于事件总线模式的 详细信息、用例和示例项目

在我的情况下,我不得不使用 从片段 B-> 片段 A 向后发送数据,因此意图不是一个选项,因为片段已经被初始化了尽管所有的 以上答案听起来都不错,但它需要一个 大量锅炉板代码的实现,所以我使用了一个更多的 更简单的方法使用 本地广播经理,它确实做到了上面所说的,但没有所有讨厌的样板代码。下面共享一个示例。

在发送片段(片段 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");
}
};
}

希望能帮到别人

getParentFragmentManager().setFragmentResultListener是2020年的做法。您唯一的限制是使用 bundle 来传递数据。查看 医生了解更多信息和例子。

还有其他办法

  • 调用 getActivity()并将其强制转换为片段之间的共享活动,然后使用它作为传递数据的桥梁。这种解决方案是强烈不推荐的,因为它需要在活动和碎片之间的杯形,但它曾经是流行的方式做到这一点回到 KitKat 的日子..。
  • 使用回调。任何事件机制都可以。这将是一个 Java 香草解决方案。相对于 FragmentManager的好处是它不仅仅局限于 Bundles。然而,缺点是,当片段管理器处于保存状态或者活动已经被销毁时,您可能会遇到边缘情况的 bug,在这种情况下,您会把活动生命周期搞乱,并得到类似于 IllegalStateException的异常。此外,它不支持跨处理通信。