Reputation: 23
I'm trying to use the setRetainInstance(true) on a ListFragment, and up until the onCreateView it works like a charm, all the properties in the class are retained and seems to be ok. But as soon as the screen rotates and the view gets generated the listView is not being displayed, although the adapter and the data are there.
I would like to ask you for some guidance in this topic because it's taken the best of me.
I'll paste the code for the activities, fragments and layouts:
ContentActivity.java
public class ContentActivity extends SherlockFragmentActivity {
private final String LOG_TAG = ContentActivity.class.getName();
private ContentListFragment contentFragment = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// set the content layout
setContentView(R.layout.content);
if (savedInstanceState == null) {
// Creates the fragment for the ContentList
contentFragment = new ContentListFragment();
// Add the fragment to the 'content_container' FrameLayout
getSupportFragmentManager()
.beginTransaction()
.add(R.id.content_container, contentFragment,
getResources().getString(R.id.content_container))
.commit();
} else {
// 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.
contentFragment = (ContentListFragment) getSupportFragmentManager()
.findFragmentByTag(
getResources().getString(R.id.content_container));
}
}
}
This is the layout for the ContentActivity content.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/content_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
This is the ContentListFragment.java
public class ContentListFragment extends SherlockListFragment implements
LoaderCallbacks<HTTPRequestLoader.RESTResponse> {
private final String LOG_TAG = ContentListFragment.class.getName();
private static final int LOADER_PREFERENCES = 0x1f;
private ContentListAdapter contentAdapter = null;
private List<Content> contents = new ArrayList<Content>();
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.content_list, container, false);
Log.i(LOG_TAG, "onCreateView");
contentAdapter = new ContentListAdapter(getActivity(),
R.layout.content_block_item, contents);
Log.i(LOG_TAG,
"savedInstanceState==null size of the adapter in onCreateView "
+ contentAdapter.getCount());
Log.i(LOG_TAG, "savedInstanceState==null size of the contents "
+ contents.size());
setListAdapter(contentAdapter);
contentAdapter.notifyDataSetChanged();
return v;
}
@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setRetainInstance(true);
// If there is no data, prepare the loader. Either re-connect with an
// existing one,
// or start a new one.
getActivity().getSupportLoaderManager().initLoader(LOADER_PREFERENCES,
null, this);
Log.i(LOG_TAG, "onCreate");
}
@Override
public Loader<RESTResponse> onCreateLoader(int id, Bundle params) {
return ConnectionManager.getInstance().getPreferencesLoader(
getActivity(), params);
}
@Override
public void onLoadFinished(Loader<HTTPRequestLoader.RESTResponse> loader,
HTTPRequestLoader.RESTResponse data) {
int code = data.getCode();
String json = data.getData();
Log.i(LOG_TAG, "loaderFinished");
// Check to see if we got an HTTP 200 code and have some data.
if (code == 200 && !json.equals("")) {
contentAdapter.clear();
contents = ParserJson.getPreferencesFromJson(json);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
contentAdapter.addAll(contents);
} else {
for (Content content : contents) {
contentAdapter.add(content);
}
}
contentAdapter.notifyDataSetChanged();
} else {
// TODO: extract string
Toast.makeText(
getActivity(),
"Failed to load Preferences data. Check your internet settings.",
Toast.LENGTH_SHORT).show();
}
}
@Override
public void onLoaderReset(Loader<RESTResponse> loader) {
}
public void deselectItems() {
for (Content content : contents) {
for (Section section : content.getSections()) {
section.setSelected(false);
}
}
contentAdapter.notifyDataSetChanged();
}
}
Here's the content_list.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="hello_world" />
<ListView
android:id="@id/android:list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@null" />
<FrameLayout
android:id="@+id/content_dialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
</FrameLayout>
</LinearLayout>
As you can see, I create the fragment only once checking the savedInstanceState, when the Fragment is created it executes a loader and sets the view. As soon as the loader finishes the load it uptades the view without problem.
As soon as I rotate the emulator's screen in shows only "hello_world" from the content_list.xml.
I've tried to move the configuration of the adapter to onViewCreated without success.
Upvotes: 2
Views: 1890
Reputation: 3489
If you are using a retained fragment then you are not supposed to attempt to update the UI in that fragment:
section 4.2:
In addition to that you can use the setRetainState(true) method call on the fragments. This retains the instance of the fragments between configuration changes but only works if the fragments is not added to the backstack. Using this method is not recommend by Google for fragments which have an user interface. In this case the data must be stored as member (field).
You could move the UI stuff to a different fragment or to the parent activity.
Upvotes: 1