【问题标题】:How to communicate from Mainactivity to Fragment using callback interface?如何使用回调接口从 Mainactivity 与 Fragment 进行通信?
【发布时间】:2016-07-11 19:41:00
【问题描述】:

我有四个菜单的导航抽屉,每个菜单都有自己的片段 , 在第一个片段内部有视图分页器滑动选项卡和 2 个片段,

Activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/drawer_layout"
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        android:fitsSystemWindows="true">

    <android.support.design.widget.CoordinatorLayout  
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/main_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.design.widget.AppBarLayout
            android:id="@+id/appbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:animateLayoutChanges="true"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="?attr/colorPrimary"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

            <android.support.design.widget.TabLayout
                android:id="@+id/tabs"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:tabIndicatorColor="@color/white"
                app:tabIndicatorHeight="4dp" />

        </android.support.design.widget.AppBarLayout>

////////////// Here I'm replacing each fragments ////////////////
        <FrameLayout   
            android:id="@+id/main_content_framelayout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior" />

        <android.support.design.widget.FloatingActionButton
            android:id="@+id/fab"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="end|bottom"
            android:layout_margin="@dimen/fab_margin"
            android:src="@drawable/ic_done"
            android:visibility="gone"/>

    </android.support.design.widget.CoordinatorLayout>


        <android.support.design.widget.NavigationView
            android:id="@+id/nav_view"
            android:layout_height="match_parent"
            android:layout_width="wrap_content"
            android:layout_gravity="start"
            android:fitsSystemWindows="true"
            app:headerLayout="@layout/nav_header"
            app:menu="@menu/drawer_view"/>

    </android.support.v4.widget.DrawerLayout>

ManinActivity-DrawerSelection

 public void selectDrawerItem(MenuItem menuItem) {
        // Create a new fragment and specify the fragment to show based on nav item clicked
        Fragment fragment = null;
        Class fragmentClass = null;

        switch (menuItem.getItemId()) {
            case R.id.nav_home:
                fragmentClass = Home_Tab_Fragment.class;
                break;
            case R.id.nav_myorders:
                fragmentClass = SecondFragment.class;
                break;
            case R.id.nav_myoffers:
                fragmentClass = ThirdFragment.class;
                break;
            case R.id.nav_notification:
                fragmentClass = FourthFragment.class;
                break;

        }

                fragment = (Fragment) fragmentClass.newInstance();
                FragmentManager fragmentManager = getSupportFragmentManager();
                fragmentManager.beginTransaction().replace(R.id.main_content_framelayout, fragment).commit();
                mDrawerLayout.closeDrawers();

}

HomeTabFragment

public class Home_Tab_Fragment extends Fragment {

    private FragmentActivity myContext;
    ViewPager viewPager;
    TabLayout tabLayout;
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View rootView =  inflater.inflate(R.layout.layout_viewpager, container, false);
          viewPager = (ViewPager) rootView.findViewById(R.id.view_pager);
        return rootView;
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        SlidingTabAdapter adapter = new SlidingTabAdapter(getChildFragmentManager());
        adapter.addFragment(new FirstTabFragment(), "First TAB");
        adapter.addFragment(new SecondTabFragment(), "Second Tab");
        viewPager.setAdapter(adapter);
        tabLayout = (TabLayout) getActivity().findViewById(R.id.tabs);
        tabLayout.setVisibility(View.VISIBLE);
        tabLayout.setupWithViewPager(viewPager);
    }

}

SlidingTabAdapter

public class SlidingTabAdapter extends FragmentPagerAdapter {

    private final List<Fragment> mFragments = new ArrayList<>();
    private final List<String> mFragmentTitles = new ArrayList<>();

    public SlidingTabAdapter(FragmentManager fm) {
        super(fm);
    }

    public void addFragment(Fragment fragment, String title) {
        mFragments.add(fragment);
        mFragmentTitles.add(title);
    }

    @Override
    public Fragment getItem(int position) {
        return mFragments.get(position);
    }

    @Override
    public int getCount() {
        return mFragments.size();
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return mFragmentTitles.get(position);
    }
}

layout_viewpager.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.view.ViewPager
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/view_pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

第一个片段

public class FirstTabFragment extends Fragment {

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
     View rootView = inflater.inflate(R.layout.fragment_first, container, false);
        getActivity().setTitle("Foodies");
        return rootView ;
    }

  public void updateFirstFragmentValues(){
      //Doing some operations
  }

}

在 MainActivity 里面,我想调用 FirstTabFragment 方法 [updateFirstFragmentValues()]

我尝试在 FirstTabFragment 中添加 TAG,

public static final String TAG ="FirstTabFragment.TAG";

然后我像下面这样在 MainActivity 中调用,但 Fragment 始终为空。

 public void invokeMethodFromFirstTabFragment() {
        FragmentManager fm = this.getSupportFragmentManager();
        FirstTabFragment fb=(FirstTabFragment)fm.findFragmentByTag(FirstTabFragment.TAG);
        if (null != fb) {
            fb.updateFirstFragmentValues();
        }else{
            L.m("Fragment is null===========");
        }
    }

请告知,如何从“MainActivity”中调用“FirstTabFragment”方法

请注意 FirstTabFragment 不直接添加到 MainActivity , 它通过“Home_Tab_Fragment”添加。

【问题讨论】:

  • 您是否考虑过为此使用回调之类的东西?
  • @Georgy Savatkov :我正在使用回调接口将片段通信到活动,但这种情况下我想从活动到片段进行通信。您可以为此提供示例代码吗?
  • 如果 FirstTabFragment 没有直接添加到 MainActivity。对于这种类型的需求,您不能使用接口回调..!
  • @Janki gadhiya,请建议从 MainActivity 调用片段公共方法的任何可能方式。我的真实情况是,一旦从服务器加载数据,我想刷新片段 recyclerview 适配器数据。
  • 我认为你的布局设计有点混乱。回复我,我会尽力给出解决方案

