2013-04-28 50 views
10

我有这个奇怪的问题,其中我的列表片段创建了两次,一次是在父活动上调用super.oncreate并且一次在同一父活动上调用setContentView时。这是一个简单的应用程序,我使用不同的肖像和横向布局。在定位更改上创建了两次android片段

这里是主要的活动:

private HeadlinesFragment headlines; 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    Log.w("MainActivity", "Before super.onCreate: " + this.toString()); 
    super.onCreate(savedInstanceState); 
    Log.w("MainActivity", "Before setContentView: " + this.toString()); 
    setContentView(R.layout.news_articles); 

    //check to see if its portrait 
    if (findViewById(R.id.fragment_container) != null) { 
     if(getSupportFragmentManager().findFragmentById(R.id.fragment_container) == null) { 
      headlines = new HeadlinesFragment(); 
      getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, headlines).commit(); 
     } 
    } 
} 

这里是在布局,土地文件夹中的news_articles:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:orientation="horizontal" 
android:layout_width="match_parent" 
android:layout_height="match_parent"> 

<fragment android:name="com.example.android.fragments.HeadlinesFragment" 
      android:id="@+id/headlines_fragment" 
      android:layout_weight="1" 
      android:layout_width="0dp" 
      android:layout_height="match_parent" /> 

<fragment android:name="com.example.android.fragments.ArticleFragment" 
      android:id="@+id/article_fragment" 
      android:layout_weight="2" 
      android:layout_width="0dp" 
      android:layout_height="match_parent" /> 

这里是在布局文件夹中的news_articles(对于纵向)

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:id="@+id/fragment_container" 
android:layout_width="match_parent" 
android:layout_height="match_parent" /> 

这里是headlinesfragment这就是被创建两次

public class HeadlinesFragment extends ListFragment { 
OnHeadlineSelectedListener mCallback; 

// The container Activity must implement this interface so the frag can deliver messages 
public interface OnHeadlineSelectedListener { 
    /** Called by HeadlinesFragment when a list item is selected */ 
    public void onArticleSelected(int position); 
} 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    Log.w("HeadlinesFragment", "inside onCreate: " + this.toString()); 

    // We need to use a different list item layout for devices older than Honeycomb 
    int layout = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? 
      android.R.layout.simple_list_item_activated_1 : android.R.layout.simple_list_item_1; 

    // Create an array adapter for the list view, using the Ipsum headlines array 
    setListAdapter(new ArrayAdapter<String>(getActivity(), layout, Ipsum.Headlines)); 
} 

@Override 
public void onStart() { 
    super.onStart(); 

    // When in landscape layout, set the listview to highlight the selected list item 
    // (We do this during onStart because at the point the listview is available.) 
    if (getFragmentManager().findFragmentById(R.id.article_fragment) != null) { 
     getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE); 
    } 
} 

@Override 
public void onAttach(Activity activity) { 
    super.onAttach(activity); 

    // This makes sure that the container activity has implemented 
    // the callback interface. If not, it throws an exception. 
    try { 
     mCallback = (OnHeadlineSelectedListener) activity; 
    } catch (ClassCastException e) { 
     throw new ClassCastException(activity.toString() 
       + " must implement OnHeadlineSelectedListener"); 
    } 
} 


@Override 
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 
    // TODO Auto-generated method stub 
    super.onCreateOptionsMenu(menu, inflater); 
} 

@Override 
public void onDestroy() { 
    Log.w("HeadlinesFragment", "inside onDestroy: " + this.toString()); 
    super.onDestroy(); 
} 
} 

这里是articlefragment

public class ArticleFragment extends Fragment { 
final static String ARG_POSITION = "position"; 
int mCurrentPosition = 0; 

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, 
    Bundle savedInstanceState) { 
    Log.w("ArticleFragment", "inside onCreateView: " + this.toString()); 

    if (savedInstanceState != null) { 
     mCurrentPosition = savedInstanceState.getInt(ARG_POSITION); 
    } 

    // Inflate the layout for this fragment 
    View view = inflater.inflate(R.layout.article_view, container, false); 
    return view; 
} 

@Override 
public void onStart() { 
    super.onStart(); 
    Bundle args = getArguments(); 
    if (args != null) { 
     // Set article based on argument passed in 
     updateArticleView(args.getInt(ARG_POSITION)); 
    } else if (mCurrentPosition != -1) { 
     // Set article based on saved instance state defined during onCreateView 
     updateArticleView(mCurrentPosition); 
    } 
} 

