ViewPager和片段—存储片段状态的正确方法是什么?

片段对于将UI逻辑分为一些模块来说似乎非常好。但是随着ViewPager它的生命周期,我仍然迷茫。因此,非常需要大师的想法!

编辑

请参阅下面的愚蠢解决方案;-)

回答:

主要活动有一个ViewPager带有片段。这些片段可以为其他(子主)活动实现一些不同的逻辑,因此片段的数据通过活动内部的回调接口填充。并且所有功能在首次启动时都正常,但是!

回答:

重新创建活动时(例如,在方向更改时),ViewPager的片段也是如此。代码(您将在下面找到)说,每次创建活动时,我都会尝试创建一个ViewPager与片段相同的新片段适配器(也许是问题所在),但是FragmentManager已经将所有这些片段存储在某个地方(哪里?),并且为这些人启动娱乐机制。因此,重新创建机制使用我的回调接口调用“旧”片段的onAttach,onCreateView等,以通过Activity的实现方法来初始化数据。但是此方法指向通过Activity的onCreate方法创建的新创建的片段。

回答:

也许我使用了错误的模式,但即使是Android 3 Pro书籍也没有太多相关信息。因此, 给我一两个拳,并指出正确的方法。非常感谢!

回答:

主要活动

public class DashboardActivity extends BasePagerActivity implements OnMessageListActionListener {

private MessagesFragment mMessagesFragment;

@Override

protected void onCreate(Bundle savedInstanceState) {

Logger.d("Dash onCreate");

super.onCreate(savedInstanceState);

setContentView(R.layout.viewpager_container);

new DefaultToolbar(this);

// create fragments to use

mMessagesFragment = new MessagesFragment();

mStreamsFragment = new StreamsFragment();

// set titles and fragments for view pager

Map<String, Fragment> screens = new LinkedHashMap<String, Fragment>();

screens.put(getApplicationContext().getString(R.string.dashboard_title_dumb), new DumbFragment());

screens.put(getApplicationContext().getString(R.string.dashboard_title_messages), mMessagesFragment);

// instantiate view pager via adapter

mPager = (ViewPager) findViewById(R.id.viewpager_pager);

mPagerAdapter = new BasePagerAdapter(screens, getSupportFragmentManager());

mPager.setAdapter(mPagerAdapter);

// set title indicator

TitlePageIndicator indicator = (TitlePageIndicator) findViewById(R.id.viewpager_titles);

indicator.setViewPager(mPager, 1);

}

/* set of fragments callback interface implementations */

@Override

public void onMessageInitialisation() {

Logger.d("Dash onMessageInitialisation");

if (mMessagesFragment != null)

mMessagesFragment.loadLastMessages();

}

@Override

public void onMessageSelected(Message selectedMessage) {

Intent intent = new Intent(this, StreamActivity.class);

intent.putExtra(Message.class.getName(), selectedMessage);

startActivity(intent);

}

BasePagerActivity aka助手

public class BasePagerActivity extends FragmentActivity {

BasePagerAdapter mPagerAdapter;

ViewPager mPager;

}

适配器

public class BasePagerAdapter extends FragmentPagerAdapter implements TitleProvider {

private Map<String, Fragment> mScreens;

public BasePagerAdapter(Map<String, Fragment> screenMap, FragmentManager fm) {

super(fm);

this.mScreens = screenMap;

}

@Override

public Fragment getItem(int position) {

return mScreens.values().toArray(new Fragment[mScreens.size()])[position];

}

@Override

public int getCount() {

return mScreens.size();

}

@Override

public String getTitle(int position) {

return mScreens.keySet().toArray(new String[mScreens.size()])[position];

}

// hack. we don't want to destroy our fragments and re-initiate them after

@Override

public void destroyItem(View container, int position, Object object) {

// TODO Auto-generated method stub

}

}

分段

public class MessagesFragment extends ListFragment {

private boolean mIsLastMessages;

private List<Message> mMessagesList;

private MessageArrayAdapter mAdapter;

private LoadMessagesTask mLoadMessagesTask;

private OnMessageListActionListener mListener;

// define callback interface

public interface OnMessageListActionListener {

public void onMessageInitialisation();

public void onMessageSelected(Message selectedMessage);

}

@Override

public void onAttach(Activity activity) {

super.onAttach(activity);

// setting callback

mListener = (OnMessageListActionListener) activity;

mIsLastMessages = activity instanceof DashboardActivity;

}

@Override

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

inflater.inflate(R.layout.fragment_listview, container);

mProgressView = inflater.inflate(R.layout.listrow_progress, null);

mEmptyView = inflater.inflate(R.layout.fragment_nodata, null);

return super.onCreateView(inflater, container, savedInstanceState);

}

@Override

public void onActivityCreated(Bundle savedInstanceState) {

super.onActivityCreated(savedInstanceState);

// instantiate loading task

mLoadMessagesTask = new LoadMessagesTask();

// instantiate list of messages

mMessagesList = new ArrayList<Message>();

mAdapter = new MessageArrayAdapter(getActivity(), mMessagesList);

setListAdapter(mAdapter);

}

@Override

public void onResume() {

mListener.onMessageInitialisation();

super.onResume();

}

public void onListItemClick(ListView l, View v, int position, long id) {

Message selectedMessage = (Message) getListAdapter().getItem(position);

mListener.onMessageSelected(selectedMessage);

super.onListItemClick(l, v, position, id);

}

/* public methods to load messages from host acitivity, etc... */

}

