在Fragments和Activity之间传递数据

17

我需要在5个片段之间传递数据到一个活动,这些片段一个接一个地发送数据,当我到达第五个片段时,我需要存储所有5个片段的数据。我们该怎么做?任何想法都很好。输入图像描述

8个回答

60

将数据从每个片段传递到活动,当活动获取所有数据后再进行处理。 您可以使用接口传递数据。

片段:

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

嘿,Kalyanganov Alexey,你能否向我详细说明如何使用接口传递数据,如果有简单的示例就更好了... - srujan maddula
1
当然。谷歌有很好的例子:http://developer.android.com/training/basics/fragments/communicating.html - Kalyaganov Alexey
但是如果我只有一个按钮,而且它在最后一个片段中,我该怎么办呢? - Hoo

13
以下链接解释了关于片段之间通信的设计。 与其他片段通信 为了让片段与其活动进行通信,您可以在片段类中定义一个接口,并在活动内实现它。片段在其onAttach()生命周期方法期间捕获接口实现,然后可以调用接口方法以便与活动进行通信。
以下是片段到活动通信的示例:
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()方法(或其他接口中的方法),向活动发送消息。

例如,当用户单击列表项时,片段中的以下方法将被调用。片段使用回调接口将事件传递给父活动。

@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
}
}

向一个片段发送消息

主活动可以通过使用findFragmentById()捕获片段实例,然后直接调用片段的公共方法向片段发送消息。

例如,假设上面显示的活动可能包含另一个片段,该片段用于显示返回的数据中指定的项。在这种情况下,活动可以将回调方法接收到的信息传递给将显示该项的其他片段:

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片段中的某个按钮和编辑文本时,然后当我提交时,我回到主屏幕。再次点击列表中的其余项目时,我执行相同的操作,最后当我点击All Info时,我需要将iPhone、BlackBerry、Android、Nokia数据发送到不同的活动中。我不知道该怎么做。 - Androi Developer
你能详细说明你所面临的问题吗?你想要实现什么目标? - Shiva

9

我尝试了上述所有方法,但都没能解决我的问题。这是我是如何做到的。我使用接口将数据从片段发送到活动。

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


}

我尝试了许多方法,但都没有起作用。你的方法很有效。非常感谢 :) - Jagadeesh
在sendData()处出现了空指针异常。顺便问一下,你是将数据发送回充气此片段的那个活动吗? - Karan Malhotra

6
你需要将信息返回给片段所属的活动,然后你的活动将信息传递给其片段:
// In fragment A
((ParentActivity)getActivity()).dispatchInformations("test");

// In ParentActivity
public void dispatchInformations(String mesg){
    fragmentB.sendMessage(mesg);
}

这是一个基本示例


2
你可以使用上面提供的通信模式来解决问题。此外,你还可以使用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();
   }

}

我已经尝试了你的解决方案。基本上它可以工作,但是它需要一些修改。 - Variag

1

有一种非常简单的方法可以将数据从一个Fragment传递到另一个不是其容器的Activity。

1)在Fragment中:当您启动活动时,例如onButtonClick,将要传递的数据作为意图的额外内容传递,如下所示:

     Intent intent = new Intent(getActivity(), MapsActivity.class);
     intent.putExtra("data", dataString);
     startActivity(intent);

2) 在接收活动中:在您的onCreate方法中,创建一个Bundle来检索传递的信息,如下所示:

Bundle extras = getIntent().getExtras();
    if (extras != null) {
        receivingString = extras.getString("data");
    } else {
        // handle case
    }

希望它有所帮助 :)

0
我正在寻找一种从片段传递数据到活动的解决方案。这是我做的,我发现它最适合我所需的。
我发现使用全局共享ViewModel来共享和更新数据最好。
在共享ViewModel中,我使用可变LiveData存储和更新数据,并将其范围限定为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


0
Fragment库提供了两种通信选项:
  1. 共享ViewModel
  2. Fragment Result API。
推荐的选项取决于使用情况。要使用自定义API共享持久数据,请使用ViewModel。对于一次性结果,可以将数据放入Bundle中,请使用Fragment Result API。
请阅读此https://developer.android.com/guide/fragments/communicate#java

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接