65

这个问题主要是就处理我的应用程序的最佳方式征求意见。我有一个活动正在处理三个片段。片段 A 有一个可点击的照片元素,片段 B 有 4 个可点击的元素和按钮。单击照片时,另一个片段仅显示详细信息。我正在使用 ActionBarSherlock。

截屏

前进和后退按钮需要分别将照片更改为下一个或上一个姿势。我可以将照片和按钮保留在同一个片段中,但想将它们分开,以防我想在平板电脑中重新排列它们。

我需要一些建议——我应该把片段 A 和 B 结合起来吗?如果没有,我需要弄清楚如何为 3 个可点击项目实现接口。

我考虑过使用 Roboguice,但我已经在使用 SherlockFragmentActivity 进行扩展,所以这是不行的。我看到提到了 Otto,但是我没有看到关于如何包含在项目中的好的教程。您认为最佳设计实践应该是什么?

我还需要帮助弄清楚如何在片段和活动之间进行通信。我想在应用程序中保留一些“全局”数据,例如姿势 ID。除了股票 android 开发人员的信息之外,我还能看到一些示例代码吗?这并不是那么有帮助。

顺便说一句,我已经将有关每个姿势的所有信息存储在 SQLite 数据库中。那是容易的部分。

4

11 回答 11

87

在 Activity 和 Fragment 之间进行通信的最简单方法是使用接口。这个想法基本上是在给定的片段 A 中定义一个接口,并让活动实现该接口。

一旦它实现了那个接口,你就可以在它覆盖的方法中做任何你想做的事情。

接口的另一个重要部分是您必须从片段中调用抽象方法并记住将其转换为您的活动。如果没有正确完成,它应该捕获 ClassCastException。

简单开发人员博客上有一个很好的教程,介绍了如何做这种事情。

我希望这对你有帮助!

于 2014-08-19T20:38:10.500 回答
24

在 Fragment 之间进行通信的建议方法是使用由主 Activity 管理的回调\侦听器。

我认为这个页面上的代码很清楚:http: //developer.android.com/training/basics/fragments/communicating.html

您还可以参考 IO 2012 Schedule 应用程序,该应用程序旨在成为事实上的参考应用程序。可以在这里找到: http ://code.google.com/p/iosched/

此外,这是一个包含很好信息的 SO 问题: 如何在片段之间传递数据

于 2013-01-09T23:13:49.483 回答
20

它由一个回调接口实现:

首先,我们要做一个接口:

public interface UpdateFrag {
     void updatefrag();
}

在活动中执行以下代码:

UpdateFrag updatfrag ;

public void updateApi(UpdateFrag listener) {
        updatfrag = listener;
}

从必须在 Activity 中触发回调的事件:

updatfrag.updatefrag();

在 Fragment 中实现接口,CreateView执行以下代码:

 ((Home)getActivity()).updateApi(new UpdateFrag() {
        @Override
        public void updatefrag() {
              .....your stuff......
        }
 });
于 2016-09-03T17:48:14.173 回答
8

anActivityFragments之间的通信有多种选择,但经过大量阅读和经验,我发现可以这样恢复:

  • Activity想和孩子交流Fragment=> 只需在你的类中编写公共方法Fragment,然后让Activity他们调用
  • Fragment想要与父母沟通Activity=> 这需要更多的工作,正如官方 Android 链接https://developer.android.com/training/basics/fragments/communicating所建议的那样,定义interface一个将由 执行Activity,并且将为任何Activity想要与之通信的人建立合同Fragment。例如,如果您FragmentA想要与activity包含它的任何对象进行通信,则定义FragmentAInterfacewhich 将定义FragmentA调用activities决定使用它的方法的方法。
  • AFragment想与其他人交流Fragment=> 这是您遇到最“复杂”情况的情况。由于您可能需要将数据从 FragmentA 传递到 FragmentB,反之亦然,这可能导致我们定义 2 个接口,它们FragmentAInterface将由. 这将开始使事情变得混乱。并想象一下,如果您还有更多的地方,甚至父母也想与他们交流。好吧,这个案例是为 the and it's建立共享的完美时机。更多信息在这里https://developer.android.com/topic/libraries/architecture/viewmodel。基本上,您需要定义一个FragmentBFragmentAInterfaceFragmentAFragmentactivityViewModelactivityfragmentSharedViewModel类,它包含您想要在它们之间共享的所有数据,activity并且它们之间fragments需要在它们之间进行数据通信。

这种ViewModel情况最终使事情变得非常简单,因为您不必添加额外的逻辑来使代码变得肮脏和混乱。此外,它还允许您将数据的收集(通过对 SQLite 数据库或 API 的调用)与Controller(activitiesfragments) 分开。

于 2018-08-10T15:33:29.407 回答
5

我做了一个注释库,可以为你做演员。看一下这个。 https://github.com/zeroarst/callbackfragment/

@CallbackFragment
public class MyFragment extends Fragment {