回答:

愚蠢的解决方案是使用putFragment将片段保存在(主机Activity的)onSaveInstanceState内部,并通过getFragment将其保存在onCreate中。但是我仍然有一种奇怪的感觉,就是事情不应该那样工作……请参见下面的代码:

    @Override

protected void onSaveInstanceState(Bundle outState) {

super.onSaveInstanceState(outState);

getSupportFragmentManager()

.putFragment(outState, MessagesFragment.class.getName(), mMessagesFragment);

}

protected void onCreate(Bundle savedInstanceState) {

Logger.d("Dash onCreate");

super.onCreate(savedInstanceState);

...

// create fragments to use

if (savedInstanceState != null) {

mMessagesFragment = (MessagesFragment) getSupportFragmentManager().getFragment(

savedInstanceState, MessagesFragment.class.getName());

StreamsFragment.class.getName());

}

if (mMessagesFragment == null)

mMessagesFragment = new MessagesFragment();

...

}

回答:

FragmentPagerAdapter增加一个片段到FragmentManager,它使用基于特定位置,该片段将被置于一个特殊的标记。FragmentPagerAdapter.getItem(int

position)仅在该位置的片段不存在时才调用。旋转后,Android将注意到它已经为该特定位置创建/保存了一个片段,因此它仅尝试使用进行重新连接FragmentManager.findFragmentByTag(),而不是创建一个新片段。使用时,所有这些都是免费的,这FragmentPagerAdapter就是为什么通常在方法中包含片段初始化代码的原因getItem(int)

即使我们不使用a

FragmentPagerAdapter,也不是每次在中创建一个新片段都是一个好主意Activity.onCreate(Bundle)。如您所知,将片段添加到FragmentManager时,将在旋转后为您重新创建它,而无需再次添加。这样做是处理片段时出错的常见原因。

使用片段的常用方法是:

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

...

CustomFragment fragment;

if (savedInstanceState != null) {

fragment = (CustomFragment) getSupportFragmentManager().findFragmentByTag("customtag");

} else {

fragment = new CustomFragment();

getSupportFragmentManager().beginTransaction().add(R.id.container, fragment, "customtag").commit();

}

...

}

当使用时FragmentPagerAdapter,我们将片段管理交给适配器,而不必执行上述步骤。默认情况下,它只会在当前位置的前后预先加载一个Fragment(尽管除非使用,否则它不会销毁它们FragmentStatePagerAdapter)。这由ViewPager.setOffscreenPageLimit(int)控制。因此,不能保证在适配器外部的片段上直接调用方法是有效的,因为它们甚至可能没有生命。

长话短说,您使用的解决方案putFragment可以随后获得参考,这并不是那么疯狂,也与普通使用片段的方式不同(上图)。否则很难获得参考,因为该片段是由适配器而不是您本人添加的。只要确保它offscreenPageLimit足够高,就可以始终加载所需的片段,因为您依赖于它的存在。这绕过了ViewPager的延迟加载功能,但似乎正是您对应用程序所期望的。

另一种方法是FragmentPageAdapter.instantiateItem(View,

int)在返回之前,重写并保存对从超级调用返回的片段的引用(它具有找到该片段(如果已经存在)的逻辑)。

要获得更完整的图片,请查看FragmentPagerAdapter(短)和ViewPager(长)的某些来源。

以上是 ViewPager和片段—存储片段状态的正确方法是什么? 的全部内容, 来源链接: utcz.com/qa/401368.html

回到顶部