标签: android android-layout android-fragments android-viewpager navigation-drawer


【解决方案1】:

好的,阅读您的所有回复,我知道您只需要在创建时将数据传递给片段并能够执行片段的一些方法。好的,很简单:

IMessageFragment 接口

public interface IMessageFragment {
  /**
   * Method to receive new message text
   * @param text Message text to receive
   */
   void updateMessageText(String text);
}

消息片段

public class MessageFragment extends Fragment implements IMessageFragment {
  /**
   * Bind views using ButterKnife
   */
  @BindView(R.id.textView) TextView mTextView;

  /**
   * Bundle data
   */
  private String mMessageText;

  /**
   * Unique id of bundle data
   */
  private static final String MESSAGE_EXTRA_KEY = "f_message";

  /**
   * New fragment pattern. This is pretty much all the magic PLUS this
   * looks by far better than `new Fragment()` upon instatiation
   */
  public static MessageFragment newFragment(String message) {
      // 1. Create new fragment
      MessageFragment auctionFragment = new MessageFragment();
      // 2. Create bundle for fragment params
      Bundle args = new Bundle();
      // 3. Put position
      args.putString(MESSAGE_EXTRA_KEY, message);
      // 4. Set arguments
      auctionFragment.setArguments(args);
      return auctionFragment;
  }


  @Nullable
  @Override
  public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
      View view = inflater.inflate(R.layout.tutorial_fragment, container, false);

      /**
       * Bind views
       */
      ButterKnife.bind(this, view);

      // Update UI
      updateUI();

      return view;
  }

  /**
   * Method to update value of mTextView
   */
  private void updateUI() {
      if(!mMessageText.equals("")) {
          mTextView.setText(mMessageText);
      }
  }

  @Override
  public void updateMessageText(String text) {
      mMessageText = text;
      updateUI();
  }
}

东西非常简单,界面的存在只是为了良好的代码风格和支持设计模式。

【讨论】:

  • 能否请你添加一些代码,如何通过 IMessageFragment 将文本从 Mainactivity 发送到 MessageFragment。
【解决方案2】:

编辑:

您不能从 MainActivity 直接访问 FirstTabFragment 方法。首先,您必须从活动中调用Home_Tab_Fragment 方法。然后从该方法中您可以调用FirstTabFragment 方法。

这里是策略:

第 1 步:Home_Tab_FragmentFirstTabFragment 通信

定义这样的接口

public interface IHomeToFirstFragmentController{
          void firstFragmentMethod();
    } 

现在在您的FirstTabFragment 中实现IHomeToFirstFragmentController。那么你必须实现firstFragmentMethod()

@overrride
    void firstFragmentMethod(){

    }

使用这种方式从Home_Tab_Fragment调用这个firstFragmentMethod方法

YOUR_fragmentInstance.firstFragmentMethod();

第 2 步: 活动至Home_Tab_Fragment

定义这样的接口

public interface IActivityToHomeTabController{
          void callFirstFragment();
    }

现在在您的Home_Tab_Fragment 中实现IFragmentController。那么你必须实现callFirstFragment()

@overrride
void callFirstFragment(){
  YOUR_fragmentInstance.firstFragmentMethod();
}

编辑 2:

使用这种方式调用片段

((IFragmentController)YOUR_fragmentInstance).firstFragmentMethod();

希望这能让您对这些主题有所了解。欲了解更多信息,请访问this answer

【讨论】:

  • @Sajedul Karim,我尝试了您的方法,但无法在 Mainactivity IFragmentController mHomeTabCall; mHomeTabCall=(HomeTabCall) MainActivity.this; mHomeTabCall.callFirstFragment(); 中调用 IFragmentController 错误:Caused by: java.lang.ClassCastException: com.example.activities.MainActivity cannot be cast to com.example.activities.IFragmentController
  • 对不起,那是我的错误。我编辑了我的答案。请检查一下。
【解决方案3】:

首先,你创建界面:

public interface CallBackListener{
      void onCallBack();
}

在片段中

public MyFragment extends Fragment{
    private CallBackListener mCallBack;

    @Override
    public void onAttach(Context context) {
        AppCompatActivity activity;
        if (context instanceof AppCompatActivity) {
            activity = (AppCompatActivity) context;
            try {
                mCallBack= (CallBackListener ) activity;
            } catch (ClassCastException e) {
                throw new ClassCastException(activity.toString() + " class must be implement" +
                        " OnBackFragmentListener");
            }
        }
        super.onAttach(context);
    }
}

使用:

mCallBack.onCallBack();

而在Activity中,你必须实现接口:

public MyActivity extends AppCompatActivity implements CallBackListener{

   @Override
   public void onCallBack(){
   // Do somethings here...
   }
}

【讨论】:

  • @lrish Louis,请注意我不想从片段调用到活动。我想从 Activity 调用 fragment 。 , 如何在Activity类中附加接口
  • 对不起。我认为如果你想将数据从活动传递到片段,你可以使用片段的参数,广播接收器,处理程序 - 消息......
  • 不能使用接口回调activity到fragment(个人观点)
  • @lrish Louis ,我无法在 MainActivity 中获取片段实例,因为片段与 MainActivity 没有直接连接,它附加在 ViewPager Host 片段中,并且该宿主片段在 MainActivity 中调用。有什么办法解决这个案子吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多