    @Callback
    interface FragmentCallback {
       void onClickButton(MyFragment fragment);
    }    
    private FragmentCallback mCallback;

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.bt1
                mCallback.onClickButton(this);
                break;
            case R.id.bt2
                // Because we give mandatory = false so this might be null if not implemented by the host.
                if (mCallbackNotForce != null)
                mCallbackNotForce.onClickButton(this);
                break;
        }
    }
}

然后它会生成片段的子类。只需将其添加到 FragmentManager。

public class MainActivity extends AppCompatActivity implements MyFragment.FragmentCallback {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        getSupportFragmentManager().beginTransaction()
            .add(R.id.lo_fragm_container, MyFragmentCallbackable.create(), "MY_FRAGM")
            .commit();
    }

    Toast mToast;

    @Override
    public void onClickButton(MyFragment fragment) {
        if (mToast != null)
            mToast.cancel();
        mToast = Toast.makeText(this, "Callback from " + fragment.getTag(), Toast.LENGTH_SHORT);
        mToast.show();
    }
}
于 2017-06-22T08:14:13.467 回答
2

在活动、片段、服务等之间有多种通信方式。最明显的一种是使用接口进行通信。但是,这不是一种有效的沟通方式。您必须实现侦听器等。

我的建议是使用事件总线。事件总线是一种发布/订阅模式的实现。

您可以订阅活动中的事件,然后可以在片段等中发布该事件。

在我的博客文章中,您可以找到有关此模式的更多详细信息,以及一个示例项目来展示其用法。

于 2016-04-08T13:45:57.177 回答
2

谷歌推荐方法

如果您查看此页面,您会看到 Google 建议您使用和ViewModel之间共享数据。FragmentActivity

添加此依赖项:

implementation "androidx.activity:activity-ktx:$activity_version"

首先,定义ViewModel您将用于传递数据的对象。

class ItemViewModel : ViewModel() {
    private val mutableSelectedItem = MutableLiveData<Item>()
    val selectedItem: LiveData<Item> get() = mutableSelectedItem

    fun selectItem(item: Item) {
        mutableSelectedItem.value = item
    }
}

其次,实例化ViewModel里面的Activity.

class MainActivity : AppCompatActivity() {
    // Using the viewModels() Kotlin property delegate from the activity-ktx
    // artifact to retrieve the ViewModel in the activity scope
    private val viewModel: ItemViewModel by viewModels()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        viewModel.selectedItem.observe(this, Observer { item ->
            // Perform an action with the latest item data
        })
    }
}

三、实例化ViewModel里面的Fragment.

class ListFragment : Fragment() {
    // Using the activityViewModels() Kotlin property delegate from the
    // fragment-ktx artifact to retrieve the ViewModel in the activity scope
    private val viewModel: ItemViewModel by activityViewModels()

    // Called when the item is clicked
    fun onItemClicked(item: Item) {
        // Set a new item
        viewModel.selectItem(item)
    }
}

您现在可以编辑此代码以创建新的观察者或设置方法。

于 2021-06-04T22:30:23.090 回答
1

我不确定我是否真的了解您想要做什么,但建议在片段之间进行通信的方法是使用 Activity 的回调,而不是直接在片段之间进行通信。见这里http://developer.android.com/training/basics/fragments/communicating.html

于 2013-01-09T23:08:20.323 回答
0

您可以在片段中创建一个带有函数声明的公共接口,并在活动中实现该接口。然后您可以从片段中调用该函数。

于 2013-06-07T13:52:55.657 回答
0

我正在使用 Intents 将操作传达回主要活动。主要活动是通过覆盖 onNewIntent(Intent intent) 来监听这些。例如,主要活动将这些动作转换为相应的片段。

所以你可以做这样的事情:

public class MainActivity extends Activity  {

    public static final String INTENT_ACTION_SHOW_FOO = "show_foo";
    public static final String INTENT_ACTION_SHOW_BAR = "show_bar";


   @Override
   protected void onNewIntent(Intent intent) {
        routeIntent(intent);
   }

  private void routeIntent(Intent intent) {
       String action = intent.getAction();
       if (action != null) {               
            switch (action) {
            case INTENT_ACTION_SHOW_FOO:
                // for example show the corresponding fragment
                loadFragment(FooFragment);
                break;
            case INTENT_ACTION_SHOW_BAR:
                loadFragment(BarFragment);
                break;               
        }
    }
}

然后在任何片段中显示 foo 片段:

Intent intent = new Intent(context, MainActivity.class);
intent.setAction(INTENT_ACTION_SHOW_FOO);
// Prevent activity to be re-instantiated if it is already running.
// Instead, the onNewEvent() is triggered
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
getContext().startActivity(intent);
于 2015-12-16T11:17:58.153 回答
-1

有最新的技术可以在没有任何接口的情况下将片段与活动通信,请按照步骤 1- 在 gradle 中添加依赖项

实现 'androidx.fragment:fragment:1.3.0-rc01'

于 2020-12-29T12:26:51.130 回答