Android - 在ViewPager中从Activity传递数据给Fragment

18

我有一个简单的Activity,其中包含TabLayout、ViewPager和两个Fragment。这是我的Activity:

public class ManagementCompanyOverviewActivity extends BaseActivity implements ManagementCompanyOverviewView {

    private ManagementCompanyVPAdapter mVPAdapter;
    private TabLayout mTLContent;
    private ViewPager mVPContent;

    @InjectPresenter
    ManagementCompanyPresenter mPresenter;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_management_company);

        mVPAdapter = new ManagementCompanyVPAdapter(getSupportFragmentManager());

        mTLContent = (TabLayout) findViewById(R.id.tl_company_content);

        mVPContent = (ViewPager) findViewById(R.id.vp_company_content);
        mVPContent.setAdapter(mVPAdapter);
        mTLContent.setupWithViewPager(mVPContent);
    }

    @Override
    public void onAboutCompanyInfoReceivedFromServer(AboutCompanyViewModel model) {

    }

在我的应用中,Activity 有一个 Presenter(我使用 Moxy),Presenter 发送请求,获得答案,创建 JavaObject(view model),并使用 getViewState() 将此模型传递给 Activity。我需要将这个模型从 Activity 传递到其中一个 Fragment。

Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

    View view = inflater.inflate(R.layout.fragment_about_company, container, false);

    mTVName = (TextView) view.findViewById(R.id.tv_company_name);
    mTVDirector = (TextView) view.findViewById(R.id.tv_company_director);
    mTVWebsite = (TextView) view.findViewById(R.id.tv_company_website);
    mTVEmail = (TextView) view.findViewById(R.id.tv_company_email);
    mTVPhone = (TextView) view.findViewById(R.id.tv_company_phone);
    mTVSchedule = (TextView) view.findViewById(R.id.tv_company_schedule);
    mTVAddress = (TextView) view.findViewById(R.id.tv_company_address);

    return view;
}

这个片段有一些TextView,用来显示我的模型信息。如何传递这个模型?如果我没错的话,应该创建一个监听器,但是怎么做呢?我不完全明白如何处理它们。

8个回答

22

好的,我已经完成了这个任务。

第一步:我在我的Activity中创建了公共接口,并为其创建了setter:

private OnAboutDataReceivedListener mAboutDataListener;

public interface OnAboutDataReceivedListener {
        void onDataReceived(AboutCompanyViewModel model);
    }

public void setAboutDataListener(OnAboutDataReceivedListener listener) {
    this.mAboutDataListener = listener;
}

第二步:我在我的Fragment中实现了这个接口并设置了监听器:

public class AboutCompanyFragment extends BaseFragment implements ManagementCompanyOverviewActivity.OnAboutDataReceivedListener

    @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);

            mActivity = (ManagementCompanyOverviewActivity) getActivity();
            mActivity.setAboutDataListener(this);
        }

步骤三:我重写了接口的方法:

@Override
    public void onDataReceived(AboutCompanyViewModel model) {
        mPBName.setVisibility(View.INVISIBLE);
        mPBDirector.setVisibility(View.INVISIBLE);
        mPBWebsite.setVisibility(View.INVISIBLE);
        mPBEmail.setVisibility(View.INVISIBLE);
        mPBPhone.setVisibility(View.INVISIBLE);
        mPBSchedule.setVisibility(View.INVISIBLE);
        mPBAddress.setVisibility(View.INVISIBLE);

        mTVName.setVisibility(View.VISIBLE);
        mTVDirector.setVisibility(View.VISIBLE);
        mTVWebsite.setVisibility(View.VISIBLE);
        mTVEmail.setVisibility(View.VISIBLE);
        mTVPhone.setVisibility(View.VISIBLE);
        mTVSchedule.setVisibility(View.VISIBLE);
        mTVAddress.setVisibility(View.VISIBLE);

        mTVName.setText(model.getCompanyName());
        mTVDirector.setText(model.getDirectorName());
        mTVWebsite.setText(model.getWebsite());
        mTVEmail.setText(model.getEmail());
        mTVPhone.setText(model.getPhone());
        mTVSchedule.setText(model.getWorkTime());
        mTVAddress.setText(model.getAddress());
    }

就这样了。


1
如何从活动中分配 AboutCompanyViewModel? - Masterpiece Mas Icang
@MasterpieceMasIcang,你只需要调用你的接口方法并传递参数即可。 - Den
1
@Den,你能告诉我如何设置活动中的数据并给出示例吗? - Shivam Kumar
2
当片段被替换或销毁时,这会出现问题吗? - Mr.Drew
这段代码仅在片段来自同一活动时才有效...如果更改活动,则此行将不再有用:- mActivity =(ManagementCompanyOverviewActivity)getActivity(); - M. H.
显示剩余2条评论

6

尝试这个: 在活动中

public String sendData() {
        return YOUR_STRING;
    }

在片段中
YOUR_ACTIVITY activity = (YOUR_ACTIVITY) getActivity();
String getData = activity.SendData();

