Android Fragment getArguments() returns null - android

As the title suggest.
I've downloaded Fragment code from here, http://developer.android.com/shareables/training/FragmentBasics.zip.
It is Fragment example from Android Official Developer site. http://developer.android.com/training/basics/fragments/fragment-ui.html
This is the MainActivity.java's onCreate():
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.news_articles);
// Check whether the activity is using the layout version with
// the fragment_container FrameLayout. If so, we must add the first fragment
if (findViewById(R.id.fragment_container) != null) {
// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
if (savedInstanceState != null) {
return;
}
// Create an instance of ExampleFragment
HeadlinesFragment fragment = new HeadlinesFragment();
// In case this activity was started with special instructions from an Intent,
// pass the Intent's extras to the fragment as arguments
//fragment.setArguments(getIntent().getExtras());
Bundle args= new Bundle();
args.putString("category", "clothes");
args.putString("item", "shirts");
fragment.setArguments(args);
// Add the fragment to the 'fragment_container' FrameLayout
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, fragment).commit();
}
}
And HeadlinesFragment.java's onCreate():
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 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;
Bundle args = getArguments();
if (args == null) {
Toast.makeText(getActivity(), "arguments is null " , Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getActivity(), "text " + args , Toast.LENGTH_LONG).show();
}
// Create an array adapter for the list view, using the Ipsum headlines array
setListAdapter(new ArrayAdapter<String>(getActivity(), layout, Ipsum.Headlines));
}
I've read several QA here, like this one Fragment getArguments() returns null, and many other that related to setArguments() and getArguments(), but still I'm stuck.
And I've moved the Bundle and Toast code to onAttach() and to onCreateView() with no avail. What wrong with the my code? I think I'm missing something, but dunno what is it.
Please Help! Thanks.
Edit:
I'll state my intention more clearly. In FragmentBasic that I downloaded, there's MainActivity.java, HeadlinesFragment.java, and ArticlesFragment.java. The 'communication' from MainActivity.java to ArticlesFragment.java is not the problem here. What I want is to send data from MainActivity.java to HeadlinesFragment.java. Their connection's like this:
--------------------------------------
| MainActivity <-> HeadlinesFragment |
| | |
| |>> ArticlesFragment |
--------------------------------------
And HeadlinesFragment is running at Runtime.
*These code works, when using Android gadget with < 600px width. But doesn't work when using on tablet ( >= 600px), As proved by #Tesla1984 below. But what I want is same result either on gadget < 600px and on gadget > 600px.

#tonny
I've download the FragmentBasics.zip. I only change the argument name. Here is the code and result pic.
MainActivity
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.news_articles);
// Check whether the activity is using the layout version with
// the fragment_container FrameLayout. If so, we must add the first fragment
if (findViewById(R.id.fragment_container) != null) {
// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
if (savedInstanceState != null) {
return;
}
// Create an instance of ExampleFragment
HeadlinesFragment fragment = new HeadlinesFragment();
// In case this activity was started with special instructions from an Intent,
// pass the Intent's extras to the fragment as arguments
// firstFragment.setArguments(getIntent().getExtras());
//test
Bundle args= new Bundle();
args.putString("category", "clothes");
args.putString("item", "shirts");
fragment.setArguments(args);
// Add the fragment to the 'fragment_container' FrameLayout
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, fragment).commit();
}
}
HeadlinesFragment
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 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;
Bundle args = getArguments();
if (args == null) {
Toast.makeText(getActivity(), "arguments is null " , Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getActivity(), "text " + args , Toast.LENGTH_LONG).show();
}
// Create an array adapter for the list view, using the Ipsum headlines array
setListAdapter(new ArrayAdapter<String>(getActivity(), layout, Ipsum.Headlines));
}
here is the result

I had the same problem, but solved it :)
My problem was that I had the <fragment android:name=""> element in the Activity's XML layout. Therefore the onCreate() of the Fragment was called before the calls in Java code, thus not setting the arguments.
I removed the <fragment> element from my XML layout and it worked!

