在片段和活动之间进行通信 - 最佳实践

时间:2013-01-09 22:52:27

标签: android android-fragments android-activity communication

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

Screen shot

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

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

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

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

顺便说一下,我已经在SQLite数据库中存储了每个姿势的所有信息。这很容易。

11 个答案:

答案 0 :(得分:70)

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

一旦实现了该界面,您就可以在它覆盖的方法中执行任何操作。

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

Simple Developer Blog有一个关于如何做到这一点的好教程。

我希望这对你有所帮助!

答案 1 :(得分:23)

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

我认为此页面上的代码非常清晰: http://developer.android.com/training/basics/fragments/communicating.html

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

此外,这是一个有良好信息的SO问题: How to pass data between fragments

答案 2 :(得分:9)

通过回调接口实现: 首先,我们必须建立一个界面:

public interface UpdateFrag {
     public void updatefrag();
    }

在活动中,请执行以下代码:

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

来自回调必须在活动中触发的事件:

updatfrag.updatefrag();

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

 ((Home)getActivity()).updateApi(new UpdateFrag() {
                @Override
                public void updatefrag() {
                   .....your stuff......
                }
            });

答案 3 :(得分:4)

我制作了一个可以为你做演员表的注释库。看一下这个。 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();
    }
}

答案 4 :(得分:3)

要在ActivityFragment之间进行交流,有几种选择,但是经过大量阅读和大量经验,我发现可以通过以下方式恢复:

  • Activity要与孩子Fragment =>交流,只需在您的Fragment类中编写公共方法,然后让Activity对其进行调用
  • Fragment要与父级Activity =>交流,这需要做更多的工作,正如官方的Android链接https://developer.android.com/training/basics/fragments/communicating所建议的那样,定义一个interface将由Activity实施,并且将为要与该Activity通信的任何Fragment建立合同。例如,如果您有FragmentA,希望与包含它的任何activity通信,则定义FragmentAInterface,它将定义FragmentA可以调用哪种方法。 activities决定使用它。
  • 一个Fragment要与其他Fragment进行交流=>在这种情况下,您会遇到最“复杂”的情况。由于您可能需要将数据从FragmentA传递到FragmentB,反之亦然,因此可能导致我们定义2个接口,FragmentAInterface将由FragmentB实现,而FragmentAInterface将由FragmentA实现Fragment。那将使事情变得混乱。想象一下,如果您还有更多activity,甚至父母ViewModel也想与他们交流。好了,这种情况是为activityfragment建立共享SharedViewModel的绝佳时机。更多信息,请点击https://developer.android.com/topic/libraries/architecture/viewmodel。基本上,您需要定义一个activity类,该类具有要在fragmentsViewModel之间共享的所有数据,而这些数据将需要在它们之间进行通信。

Controller情况使最后的事情变得更加简单,因为您不必添加额外的逻辑即可使事情变得肮脏且混乱。另外,它还允许您从activitiesfragmentspg_hba.conf)中分离数据的收集(通过调用SQLite数据库或API)。

答案 5 :(得分:2)

有多种方法可以在活动,片段,服务等之间进行通信。显而易见的方法是使用接口进行通信。但是,它不是一种富有成效的沟通方式。你必须实现听众等。

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

您可以订阅活动中的活动,然后您可以将这些活动发布到您的片段等中。

on my blog post,您可以找到有关此模式的更多详细信息,还可以an example project显示该用途。

答案 6 :(得分:1)

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

答案 7 :(得分:0)

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

答案 8 :(得分: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);

答案 9 :(得分:0)

Google 推荐的方法

如果您查看 this page,您会发现 Google 建议您使用 ViewModelFragmentActivity 之间共享数据。

添加此依赖项:

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

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

答案 10 :(得分:-1)

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

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