不行,不会起作用。数据来自服务器,需要3-5秒才能接收到。当我的Activity接收到这些数据时,将调用方法public void onAboutCompanyInfoReceivedFromServer(AboutCompanyViewModel model)。 - Den
当数据准备好时,Activity 应该将数据发送到 Fragment。我不能使用 getter。 - Den
1
当您收到数据时,可以尝试使用setupViewPager,我在我的应用程序中就是这样做的。 - MKovac
你能贴一些示例代码吗?只需编辑您的第一个答案 :) - Den
我不知道你从哪里获取数据。我正在使用AsyncTask,当任务完成后,我调用setupViewPager。只需将mTLContent.setupWithViewPager(mVPContent);放入获取数据响应的方法中即可。 - MKovac
显示剩余2条评论

6
您可以在Fragment中使用newInstance方法:
public static MyFragment newInstance(String parameter) {

        Bundle args = new Bundle();
        args.putString("parameter", parameter);
        SfCategoryFragment fragment = new SfCategoryFragment();
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (getArguments() != null) {
            parameter = getArguments().getString("parameter");
        }
    }

在您的 Activity 中: 使用 MyFragment.newInstance("yourParam"); 代替 new MyFragment()

谢谢。它在我的情况下起作用并节省了我很多时间! - hetsgandhi

3

在适配器的构造函数中,您还可以输入要在片段中显示的数据,并在返回新片段之前设置参数。

public class ViewPagerAdapter extends FragmentStatePagerAdapter {
private Weather weather;

ViewPagerAdapter(FragmentManager fm, Weather weather) {
    super(fm);
    this.weather = weather;
}

@Override
public Fragment getItem(int position) {
    switch (position) {
        case 0:
            Bundle bundle = new Bundle();
            WeatherFragment weatherFragment = new WeatherFragment();
            bundle.putParcelable("weather", weather);
            weatherFragment.setArguments(bundle);
            return weatherFragment;
        case 1:
            return new PoemFragment();
        default:
            return new EmptyFragment();
    }
}

2
不,我的片段已经在运行了,我不想重新初始化它。 - Den
嗨,这个问题的新解决方案是:如果您正在使用MVVM,则使用共享的viewModel。谢谢! - Rajneesh Shukla

2
从Activity或ViewPager中获取。最初的回答。
Bundle bundle = new Bundle();
bundle.putParcelable(Keys.KEY_ITEM, cardResult);
CardItemFragment cardItemFragment = new CardItemFragment();
cardItemFragment.setArguments(bundle);

From Fragment

@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
     getBundle();
}


private void getBundle() {
    bundle = getArguments();
    if (null != bundle) {
        if (bundle.containsKey(Keys.KEY_ITEM)) {
            cardResult = bundle.getParcelable(Keys.KEY_ITEM);
        }
    }
}

2

片段

class SampleFragment : Fragment(), BaseFragmentInteraction {
    override fun updateFragmentData(data: String) {
        Toast.makeText(activity!!, data, Toast.LENGTH_SHORT).show()
    }
}

接口

interface BaseFragmentInteraction {
    fun updateFragmentData(data: String)
}

活动:

view_pager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {

        override fun onPageSelected(position: Int) {
            val fragmentItem = (view_pager.adapter as FragmentPagerAdapter).getItem(view_pager.currentItem)
            (fragmentItem as BaseFragmentInteraction).updateFragmentData("SomeData")
        }

        override fun onPageScrollStateChanged(state: Int) {}

        override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
    })

updateFragmentData 方法将在当前选择的 viewpager 项 fragment 中调用。您还可以为 updateFragmetData 添加一个标签参数,以确保调用正确的 fragment 实例。如果需要,可以在 updateFragmetData 的实现中调用 isVisible 来确保 fragment 可见。


0

当使用FragmentStatePagerAdapter时,您可以通过2个简单的步骤将数据从活动传递到片段或任何您想要的片段:

第一步:将数据从Activity传递到ViewPagerAdapter类:为此,您需要向构造函数添加另一个属性(属性==您的数据)

第二步:将数据从viewPagerAdapter类传递到片段:现在,在createFragment()函数中,您可以使用bundle传递该属性

最后:在片段中接收数据


0

我发现了一种新的将数据传递给Fragment或Fragment Adapter的方法。

首先,你需要创建一个获取数据的getter方法。比如你想要获取用户名,在Activity中创建一个方法。

public String getUsername(){
return username;
}

然后你可以像这样从片段和片段适配器中调用此方法

片段

(MainActivity) getActivity()).getUsername()

适配器

(MainActivity) context).getUsername()

这种方式也可以帮助您减少对数据库的请求次数


1
如果你的Fragment被用在另一个Activity中怎么办?你应该总是使用接口来重复使用你的代码。 - Den
你是100%正确的,但我们正在谈论从活动传递数据到片段,如果你需要在其他未运行状态的活动中使用数据,则必须使用接口。 - Adnan Bashir
无论如何,在我的原始帖子中,情况是活动从互联网接收一些数据,这个活动应该将这些数据发送到片段,而getter在这种情况下是无法帮助的。 - Den

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