@Override 
public void onSaveInstanceState(Bundle outState) { 
    super.onSaveInstanceState(outState); 

    // Save the current article selection in case we need to recreate the fragment 
    outState.putInt(ARG_POSITION, mCurrentPosition); 
} 

@Override 
public void onDestroy() { 
    Log.w("ArticleFragment", "inside onDestroy: " + this.toString()); 
    super.onDestroy(); 
} 

}

详细问题是这样的:

1)启动应用程序纵向方向 2)调用setContentView并加载news_articles,但它带有frag的一个ment_container。 3)headlinesfragment创建//到目前为止正常行为 4)改变方向为横向 5)mainActivity被破坏 - > headlinefragment被破坏 6)上mainactivity super.oncreate称为 7)Headlinefragment创建 8)的setContentView在主要活动被称为 9)另一个标题片段被创建//问题

我已经放置日志,可以在上面的代码中看到,这里是当我在纵向模式中启动应用程序,我改变为风景的输出。

W/MainActivity(6925): Before super.onCreate: [email protected] 
W/MainActivity(6925): Before setContentView: [email protected] 
W/HeadlinesFragment(6925): inside onCreate: HeadlinesFragment{41d8d4d8 #0 id=0x7f050001} 
W/MainActivity(6925): inside onDestroy: [email protected] 
W/HeadlinesFragment(6925): inside onDestroy: HeadlinesFragment{41d8d4d8 # 0id=0x7f050001} 
W/MainActivity(6925): Before super.onCreate: [email protected] 
W/HeadlinesFragment(6925): inside onCreate: HeadlinesFragment{41ea7290 #0 id=0x7f050001} 
W/MainActivity(6925): Before setContentView: [email protected] 
W/HeadlinesFragment(6925): inside onCreate: HeadlinesFragment{41eb1f30 #1 id=0x7f050002} 
W/ArticleFragment(6925): inside onCreateView: ArticleFragment{41eb5f20 #2 id=0x7f050003} 

我希望我已经与我的代码和日志清楚,在我看来super.oncreate和的setContentView都创建一个每一个headlinesfragment;至少我想。

我的问题是为什么会创建2个headlinesfragment实例,以及我如何避免这种情况。

,了解关于此次

回答

15

在你活动的onCreate任何帮助非常感谢,您可以检查savedInstanceState捆绑的状态。如果它不为空,则表示发生了配置更改(在您的情况下,屏幕方向更改),并且您不需要重新创建Fragment

您正在做的另一个错误是您试图检索FragmentfindFragmentById。不是传递片段ID,而是给予它附加到片段的视图的ID,这是不同的(这就是我猜测这总是返回null的原因)。

正确实现的会更喜欢这个(这是你的Activity):

//check to see if its portrait 
    if (findViewById(R.id.fragment_container) != null) { 
     if(savedInstanceState == null) { 
      headlines = new HeadlinesFragment(); 
      getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, headlines, FRAGMENT_TAG_STRING).commit(); // Use tags, it's simpler to deal with 
     } else { 
      headlines = getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG_STRING); 
     } 
    } 
+0

感谢您的回应,但是问题在于应用程序转向横向时,您所提供的代码仍然无法执行。另外关于你给出的代码,当应用程序第一次以纵向模式启动时,savedInstanceState为null,else块被执行,所以如果我们从来没有创建它,我们如何通过标记找到HeadlinesFragment? – 2013-05-12 16:03:50

+3

我认为如果陈述条件是倒退在这里。如果存在已保存的实例状态,则应找到现有片段。如果保存的实例状态为空,则应该创建一个新的片段。 – Razz 2015-04-09 15:24:40

+0

@Razz是正确的。注意:如果savedInstanceState IS为null,那么您创建一个新的片段,否则片段已经存在!所以,只要将内部if语句更改为if(savedInstanceState == null) – 2015-11-08 00:07:52

2

覆盖onSavedInstanceState不调用它的超级。

+3

您是否可以扩展您的答案,解释您的推理,并且在这种情况下也没有调用super的缺陷。 – CurlyPaul 2014-05-22 10:18:18

+0

天才,我唯一的工作解决方案。 :) – Galya 2017-04-06 15:28:45