我有这个奇怪的问题,我的列表片段被创建两次,一次当super.oncreate被调用父活动,一次当setContentView被调用在同一个父活动.这是一个简单的应用程序,我使用不同的布局为纵向和横向.
这是主要的活动:
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(); } } }
这里是layout-land文件夹中的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" />
这里是layout_articles在layout文件夹(为纵向)
<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" />
这里是两次头条碎片
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(); } }
这里是文章片段
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被加载,但是其中包含了fragment_container.
3)headlinesfragment被创建//到目前为止正常行为
4)将方向改为景观
5)主动性被破坏 – >标题碎片被摧毁
6)super.oncreate on mainactivity被称为
7)创建标题片段
8)setcontentview的主动性被称为
9)另一个headlinefragment被创建//问题
我已经放置了日志,可以在上面的代码中看到,这里是当我以纵向模式启动应用程序时的输出,我改为横向.
W/MainActivity(6925): Before super.onCreate: MainActivity@41d81238 W/MainActivity(6925): Before setContentView: MainActivity@41d81238 W/HeadlinesFragment(6925): inside onCreate: HeadlinesFragment{41d8d4d8 #0 id=0x7f050001} W/MainActivity(6925): inside onDestroy: MainActivity@41d81238 W/HeadlinesFragment(6925): inside onDestroy: HeadlinesFragment{41d8d4d8 # 0id=0x7f050001} W/MainActivity(6925): Before super.onCreate: MainActivity@41ea6258 W/HeadlinesFragment(6925): inside onCreate: HeadlinesFragment{41ea7290 #0 id=0x7f050001} W/MainActivity(6925): Before setContentView: MainActivity@41ea6258 W/HeadlinesFragment(6925): inside onCreate: HeadlinesFragment{41eb1f30 #1 id=0x7f050002} W/ArticleFragment(6925): inside onCreateView: ArticleFragment{41eb5f20 #2 id=0x7f050003}
我希望我已经清楚了我的代码和日志,在我看来,super.oncreate和setcontentview都创建了一个头条碎片;至少我想.
我的问题是为什么会创建2个头条碎片实例,以及如何避免这种情况.
非常感谢任何有关这方面的帮助
解决方法
在您的活动的onCreate中,您可以检查savedInstanceState包的状态.如果它不为空,则表示发生配置更改(在您的情况下,屏幕方向更改),并且您不需要重新创建片段.
你正在做的另一个错误是你试图用findFragmentById来检索你的片段.而不是传递Fragment id,而是给它附加到Fragment的View的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); } }