I've solved it. Looks like the only way to send data from MainActivity.java to HeadlinesFragment.java is from callbacks (If anybody else know other ways, please contribute, then we have some other ways beside this one, helping others with this kind of problem).
The main code from is MainActivity.java's function public Bundle getBundle() {}, then set the interface section on HeadlinesFragment.java, and add public Bundle getBundle();, and last, call it from HeadlinesFragment.java's onCreate.
What confuse me is fragment.setArguments(getIntent().getExtras()); on MainActivity.java's onCreate. They put that code there, and I believing it will works cause it's from Android Official Developer Guide and API http://developer.android.com/training/basics/fragments/fragment-ui.html, but it didn't work (now I believe that piece of code won't do anything). So, anyone who read the tutorial or sample from there, take it with a grain of salt!
Codes below, so everyone can understand it.
MainActivity.java:
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.fragments;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTransaction;
import android.widget.Toast;
public class MainActivity extends FragmentActivity
implements HeadlinesFragment.OnHeadlineSelectedListener {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.news_articles);
// Check whether the activity is using the layout version with
// the fragment_container FrameLayout. If so, we must add the first fragment
if (findViewById(R.id.fragment_container) != null) {
// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
if (savedInstanceState != null) {
return;
}
Toast.makeText(getApplicationContext(), "activity", Toast.LENGTH_LONG).show();
// Create an instance of ExampleFragment
HeadlinesFragment fragment = new HeadlinesFragment();
// In case this activity was started with special instructions from an Intent,
// pass the Intent's extras to the fragment as arguments
fragment.setArguments(getIntent().getExtras());
// Add the fragment to the 'fragment_container' FrameLayout
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, fragment).commit();
}
}
public void onArticleSelected(int position) {
// The user selected the headline of an article from the HeadlinesFragment
// Capture the article fragment from the activity layout
ArticleFragment articleFrag = (ArticleFragment)
getSupportFragmentManager().findFragmentById(R.id.article_fragment);
if (articleFrag != null) {
// If article frag is available, we're in two-pane layout...
// Call a method in the ArticleFragment to update its content
articleFrag.updateArticleView(position);
} else {
// If the frag is not available, we're in the one-pane layout and must swap frags...
// Create fragment and give it an argument for the selected article
ArticleFragment newFragment = new ArticleFragment();
Bundle args = new Bundle();
args.putInt(ArticleFragment.ARG_POSITION, position);
newFragment.setArguments(args);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack so the user can navigate back
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
}
}
public Bundle getBundle() {
Bundle args = new Bundle();
args.putString("category", "cloths");
args.putString("item", "shirts");
return args;
}
}
HeadlinesFragment.java:
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.fragments;
import android.app.Activity;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
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);
public Bundle getBundle();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = mCallback.getBundle();
Toast.makeText(getActivity(), "headline fragment " + bundle, Toast.LENGTH_LONG).show();
// 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 View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
return super.onCreateView(inflater, container, savedInstanceState);
}
#Override
public void onStart() {
super.onStart();
// When in two-pane 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 onListItemClick(ListView l, View v, int position, long id) {
// Notify the parent activity of selected item
mCallback.onArticleSelected(position);
// Set the item as checked to be highlighted when in two-pane layout
getListView().setItemChecked(position, true);
}
}

It looks like you are inserting a key and value pair into your bundle. You probably need to reference the key value as in getArguments().getString(category);
According to the docs for putString: Inserts a String value into the mapping of this Bundle, replacing any existing value for the given key. Either key or value may be null.
Parameters
key a String, or null
value a String, or null

Related

How to putExtra in FragmentTransaction Android SDK 21

I have converted my app from activity views to fragment, but I don't know how to pass the extra info to my new fragment. Here I create a new fragment from another fragment.
This was the old working code
Launch a new Activity to display the selected sensor
Intent intent = new Intent(getActivity(), SensorViewFragment.class);
// Push the sensor index to the new Activity
intent.putExtra(SensorViewFragment.SENSOR_INDEX_EXTRA, position);
// Start the activity
startActivity(intent);*/
And this is the new code in which I don't know how to putExtra
// Set a listener to respond to list item clicks
sensorListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// Create new fragment and transaction
Fragment newFragment = new SensorViewFragment();
// consider using Java coding conventions (upper first char class names!!!)
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
}
});
The recommended solution is to use an arguments Bundle. That way the data, as with your old extras, is automatically retained on a configuration change, in the recent-tasks list, etc.
Google's typical approach is to use a factory method (newInstance()) on the fragment class to handle packaging data into the arguments Bundle.
For example, in this sample app, I am creating fragments for a ViewPager. I want to pass the position (page number) into the fragments, so the fragments can use that in the UI.
On my fragment class (EditorFragment), I have a newInstance() factory method that puts the supplied position into the arguments Bundle, and I use the value in my onCreateView() method via getArguments():
/***
Copyright (c) 2012-14 CommonsWare, LLC
Licensed under the Apache License, Version 2.0 (the "License"); you may not
use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless required
by applicable law or agreed to in writing, software distributed under the
License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
OF ANY KIND, either express or implied. See the License for the specific
language governing permissions and limitations under the License.
From _The Busy Coder's Guide to Android Development_
http://commonsware.com/Android
*/
package com.commonsware.android.pager;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
public class EditorFragment extends Fragment {
private static final String KEY_POSITION="position";
static EditorFragment newInstance(int position) {
EditorFragment frag=new EditorFragment();
Bundle args=new Bundle();
args.putInt(KEY_POSITION, position);
frag.setArguments(args);
return(frag);
}
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
View result=inflater.inflate(R.layout.editor, container, false);
EditText editor=(EditText)result.findViewById(R.id.editor);
int position=getArguments().getInt(KEY_POSITION, -1);
editor.setHint(String.format(getString(R.string.hint), position + 1));
return(result);
}
}
When I want to create an instance of the fragment, I just use the factory method (EditorFragment.newInstance(position)).

