我知道之前已经提出这个问题,但到目前为止给出的答案都没有对我有任何帮助。
我有一个viewpager,它填充了FragmentStatePagerAdapter中的片段(android.support.v4.app.Fragment)。其中一些片段包含在方向更改时需要保留的逻辑,例如跟踪当前选择的视图。
但是,尽管我在onSaveInstanceState中保存了有问题的数据,但savedInstanceState始终为null。我可以通过将数据存储在静态变量中来解决这个问题(因为我只有每个片段的一个实例对我有用)但我发现这是一个非常难看的解决方案,必须有一个正确的方法来做到这一点。
这是在轮换中不保留它的状态之一:
public class PriceSelectFragment extends Fragment {
private TableRow mSelected;
private int mSelectedPos = 0;
// newInstance constructor for creating fragment with arguments
public static PriceSelectFragment newInstance() {
PriceSelectFragment fragmentFirst = new PriceSelectFragment();
return fragmentFirst;
}
public PriceSelectFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_price_select, container, false);
TableLayout mTable = (TableLayout)view.findViewById(R.id.price_table);
List<PriceGroup> mPriceGroups = ((MainActivity) getActivity()).getPriceGroups();
int i = 0;
for (final PriceGroup group : mPriceGroups) {
//Create row from layout and access child TextViews
TableRow r = (TableRow)inflater.inflate( R.layout.price_group, mTable, false);
TextView size = (TextView)r.getChildAt(0);
TextView dimension = (TextView)r.getChildAt(1);
TextView weight = (TextView)r.getChildAt(2);
TextView price = (TextView)r.getChildAt(3);
//Populate row with PriceGroup Data
size.setText(group.sizeIndicator);
dimension.setText(String.format("%2.0fx%2.0fx%2.0f", group.length, group.width, group.height));
weight.setText(Float.toString(group.weight));
price.setText(Integer.toString(group.price));
//Alternate background color every other row
if (i % 2 == 0) {
r.setBackgroundDrawable(getResources().getDrawable(R.drawable.price_selector_1));
}
else {
r.setBackgroundDrawable(getResources().getDrawable(R.drawable.price_selector_2));
}
mTable.addView(r); // Add to table
r.setTag(i);
r.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
selectRow((TableRow) v);
}
});
i++;
}
mSelected = (TableRow)view.findViewWithTag(mSelectedPos);
selectRow(mSelected);
return view;
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("selected", mSelectedPos);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null) {
mSelectedPos = savedInstanceState.getInt("selected");
}
}
private void selectRow(TableRow row) {
if ((int) mSelected.getTag() % 2 == 0) {
mSelected.setBackgroundDrawable(getResources().getDrawable(R.drawable.price_selector_1));
}
else {
mSelected.setBackgroundDrawable(getResources().getDrawable(R.drawable.price_selector_2));
}
mSelected = row;
mSelectedPos = (int) mSelected.getTag();
mSelected.setBackgroundColor(getResources().getColor(R.color.light_blue));
}
}
如何在不必将状态保存在静态变量中的情况下解决这个问题?
我应该指出所有的片段都是以编程方式创建的,因此它们没有id,我读到这可能是问题,但我也不知道如何解决这个问题。
此外,我的应用程序结构如下:
状态I遇到问题的片段是子片段。
答案 0 :(得分:1)
FragmentPagerAdapter不再在不再可见的frgments中调用onSaveInstanceState。也许这就是导致你的问题的原因。 请尝试使用FragmentStatePagerAdapter。
答案 1 :(得分:0)
我终于找到了解决方案并解释了为什么会这样。我有一个非常相似的问题。我认识到,当我向右滚动到第3个子碎片然后回到第1个时,第1个状态就被保存了。但不是取向取向。
我认为只有在调用适配器的destroyItem(..)时才会保存状态。如果方向发生变化,则不会自动调用。
现在,MainFragment的onSaveInstanceState(包含ViewPager)我为每个活动片段调用destroyItem。我检查activity.isChangingConfigurations(),因为如果关闭屏幕也会调用onSaveInstanceState,但在这种情况下,所有片段都保持活动状态,不需要更改任何内容。
我使用onDestroy(boolean retain)扩展了适配器,然后调用它:
//in the main-fragment which holds the ViewPager:
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if(getActivity()!=null && getActivity().isChangingConfigurations())
{
if (pager != null) {
try {
Log.w(TAG, TAG + " pager.onDestroy(true)");
pager.onDestroy(true);
} catch (Exception e) {
e.printStackTrace();
}
}
MyFragmentStatePagerAdapter中的实现:
public void onDestroy(boolean retain)
{
this.m_allowDynamicLoading = false;
if(retain)
{
try{
if(getAdapter()!=null)
{
int limit = this.getOffscreenPageLimit();
int currentIndex = this.getCurrentItem();
if(currentIndex <0 || getAdapter().getCount() <= 0)
return;
//active fragments = fragments that are (less or equal) then
//offscreenPageLimit awaw from the currently displayed one.
for(int i = Math.min(currentIndex+limit, getAdapter().getCount()-1);
i>= Math.max(0, currentIndex-limit);//erstes aktives fragment ist current - offscreen limit, aber nicht unter 0..
i--)
{
getAdapter().destroyItem(MessagingViewPager.this, i, getAdapter().instantiateItem(MessagingViewPager.this, i)); //this saved the state of that fragment, that will be restored after orientation change
Log.e(TAG,TAG + " orientation-change: destroying item " + i);
}
}
}catch(Exception e){}
}
else{ //retain = false is called onDestroy of the Fragment holding this Pager.
try{
this.setAdapter(null);
//this will destroy all fragments and forget the position
}catch(Exception e){}
}
}
还有其他一些事情要说:
etvoiá:现在,在方向更改后,您将在SubFragments中获取savedInstanceState包。如果你只关闭屏幕,它不会破坏物品。