我如何使用FragmentStatePagerAdapter有什么问题?

时间:2018-09-19 11:59:17

标签: android user-interface fragmentstatepageradapter

我有一个使用FragmentStatePagerAdapter的Activity。如果我启动另一个活动,该活动更改了一些与显示内容有关的数据,则该视图不会更新。 如果适配器正在处理选项卡,则每个选项卡都通过片段显示同一对象的不同方面, 如果对象属性由适配器处理的页面启动的活动更改, 并且在onActivityResult中调用了适配器notifyDataSetChanged,选项卡视图中的数据没有得到更新,正如我期望的那样。 我不知道为什么。

在活动类别中:

public class EventDetailActivity extends AppCompatActivity
{
    public ViewPager viewPager;
    public PagerAdapter adapter; // This extends FragmentStatePagerAdapter
    public TabLayout tabLayout;
    public Event currentEvent; // ****** Contains the data to display in tabs

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

        currentEvent = (Event)getIntent().getSerializableExtra(Event.EVENT_KEY); // ***** The object on display was serialized to pass in the intent.
        // Serializing it in the initial intent is not a problem, because it is saved in the database within this activity,
        // and the calling activity gets the update via the database.
        tabLayout = (TabLayout) findViewById (R.id.tab_layout);
        tabLayout.addTab(tabLayout.newTab().
            setText(getResources().getString(R.string.details)));
        ... Add other tabs. ...
        tabLayout.setTabGravity (TabLayout.GRAVITY_FILL);
        viewPager = (ViewPager) findViewById (R.id.pager);
        adapter = new PagerAdapter(currentEvent, getSupportFragmentManager(), tabLayout.getTabCount());
        viewPager.setAdapter (adapter);
        viewPager.addOnPageChangeListener (new TabLayout.TabLayoutOnPageChangeListener (tabLayout));
        tabLayout.setOnTabSelectedListener (new TabLayout.OnTabSelectedListener () {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                viewPager.setCurrentItem (tab.getPosition ());
            }
        });
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId ())
        {
            case R.id.menu_edit:
                Intent intent = new Intent(EventDetailActivity.this, EditEventActivity.class);
                intent.putExtra(Event.EVENT_KEY, currentEvent); // TODO Event via serialization, or event id only ?
                //intent.putExtra("id", currentEvent.getId());
                startActivityForResult(intent, EDIT_EVENT_REQUEST);
                return true;
            ... other cases
        }
    }

    @Override
    protected void onActivityResult (int requestCode, int resultCode, Intent data)
    {
        if (requestCode == EDIT_EVENT_REQUEST)
        {
            switch (resultCode)
            {
                case RESULT_CANCELED:
                    // Nothing to do
                    return;
                case RESULT_EVENT_MODIFIED:
                    // Cause event view for this activity to update.
                    // When the edit activity was started, the Event was serialized.
                    // An updated Event is passed back in the result.
                    //currentEvent = (Event)data.getSerializableExtra(Event.EVENT_KEY);
                    //System.out.println("Modified event returned: " + currentEvent.getEventTitle());
                    // Alternatively, Load the Event from the database:
                    try
                    {
                        HashMap attr = MyApp.getDatabase().getEventById(currentEvent.getId());
                        currentEvent.load(attr);
                        System.out.println("Event reloaded: " + currentEvent.getEventTitle());
                    }
                    catch (PersistenceException ex)
                    {
                        // TODO handle error
                    }
                    // FIXME: In both cases the received event is correct, but the UI is not updated.
                    // The adapter still references the object that was passed to the edit activity as serialized data
                    // So must give the adapter the object just deserialized/loaded here.
                    adapter.setEvent(currentEvent); // ***** notifyDataSetChanged() is called within this, but not updating the view !!!!!!!!
                    return;
                case RESULT_EVENT_UPDATE_FAILED:
                    // Nothing to do
                    return;
            }
        }
    }
    ...
}

适配器:

public class PagerAdapter extends FragmentStatePagerAdapter
{
    /** The event on display */
    private Event m_event;

    public PagerAdapter (Event event, FragmentManager fm)
    {
        super(fm);
        m_event = event;
    }

    public void setEvent (Event event)
    {
        m_event = event;
        notifyDataSetChanged(); // ****** Attempting to trigger update of displayed data, but the view does not update.
    }

    @Override
    public Fragment getItem (int position)
    {
        Fragment f;
        switch (position)
        {
            case 0:
                f = new DetailsFragment();
                break;
            ... other tab fragments
            default:
                return null;
        }
        // ******* FIXME?: The problem with passing serialized event to the fragment is that the fragment does not reference our event. 
        ... each fragment references a COPY of the event.
       // The updated event is passed back in the result... then set in the adapter.... BUT NOT IN FRAGMENTS 
       ... BUT FRAGMENTS GET CREATED HERE AS NECESSARY TO VIEW, AND WILL GET THE MODIFIED EVENT IN THIS ARGUMENTS BUNDLE:
       Bundle bundle = new Bundle();
       bundle.putSerializable(Event.EVENT_KEY, m_event);
       // Maybe just pass the event id in arguments, and the fragment gets the event from the database?? Sounds inefficient, and I think should not be necessary.
       //bundle.putLong(Event.EVENT_ID_KEY, m_event.getId());
       f.setArguments(bundle);
       return f;
    }
    ...
}

public class DetailsFragment extends Fragment
{
    /** Event to display */
    private Event m_event = null;

    ... UI TextView object declarations to show various attributes ...

    public DetailsFragment() {
        // Required empty public constructor
    }

    private void update ()
    {
        if (m_event == null)
        {
            ... set views empty ...
            return;
        }
        ... set views for attributes of m_event ...
    }

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

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate (R.layout.fragment_event_details, container, false);

        //initalize widgets ...

        // Get event for view
        Bundle args = getArguments();
        m_event = (Event)args.getSerializable(Event.EVENT_KEY); // ***** Get the event passed in arguments to this fragment
        update();
        return view;
    }
}

1 个答案:

答案 0 :(得分:1)

在您的 override

中尝试FragmentStatePagerAdapter方法
@Override
public int getItemPosition(@NonNull Object object) {
return POSITION_NONE;
}