Android fragments using v7 appCompat library

I downloaded the fragmentbasics.zip from the Android Training site. At the bottom of the page (from provided link) there is a section stating "If you're using the v7 appcompat library, your activity should instead extend ActionBarActivity, which is a subclass of FragmentActivity". I am using the android-support-v7-appcompat.jar in my project.
I did as the tutorial page says and updated 'MainActivity.java' to extend ActionBarActivity instead of FragmentActivity, I am now getting the below errors...
The hierarchy of the type MainActivity is inconsistent
The type android.support.v4.app.TaskStackBuilder$SupportParentable cannot be resolved. It is indirectly referenced from required .class files
MainActivity.java
public class MainActivity extends ActionBarActivity
implements HeadlinesFragment.OnHeadlineSelectedListener {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.news_articles);
// Check whether the activity is using the layout version with
// the fragment_container FrameLayout. If so, we must add the first fragment
if (findViewById(R.id.fragment_container) != null) {
// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
if (savedInstanceState != null) {
return;
}
// Create an instance of ExampleFragment
HeadlinesFragment firstFragment = new HeadlinesFragment();
// In case this activity was started with special instructions from an Intent,
// pass the Intent's extras to the fragment as arguments
firstFragment.setArguments(getIntent().getExtras());
// Add the fragment to the 'fragment_container' FrameLayout
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, firstFragment).commit();
}
}
public void onArticleSelected(int position) {
// The user selected the headline of an article from the HeadlinesFragment
// Capture the article fragment from the activity layout
ArticleFragment articleFrag = (ArticleFragment)
getSupportFragmentManager().findFragmentById(R.id.article_fragment);
if (articleFrag != null) {
// If article frag is available, we're in two-pane layout...
// Call a method in the ArticleFragment to update its content
articleFrag.updateArticleView(position);
} else {
// If the frag is not available, we're in the one-pane layout and must swap frags...
// Create fragment and give it an argument for the selected article
ArticleFragment newFragment = new ArticleFragment();
Bundle args = new Bundle();
args.putInt(ArticleFragment.ARG_POSITION, position);
newFragment.setArguments(args);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack so the user can navigate back
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
}
}
}
Based on the tutorial I guess I am doing things correctly, any ideas why I would be getting these errors?
Steps to reproduce:
download the sample from provided link (top of post)
right click project -> build path -> add external arhchives
find your v7 appCompat support jar and click open
observe errors
Try to update the android.support.v4

Get data result from second Fragment

In my MainActivity extends FragmentActivity, I have a FragmentA, When I press a Button in FragmentA, I call to FragmentB.
FragmentB f = FragmentB.newInstance(1);
getSupportFragmentManager().beginTransaction().replace(R.id.llMain, f).addToBackStack(null).commit();
In FragmentB, I create a Object People p1(with Name and age) . And When I press a Button B in FragmentB, I call
getFragmentManager().popBackStack();
It will return FragmentA,
So, I want to pass data Object People p1 from FragmentB to FragmentA. What do i have to do?
I try to search but can't find a solution.
create CallBack in your Fragment and handle it in FragmentActivity,
google example has this realization
declaring OnHeadlineSelectedListener callback
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);
// 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 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 onListItemClick(ListView l, View v, int position, long id) {
// Notify the parent activity of selected item
mCallback.onArticleSelected(position);
// Set the item as checked to be highlighted when in two-pane layout
getListView().setItemChecked(position, true);
}
Realize callback method in FragmentActivity and send (by .setArguments()) data from HeadLinesFragment to ArticleFragment, if ArticleFragment is available
public class MainActivity extends FragmentActivity
implements HeadlinesFragment.OnHeadlineSelectedListener {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.news_articles);
// Check whether the activity is using the layout version with
// the fragment_container FrameLayout. If so, we must add the first fragment
if (findViewById(R.id.fragment_container) != null) {
// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
if (savedInstanceState != null) {
return;
}
// Create an instance of ExampleFragment
HeadlinesFragment firstFragment = new HeadlinesFragment();
// In case this activity was started with special instructions from an Intent,
// pass the Intent's extras to the fragment as arguments
firstFragment.setArguments(getIntent().getExtras());
// Add the fragment to the 'fragment_container' FrameLayout
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, firstFragment).commit();
}
}
public void onArticleSelected(int position) {
// The user selected the headline of an article from the HeadlinesFragment
// Capture the article fragment from the activity layout
ArticleFragment articleFrag = (ArticleFragment)
getSupportFragmentManager().findFragmentById(R.id.article_fragment);
if (articleFrag != null) {
// If article frag is available, we're in two-pane layout...
// Call a method in the ArticleFragment to update its content
articleFrag.updateArticleView(position);
} else {
// If the frag is not available, we're in the one-pane layout and must swap frags...
// Create fragment and give it an argument for the selected article
ArticleFragment newFragment = new ArticleFragment();
Bundle args = new Bundle();
args.putInt(ArticleFragment.ARG_POSITION, position);
newFragment.setArguments(args);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack so the user can navigate back
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
}
}
You should use an interface within Activity for communication between fragments. Check this android training lesson.
All Fragment-to-Fragment communication is done through the associated
Activity. Two Fragments should never communicate directly.
You can pass arguments to a Fragment with Bundle. Change your code to:
FragmentB f = FragmentB.newInstance(1);
Bundle args = new Bundle();
args.putString("NAME", name);
args.putInt("AGE", age);
f.setArguments(args);
getSupportFragmentManager().beginTransaction().replace(R.id.llMain, f).addToBackStack(null).commit();
and then retrieve the arguments for example in FragmentA's onCreateView with:
int age = getArguments().getInt("AGE");
//or with a second parameter as the default value
int age = getArguments().getInt("AGE", 0);
If you want to pass the whole People object to the Bundle, you need to make the class serializable. I think it's easier to pass the variables and then recreate the object.

Real approach for Avoiding Re-creation of Fragment after Screen Rotate (Official Fragment Developer Guide as example)

i'm finding a Real approach for Avoiding Re-creation of Fragment after Screen Rotate
if (container == null) { return null; } is not really avoiding the Fragment to be re-created at all. (illustrated below)
Where is the Official Fragment Developer Guide?
The official guide we are concerning is at http://developer.android.com/guide/components/fragments.html. The partial example code is at the bottom of the guide. As far as i know, the full sample code is available in the "Samples for SDK" under Android 3.0 (API 11). Also, i have done minimal modification to the sample code for it to run in API 10- and added some debug messages, which is included at the bottom of this question.
Where is R.id.a_item?
You may find in the Developer Guide Example the follow code stub:
if (index == 0) {
ft.replace(R.id.details, details);
} else {
ft.replace(R.id.a_item, details);
}
i did some searches on the Internet and find some others are also concerning where is the R.id.a_item. After inspecting the sample in API 11, i am quite sure it is just a meaningless typo. There are no such lines in the sample at all.
Real approach for avoiding re-creation of Fragment after screen rotate?
There are many existing discussions over the web. But it seems that there is not a "real" solution yet.
I have added lots of debug messages into the code below to keep track of the lifecycle of the DetailsFragment class. Try to (1) initiate the program in portrait mode, then (2) turn the device into landscape mode, then (3) turn it back to portrait, (4) to landscape again, (5) back to portrait again, and finally (6) quit it. We will have the following debug messages:
(1) Initiate in portrait mode
TitlesFragment.onCreate() Bundle=null
Only TitlesFragment is created. DetailsFragment is not shown yet.
(2) Turn into landscape mode
TitlesFragment.onCreate() Bundle=Bundle[{shownChoice=-1, android:view_state=android.util.SparseArray#4051d3a8, curChoice=0}]
DetailsFragment.onAttach() Activity=com.example.android.apis.app.FragmentLayout#4051d640
DetailsFragment.onCreate() Bundle=null
DetailsFragment.onCreateView() Activity=android.widget.FrameLayout#4050df68
DetailsFragment.onActivityCreated() Bundle=null
DetailsFragment.onStart()
DetailsFragment.onResume()
First, TitlesFragment is re-created (with the savedInstanceState Bundle). Then DetailsFragment is created dynamically (by TitlesFragment.onActivityCreated(), calling showDetails(), using FragmentTransaction).
(3) Back to portrait mode
DetailsFragment.onPause()
DetailsFragment.onStop()
DetailsFragment.onDestroyView()
DetailsFragment.onDestroy()
DetailsFragment.onDetach()
DetailsFragment.onAttach() Activity=com.example.android.apis.app.FragmentLayout#40527f70
DetailsFragment.onCreate() Bundle=null
TitlesFragment.onCreate() Bundle=Bundle[{shownChoice=0, android:view_state=android.util.SparseArray#405144b0, curChoice=0}]
DetailsFragment.onCreateView() Activity=null
DetailsFragment.onActivityCreated() Bundle=null
DetailsFragment.onStart()
DetailsFragment.onResume()
Here is the first place that we are concerning about the real re-creation avoiding approach.
It is because the DetailsFragment was previously attached to the layout-land/fragment_layout.xml <FrameLayout> ViewGroup in landscape mode. And it is having an ID (R.id.details). When the screen rotates, the ViewGroup, which is an instance of the DetailsFragment, is saved into the Activity FragmentLayout's Bundle, in the FragmentLayout's onSaveInstanceState(). After entering portrait mode, the DetailsFragment is re-created. But it is not needed in portrait mode.
In the sample (and so as many others suggested), the DetailsFragment class uses if (container == null) { return null; } in onCreateView() to avoid the DetailsFragment showing up in portrait mode. However, as shown in the above debug messages, the DetailsFragment is still alive in the background, as an orphan, having all the lifecycle method calls.
(4) To landscape mode again
DetailsFragment.onPause()
DetailsFragment.onStop()
DetailsFragment.onDestroyView()
DetailsFragment.onDestroy()
DetailsFragment.onDetach()
DetailsFragment.onAttach() Activity=com.example.android.apis.app.FragmentLayout#4052c7d8
DetailsFragment.onCreate() Bundle=null
TitlesFragment.onCreate() Bundle=Bundle[{shownChoice=0, android:view_state=android.util.SparseArray#40521b80, curChoice=0}]
DetailsFragment.onCreateView() Activity=android.widget.FrameLayout#40525270
DetailsFragment.onActivityCreated() Bundle=null
DetailsFragment.onStart()
DetailsFragment.onResume()
Notice in the first 5 lines, the DetailsFragment completes its lifecycle states then destroy and detached.
This further proves the if (container == null) { return null; } method is not a real approach to get rid of the DetailsFragment instance. (i thought the Garbage Collector would destroy this dangling child but it didn't. It's because Android does allow a dangling Fragment. Ref: Adding a fragment without a UI.)
As far as i understand, starting from the 6th line, it should be a new DetailsFragment instance creating by the TitlesFragment, as it did in (2). But i cannot explain why the DetailsFragment's onAttach() and onCreate() methods are called before the TitlesFragment's onCreate().
But the null Bundle in DetailsFragment's onCreate() would prove it is a new instance.
To my understanding, the previous dangling DetailsFragment instance is not re-creating this time because it does not have an ID. So it did not auto-save with the view hierarchy into the savedInstanceState Bundle.
(5) Back to portrait mode again
DetailsFragment.onPause()
DetailsFragment.onStop()
DetailsFragment.onDestroyView()
DetailsFragment.onDestroy()
DetailsFragment.onDetach()
DetailsFragment.onAttach() Activity=com.example.android.apis.app.FragmentLayout#4052d7d8
DetailsFragment.onCreate() Bundle=null
TitlesFragment.onCreate() Bundle=Bundle[{shownChoice=0, android:view_state=android.util.SparseArray#40534e30, curChoice=0}]
DetailsFragment.onCreateView() Activity=null
DetailsFragment.onActivityCreated() Bundle=null
DetailsFragment.onStart()
DetailsFragment.onResume()
Notice here that all the lifecycle callbacks are identical to the first time back to portrait in (3), except with the different Activity ID (40527f70 vs 4052d7d8) and view_state Bundle (405144b0 vs 40534e30). This is reasonable. Both the FragmentLayout Activity and the Instance State Bundle are re-created.
(6) Quit (by BACK button)
I/System.out(29845): DetailsFragment.onPause()
I/System.out(29845): DetailsFragment.onStop()
I/System.out(29845): DetailsFragment.onDestroyView()
I/System.out(29845): DetailsFragment.onDestroy()
I/System.out(29845): DetailsFragment.onDetach()
It would be perfect if we can remove the DetailsFragment in FragmentLayout's onDestroy(). But the FragmentTransaction's remove() method needs to be called before the onSaveInstanceState(). However there is no way to determine if it is a screen rotate or not in onSaveInstanceState().
It is also not possible to remove the DetailsFragment in FragmentLayout's onSaveInstanceState() anyway. First, if the DetailsFragment is just partially obscured by a dialogue box, it will be disappeared in the background. In addition, in cases of obscured by dialogue box, or switching activities, neither onCreate(Bundle) nor onRestoreInstanceState(Bundle) will be called again. Thus we have no where to restore the Fragment (and retrieve data from Bundle).
Source codes & files
FragmentLayout.java
package com.example.android.apis.app;
import android.app.Activity;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.ListFragment;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.ScrollView;
import android.widget.TextView;
public class FragmentLayout extends FragmentActivity {
private final static class Shakespeare {
public static final String[] TITLES = { "Love", "Hate", "One", "Day" };
public static final String[] DIALOGUE = {
"Love Love Love Love Love",
"Hate Hate Hate Hate Hate",
"One One One One One",
"Day Day Day Day Day" };
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_layout);
}
public static class DetailsActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getResources().getConfiguration().orientation
== Configuration.ORIENTATION_LANDSCAPE) {
// If the screen is now in landscape mode, we can show the
// dialog in-line with the list so we don't need this activity.
finish();
return;
}
if (savedInstanceState == null) {
// During initial setup, plug in the details fragment.
DetailsFragment details = new DetailsFragment();
details.setArguments(getIntent().getExtras());
getSupportFragmentManager().beginTransaction().add(android.R.id.content, details).commit();
}
}
}
public static class TitlesFragment extends ListFragment {
boolean mDualPane;
int mCurCheckPosition = 0;
int mShownCheckPosition = -1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
System.out.println(getClass().getSimpleName() + ".onCreate() Bundle=" +
(savedInstanceState == null ? null : savedInstanceState));
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Populate list with our static array of titles.
setListAdapter(new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, Shakespeare.TITLES));
// API 11:android.R.layout.simple_list_item_activated_1
// Check to see if we have a frame in which to embed the details
// fragment directly in the containing UI.
View detailsFrame = getActivity().findViewById(R.id.details);
mDualPane = detailsFrame != null && detailsFrame.getVisibility() == View.VISIBLE;
if (savedInstanceState != null) {
// Restore last state for checked position.
mCurCheckPosition = savedInstanceState.getInt("curChoice", 0);
mShownCheckPosition = savedInstanceState.getInt("shownChoice", -1);
}
if (mDualPane) {
// In dual-pane mode, the list view highlights the selected item.
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
// Make sure our UI is in the correct state.
showDetails(mCurCheckPosition);
}
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("curChoice", mCurCheckPosition);
outState.putInt("shownChoice", mShownCheckPosition);
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
showDetails(position);
}
/**
* Helper function to show the details of a selected item, either by
* displaying a fragment in-place in the current UI, or starting a
* whole new activity in which it is displayed.
*/
void showDetails(int index) {
mCurCheckPosition = index;
if (mDualPane) {
// We can display everything in-place with fragments, so update
// the list to highlight the selected item and show the data.
getListView().setItemChecked(index, true);
if (mShownCheckPosition != mCurCheckPosition) {
// If we are not currently showing a fragment for the new
// position, we need to create and install a new one.
DetailsFragment df = DetailsFragment.newInstance(index);
// Execute a transaction, replacing any existing fragment
// with this one inside the frame.
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.details, df);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
mShownCheckPosition = index;
}
} else {
// Otherwise we need to launch a new activity to display
// the dialog fragment with selected text.
Intent intent = new Intent();
intent.setClass(getActivity(), DetailsActivity.class);
intent.putExtra("index", index);
startActivity(intent);
}
}
}
public static class DetailsFragment extends Fragment {
/**
* Create a new instance of DetailsFragment, initialized to
* show the text at 'index'.
*/
public static DetailsFragment newInstance(int index) {
DetailsFragment f = new DetailsFragment();
// Supply index input as an argument.
Bundle args = new Bundle();
args.putInt("index", index);
f.setArguments(args);
return f;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
System.out.println(getClass().getSimpleName() + ".onCreate() Bundle=" +
(savedInstanceState == null ? null : savedInstanceState));
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
System.out.println(getClass().getSimpleName() + ".onAttach() Activity=" +
(activity == null ? null : activity));
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
System.out.println(getClass().getSimpleName() + ".onActivityCreated() Bundle=" +
(savedInstanceState == null ? null : savedInstanceState));
}
#Override
public void onStart() { super.onStart(); System.out.println(getClass().getSimpleName() + ".onStart()"); }
#Override
public void onResume() { super.onResume(); System.out.println(getClass().getSimpleName() + ".onResume()"); }
#Override
public void onPause() { super.onPause(); System.out.println(getClass().getSimpleName() + ".onPause()"); }
#Override
public void onStop() { super.onStop(); System.out.println(getClass().getSimpleName() + ".onStop()"); }
#Override
public void onDestroyView() { super.onDestroyView(); System.out.println(getClass().getSimpleName() + ".onDestroyView()"); }
#Override
public void onDestroy() { super.onDestroy(); System.out.println(getClass().getSimpleName() + ".onDestroy()"); }
#Override
public void onDetach() { super.onDetach(); System.out.println(getClass().getSimpleName() + ".onDetach()"); }
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
System.out.println(getClass().getSimpleName() + ".onCreateView() Activity=" +
(container == null ? null : container));
if (container == null) {
// We have different layouts, and in one of them this
// fragment's containing frame doesn't exist. The fragment
// may still be created from its saved state, but there is
// no reason to try to create its view hierarchy because it
// won't be displayed. Note this is not needed -- we could
// just run the code below, where we would create and return
// the view hierarchy; it would just never be used.
return null;
}
ScrollView scroller = new ScrollView(getActivity());
TextView text = new TextView(getActivity());
int padding = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
4, getActivity().getResources().getDisplayMetrics());
text.setPadding(padding, padding, padding, padding);
scroller.addView(text);
text.setText(Shakespeare.DIALOGUE[getArguments().getInt("index", 0)]);
return scroller;
}
}
}
layout/fragment_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
<fragment class="com.example.android.apis.app.FragmentLayout$TitlesFragment"
android:id="#+id/titles"
android:layout_width="match_parent" android:layout_height="match_parent" />
</FrameLayout>
layout-land/fragment_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:baselineAligned="false"
android:layout_width="match_parent" android:layout_height="match_parent">
<fragment class="com.example.android.apis.app.FragmentLayout$TitlesFragment"
android:id="#+id/titles" android:layout_weight="1"
android:layout_width="0px" android:layout_height="match_parent" />
<FrameLayout android:id="#+id/details" android:layout_weight="1"
android:layout_width="0px" android:layout_height="match_parent" />
<!-- API 11:android:background="?android:attr/detailsElementBackground" -->
</LinearLayout>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.apis.app"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="4"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.example.android.apis.app.FragmentLayout"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.example.android.apis.app.FragmentLayout$DetailsActivity"
android:label="#string/app_name" >
</activity>
</application>
</manifest>
I've had some success with the following method.
This does the right thing based on the fragment's state.
public void activate(FragmentTransaction ft, Fragment f, String tag, int resId) {
boolean changed = resId != f.getId();
if (changed && (f.isAdded() || f.isDetached())) {
ft.remove(f);
ft.add(resId, f, tag);
return;
}
// Currently in a detached mode
if (f.isDetached()) {
ft.attach(f);
return;
}
// Not in fragment manager add
if (!f.isAdded() && ! f.isDetached()) {
ft.add(resId, f, tag);
return;
}
}
This handles the specific memoized fragment.
private enum FragmentOp {
ADD
,DETACH
,REMOVE
;
}
private void ensureFragmentState(FragmentOp op) {
if (null == iChild) {
iChild = (FragmentChild) iFM.findFragmentById(R.id.fragment_phonenumber_details);
}
FragmentTransaction ft = iFM.beginTransaction();
switch(op) {
case ADD:
if (null == iChild) {
iChild = new FragmentChild();
}
activate(ft, iChild, null, R.id.fragment_phonenumber_details);
break;
case DETACH:
if (null != iChild) {
iChild.deactivate(ft);
}
break;
case REMOVE:
if (null != iChild) {
iChild.remove(ft);
}
break;
}
// Only if something shows up did we do anything!
if (null != iChild) {
ft.commit();
}
}
And then in the lifecycle methods:
#Override public void onResume() {
super.onResume();
if (iDualPane) {
ensureFragmentState(FragmentOp.ADD);
}
}
#Override public void onPause() {
super.onPause();
recordState(); // Grab what I need from the child fragment
ensureFragmentState(FragmentOp.DETACH);
}
Thanks #RogerGarzonNieto very much for spotting the method that disable auto Activity re-creation upon orientation changes. It is very useful. I am sure i will have to use it in some situations in the further.
For just avoiding Fragments re-creation upon screen rotates, i have found a simpler method that we can still allow the Activity re-creates as usual.
In onSaveInstanceState():
#Override
protected void onSaveInstanceState(Bundle outState) {
if (isPortrait2Landscape()) {
remove_fragments();
}
super.onSaveInstanceState(outState);
}
private boolean isPortrait2Landscape() {
return isDevicePortrait() && (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE);
}
and the isDevicePortrait() would be like:
private boolean isDevicePortrait() {
return (findViewById(R.id.A_View_Only_In_Portrait) != null);
}
*Notice that we cannot use getResources().getConfiguration().orientation to determine if the device is currently literally Portrait. It is because the Resources object is changed RIGHT AFTER the screen rotates - EVEN BEFORE onSaveInstanceState() is called!!
If you do not want to use findViewById() to test orientation (for any reasons, and it's not so neat afterall), keep a global variable private int current_orientation; and initialise it by current_orientation = getResources().getConfiguration().orientation; in onCreate(). This seems neater. But we should be aware not to change it anywhere during the Activity lifecycle.
*Be sure we remove_fragments() before super.onSaveInstanceState().
(Because in my case, i remove the Fragments from the Layout, and from the Activity. If it is after super.onSaveInstanceState(), the Layout will already be saved into the Bundle. Then the Fragments will also be re-created after the Activity re-creates. ###)
### I have proved this phenomenon. But the reason of What to determine a Fragment restore upon Activity re-create? is just by my guess. If you have any ideas about it, please answer my another question. Thanks!

Android Fragment Basics Tutorial

So I've been stuck on the third tutorial on the Android Developer Site about Fragments for few days. I just can't understand how the app populates data when I run the app on a tablet (big screen layout). I can understand how the data is being populated on a smaller screen (phone screen).
How does the bigger screen list populate with data?
Here is a link of the whole project from Android.com tutorials.
MainActivity Class
public class MainActivity extends FragmentActivity
implements HeadlinesFragment.OnHeadlineSelectedListener {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Here, the system will decide which news_article layout it will use based on the screen size. Will use layout if small or layout-large if it's big.
setContentView(R.layout.news_articles);
// Check whether the activity is using the layout version with
// the fragment_container FrameLayout. If so, we must add the first fragment
//This check is to determine which layout to be used, either small screen or big screen.
//fragment_container used FrameLayout for small screens.
//fragment_container is the id of FrameLayout in news_article for small screen.
if (findViewById(R.id.fragment_container) != null) {
// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
if (savedInstanceState != null) {
return;
}
// Create an instance of ExampleFragment
HeadlinesFragment firstFragment = new HeadlinesFragment();
// In case this activity was started with special instructions from an Intent,
// pass the Intent's extras to the fragment as arguments
firstFragment.setArguments(getIntent().getExtras());
// Add the fragment to the 'fragment_container' FrameLayout
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, firstFragment).commit();
}
}
public void onArticleSelected(int position) {
// The user selected the headline of an article from the HeadlinesFragment
// Capture the article fragment from the activity layout
ArticleFragment articleFrag = (ArticleFragment)
getSupportFragmentManager().findFragmentById(R.id.article_fragment);
if (articleFrag != null) {
// If article frag is available, we're in two-pane layout...
// Call a method in the ArticleFragment to update its content
articleFrag.updateArticleView(position);
} else {
// If the frag is not available, we're in the one-pane layout and must swap frags...
// Create fragment and give it an argument for the selected article
ArticleFragment newFragment = new ArticleFragment();
Bundle args = new Bundle();
args.putInt(ArticleFragment.ARG_POSITION, position);
newFragment.setArguments(args);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack so the user can navigate back
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
}
}
}
HeadLineFragment
public class HeadlinesFragment extends ListFragment {
// 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);
}
OnHeadlineSelectedListener mCallback;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 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 two-pane 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 onListItemClick(ListView l, View v, int position, long id) {
// Notify the parent activity of selected item
mCallback.onArticleSelected(position);
// Set the item as checked to be highlighted when in two-pane layout
getListView().setItemChecked(position, true);
}
}
Layout for small screen
news_article.xml
<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" />
Layout for bigscreen
news_article.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<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" />
</LinearLayout>
Notice the placement of the two layouts.
Large screen is in a tablet bin (folder) res/layout-large/main.xml while small screen layout is in generic res/layout/main.xml
Since the java asks if the findViewById is null we know if the device is a large screen or normal layout.
ArticleFragment articleFrag = (ArticleFragment) getSupportFragmentManager().findFragmentById(R.id.article_fragment);
if (articleFrag != null) {
/* not null because we are in res/layout-large */
} else {
/* we are in single pain view /res/layout/... */
}
When you call setContentView(int); they system handles loading the best layout you provided for the device based on the DPI bins provided.
I think, this question is related with this post: http://developer.android.com/training/multiscreen/screensizes.html
Note: large qualifier mean that layout will be selected on devices with screens classified as large (for example, 7" tablets and above). The other layout (without qualifiers) will be selected for smaller devices;
Also if you want to use for small screens two-pane layout, create directory:
res/layout-sw600dp/main.xml;
About Data Population:
In MainActivity you have implemented interface OnHeadlineSelectedListener, when you click on item from list (HeadLinesFragment class)
interface mCallback call function from MainActivity onArticleSelected(position);
in this function you have articleFlag
ArticleFragment articleFlag = (ArticleFragment) getSupportFragmentManager(). findFragmentById(R.id.article_fragment);
if(articleFlag != null){
//we have 2 panes (big screen)
articleFlag.updateArticleView(position);
}else{
//small screen
ArticleFragment newFragment = new ArticleFragment();
Bundle args = new Bundle();
args.putInt(ArticleFragment.ARG_POSITION, position);
newFragment.setArguments(args);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack so the user can navigate back
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
//Commit the transaction
transaction.commit();
}

Categories

Resources