Android FragmentTransaction commit twice - android

I'm new to Android Developing and i'm trying to create a clickable ListView. And when you click on any element of it, it shows a fragment with the text from elememnt. But it doesn't seem to work becouse you can't commit FragmentTransaction twice. And without first commiting you can't add a fragment to fragment contrainer and therefore you can't change the text of Fragment=(
Here's my Activity Code:
public class MyActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
final FragmentManager fManager = getFragmentManager();
final FragmentTransaction fTransaction = fManager.beginTransaction();
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
Random rand = new Random(); // Randomizer
ArrayList Array = new ArrayList(5); // Array
for(int i = 0; i < 8; i++)
{
Array.add(rand.nextInt(30));
}
ArrayAdapter<String> MyAdapter =
new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, Array);
final ListView listview = (ListView)findViewById(R.id.MyList);
listview.setAdapter(MyAdapter);
final MyFragment MyFrag = new MyFragment();
fTransaction.add(R.id.FragmentContainer, MyFrag);
fTransaction.commit();
AdapterView.OnItemClickListener itemListener = new AdapterView.OnItemClickListener()
{
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
String Selection = parent.getItemAtPosition(position).toString();
MyFrag.SetText(Selection);
fTransaction.remove(MyFrag);
fTransaction.add(R.id.FragmentContainer, MyFrag);
fTransaction.commit();
}
};
listview.setOnItemClickListener(itemListener);
}
I've tried to use "replace" but the result was the same...
It says:
" java.lang.IllegalStateException: commit already called "
Here is my fragment code:
public class MyFragment extends Fragment
{
TextView textView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View myInflatedView = inflater.inflate(R.layout.fragment_my_first, container, false);
textView = (TextView) myInflatedView.findViewById(R.id.MyFragView);
if (textView == null)
{
System.out.println("myInflatedView == null");
}
return inflater.inflate(R.layout.fragment_my_first, null);
}
#Override
public void onAttach( Activity activity)
{
super.onAttach(activity);
Toast.makeText(getActivity(), "You have attached a fragment",
Toast.LENGTH_SHORT).show();
}
public void SetText(String text)
{
if(textView == null)
{
System.out.println("textView == null");
}
textView.setText(text);
}
}
Sry for a huge pack of hard-reading code=(

You have to initiate a new transaction, not use the previous because you have already commit it.

well, you should create new FragmentTransaction inside the onItemClick which will remove the old fragment

Related

Can't Access to ExpandablelistView in fragment

MainActivity on startup add a fragment layout to Relativeview, then i send a data to fragment to add it to ExpandablelistView but my app shows me error that couldn't recognize ExpandablelistView.
MainActivity:
public class MainActivity extends AppCompatActivity implements FragmentAddCatergory.onClickButtonListener {
private FragmentManager manager;
private FragmentTransaction transactionShowList;
private FragmentTransaction transactionAddCatergory;
private FragmentAddCatergory addCatergory;
private FragmentShowCategory showCategory;
private boolean addcategory;
private TextView txtAddCategory;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
manager = getFragmentManager();
transactionShowList = manager.beginTransaction();
showCategory = new FragmentShowCategory();
addCatergory=new FragmentAddCatergory();
transactionShowList.add(R.id.Fragment_container, showCategory);
transactionShowList.commit();
addcategory=false;
txtAddCategory = (TextView) findViewById(R.id.txtaddcategory);
txtAddCategory.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ChangeFragment();
}
});
}
public void ChangeFragment(){
transactionAddCatergory=manager.beginTransaction();
if (addcategory){
transactionAddCatergory.replace(R.id.Fragment_container,addCatergory);
txtAddCategory.setText("Do you want to see your List?Show me!");
addcategory=false;
}else{
transactionAddCatergory.replace(R.id.Fragment_container,showCategory);
txtAddCategory.setText("Do you want to add a Category?Create One");
addcategory=true;
}
transactionAddCatergory.commit();
}
#Override
public void ClickButton(String group, String child) {
FragmentShowCategory a=new FragmentShowCategory();
a.showExpand(this,group,child);
}}
in last above code i make object from first fragment and send a data and in below code is code of first fragment
public class FragmentShowCategory extends Fragment {
private View view;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
view = inflater.inflate(R.layout.activity_expandable_list_view, container, false);
return view;
}
public void showExpand(Context context, String g, String c) {
Toast.makeText(context, g + " is " + c, Toast.LENGTH_LONG).show();
HashMap<String, List<String>> carsDetails = DataProvider.getInfo(g, c);
List<String> carsBrands = new ArrayList<String>(carsDetails.keySet());
ItemClass adapter = new ItemClass(context, carsDetails, carsBrands);
ExpandableListView list = (ExpandableListView) view.findViewById(R.id.expandList);
list.setAdapter(adapter);
}}
but when i ran my app, i get error that i don't know why in line of:
ExpandableListView list = (ExpandableListView) view.findViewById(R.id.expandList);
i'd appreciate to help me.
Your fragment's view hierarchy is not inflated automatically just because you created an instance of your fragment, as you do in ClickButton. The onCreateView() method that has to be called first in order to inflate your views is part of the fragment's lifecycle. You should let Android instantiate your fragment, and acquire it's instance through the FragmentManager.
This tutorial explains basics about fragments very well.

(Unusual way of) Controlling nested fragments by Activity's fragment manager

Having a look at this thread, I have a fundamental question.
1) Imagine I have a multi-pane layout like this one:
2) Now lets imagine that the underlying xml is like this one (for simplicity's sake most attributes are missed):
somefragment_land.xml:
<LinearLayout orientation="horizontal" ...>
<!--our side menu-->
<ListView id="#+id/menu" />
<!--our details fragment container-->
<FrameLayout id="#+id/container"/>
</LinearLayout>
3) Ok, so we have this SomeFragment class:
public class SomeFragment extends Fragment {
public static final String TAG = "TAGTAGTAG";
private static final String STATE_SELECTED_POSITION = "selected_position";
private int currentSelectedPosition;
private ListView mMenu;
private MyAdapter mAdapter;
private boolean isMultipaneMode;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
isMultipaneMode = getResources().getBoolean(R.bool.show_fragment_multiplane);
if (savedInstanceState != null) {
currentSelectedPosition = savedInstanceState.getInt(STATE_SELECTED_POSITION, 0);
} else if (isMultipaneMode) {
currentSelectedPosition = 0;
}
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
int resId = isMultipaneMode ? R.layout.fragment_somefragment_land : R.layout.fragment_somefragment;
View root = inflater.inflate(resId, container, false);
mMenu = (ListView) root.findViewById(R.id.menu);
mMenu.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
SomeItem item = mAdapter.getItem(position);
showDetails(item);
}
});
///do some stuff creating adapter
mMenu.setAdapter(mAdapter);
if (isMultipaneMode) {
showDetails(mAdapter.getItem(currentSelectedPosition));
}
return root;
}
#Override
public void onDestroyView() {
//remove details fragment
destroyDetails();
super.onDestroyView();
}
private void destroyDetails() {
if (isMultipaneMode) {
//schedule a transaction to remove a fragment
//it will happen after SomeFragment is removed
FragmentManager fm = getFragmentManager();
Fragment fragmentByTag = fm.findFragmentByTag(FragmentDetails.TAG);
if (fragmentByTag == null) {
L.e(this.getClass(), "Details fragment removed");
return;
}
fm.beginTransaction()
.remove(fragmentByTag)
.commit();
}
}
private void showDetails(SomeItem item) {
if (isMultipaneMode) {
FragmentDetails details = new FragmentDetails();
Bundle args = new Bundle();
args.putString(FragmentDetails.ARG_ID, item.getId());
details.setArguments(args);
getFragmentManager()
.beginTransaction()
.replace(R.id.fragment, details, FragmentDetails.TAG)
.commit()
;
} else {
ActivityDetail.launch(getActivity(), item.getTitle(), item.getType());
}
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (isMultipaneMode) {
outState.putInt(STATE_SELECTED_POSITION, currentSelectedPosition);
}
}
}
So the logic is straightforward, show details in Fragment (for multipane mode) or start Details activity if we are running on a smartphone etc
What I want to know is - how much wrong is this approach in terms of Fragment management?
I imagine myself the following case:
SomeFragment is added to FragmentManager
user decides to go elsewhere
Transaction_1 is started to remove SomeFragment
this calls to onDestroyView() which schedules a transaction to
remove DetailsFragment
Transaction_1 is complete, however, DetailsFragment is not yet
removed. It possibly holds some part of SomeFragment view hierarchy
in memory
Transaction_2 is started to remove DetailsFragment
Transaction_2 is complete, DetailsFragment is destroyed
???
These question marks stand for some uncertainty - have I created a memory leak? Or something worse? Any off-top-of-your-head consequences of using this approach?

in Android replace ListView Fragment with Details Fragment on item click

I've got a database search function working in a Fragment. Now I want the search Fragment to get replaced with the details Fragment when the user clicks an item in the search results list. It's my understanding that a Fragment Transaction can't be initiated in a Fragment, so what I've done is sub classed the Fragment in the Main Activity Class, and everything works fine, up until you want to click an item in the search results. My minimum API is 10, so I'm using the support library, and when I try and set up the Transaction in the setOnClickListener() by doing this: FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); I get the warning: Cannot make a static reference to the non-static method getSupportFragmentManager() from the type FragmentActivity. So How can I replace my search Fragment with the details Fragment in the setOnClickListener()? Here's what I've got:
public class SearchInterface extends ActionBarActivity {
ActionBar bar_AB;
private static EditText searchbox_ET;
private static DBAdapter dbHelper;
static View searchRootView;
static ListView listView_LV;
String searchResultStr;
static Cursor getPathCursor;
static String cursorSDFStr = null;
static String cursorCalDateStr = null;
static String cursorURLStr = null;
static String cursorTitleStr = null;
static String cursorinfoBodyStr = null;
String videoURLStr = null;
String sdfStr = null;
String calDateStr = null;
String titleStr = null;
String infoBodyStr = null;
static FragmentManager fragMan;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
overridePendingTransition(R.anim.fadein, R.anim.fadeout);
// --- set up Action Bar
bar_AB = getSupportActionBar();
bar_AB.setDisplayHomeAsUpEnabled(true);
fragMan = getSupportFragmentManager();
if (fragMan.findFragmentById(android.R.id.content) == null) {
SSISearchFragEm searchEm_FRG = new SSISearchFragEm();
fragMan.beginTransaction().add(android.R.id.content, searchEm_FRG)
.commit();
}
}// --- END onCreate
public static class SSISearchFragEm extends Fragment {
LinearLayout list_LL;
private Button search_BTN;
// --- Create the ROOT VIEW
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
searchRootView = inflater.inflate(R.layout.ssi_search_frag,
container, false);
searchbox_ET = (EditText) searchRootView
.findViewById(R.id.ssi_Search1_et1);
search_BTN = (Button) searchRootView
.findViewById(R.id.ssi_search_btn1);
list_LL = (LinearLayout) searchRootView
.findViewById(R.id.ssi_search_list_LL);
// --- Button
search_BTN.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
dbHelper = new DBAdapter(getActivity());
dbHelper.open();
String searchTermStr = searchbox_ET.getText().toString();
Cursor cursor = dbHelper.searchDB(searchTermStr);
if (cursor != null) {
String[] columns = new String[] { DBAdapter.KEY_TITLE,
DBAdapter.KEY_CAL_DATE, DBAdapter.KEY_PATH,
DBAdapter.KEY_SDF, DBAdapter.KEY_INFOBODY,
DBAdapter.KEY_KEYWORDS };
int[] to = new int[] { R.id.slp_title_tv, R.id.slp_date_tv,
R.id.slp_url_tv, R.id.slp_sdf_tv, R.id.slp_infoBody_tv,
R.id.slp_keywords_tv };
SimpleCursorAdapter dataAdapter = new SimpleCursorAdapter(
getActivity(), R.layout.slp_list_item, cursor, columns, to,
0);
listView_LV = (ListView) searchRootView
.findViewById(R.id.ssisearch_list_lv);
listView_LV.setEmptyView(searchRootView
.findViewById(R.id.ssiempty_list_tv));
listView_LV.setAdapter(dataAdapter);
}
dbHelper.close();
//--- onClick
// --- pass to ListVideo
listView_LV.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
getPathCursor = (Cursor) listView_LV
.getItemAtPosition(position);
cursorSDFStr = getPathCursor.getString(getPathCursor
.getColumnIndexOrThrow("sdfdate"));
cursorCalDateStr = getPathCursor.getString(getPathCursor
.getColumnIndexOrThrow("caldate"));
cursorURLStr = getPathCursor.getString(getPathCursor
.getColumnIndexOrThrow("path"));
cursorTitleStr = getPathCursor.getString(getPathCursor
.getColumnIndexOrThrow("title"));
cursorinfoBodyStr = getPathCursor.getString(getPathCursor
.getColumnIndexOrThrow("details"));
Toast.makeText(getActivity(), "Item Be Clicked!", Toast.LENGTH_SHORT).show();
//--- Detail fragment here?
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
}
});//--- END onClick
}
});
// --- END Button
return searchRootView;
}// --- END Create the ROOT VIEW
}
}
try to use
FragmentTransaction fragmentTransaction =
getChildFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.graph_layout, checkUpGraphFragment);
fragmentTransaction.commit();
I figured it out. #jitain sharma set me on the right path, even though I found that getChildFragmentManager() was not my solution. Here's my solution:
fragTrans = fragMan.beginTransaction();
listFrag = fragMan.findFragmentByTag("com.myapp.SearchFragEm");
if(listFrag != null)fragTrans.remove(listFrag);
video_FRG = new SSIVideoFrag();
fragTrans.replace(R.id.frag5_main_FL, video_FRG);
fragTrans.addToBackStack(null);
fragTrans.commit();

Textview is null on first click but updates on second click

It's small Android 2.2 test application using the Compatibility Package. I am trying to update the textview on another fragment on another activity on list item selection. But problem is that everytime the first click returns nullpointer exception and only on the second try its text is changing. I would like to know why is the happening and what is a good solution.
ListActivity:-
public class ListActivity extends FragmentActivity implements
ListFragment.OnItemSelectedListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list);
}
#Override
public void onItemSelected(int index) {
// TODO Auto-generated method stub
// Check to see if there is a frame in which to embed the
// detail fragment directly in the containing UI.
View detailsFrame = findViewById(R.id.detailcontainer);
if (detailsFrame != null
&& detailsFrame.getVisibility() == View.VISIBLE) {
DetailFragment detailFragment = (DetailFragment) getSupportFragmentManager()
.findFragmentById(R.id.detailcontainer);
if (detailFragment == null) {
detailFragment = new DetailFragment();
}
// Execute a transaction, replacing any existing fragment
// with this one inside the frame.
getSupportFragmentManager().beginTransaction()
.replace(R.id.detailcontainer, detailFragment).commit();
detailFragment.setTextView(index);
} else {
// Otherwise we need to launch a new activity to display
Intent intent = new Intent(this, DetailActivity.class);
intent.putExtra("index", index);
startActivity(intent);
}
}
}
ListFragment :-
public class ListFragment extends Fragment {
private OnItemSelectedListener listener;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
String[] countries = new String[] { "India", "Pakistan", "Sri Lanka",
"China", "Bangladesh", "Nepal", "Afghanistan", "North Korea",
"South Korea", "Japan" };
View view = inflater.inflate(R.layout.list_fragment, container, false);
ListView listView = (ListView) view.findViewById(R.id.listView);
// Populate list
ArrayAdapter<String> adapter = new ArrayAdapter<String>(
this.getActivity(), android.R.layout.simple_list_item_1,
countries);
listView.setAdapter(adapter);
// operation to do when an item is clicked
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Toast.makeText(getActivity(), "ListItem Number " + position,
Toast.LENGTH_SHORT).show();
listener.onItemSelected(position);
}
});
return view;
}
// Container Activity must implement this interface
public interface OnItemSelectedListener {
public void onItemSelected(int index);
}
// To ensure that the host activity implements this interface
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof OnItemSelectedListener) {
listener = (OnItemSelectedListener) activity;
} else {
throw new ClassCastException(activity.toString()
+ " must implemenet ListFragment.OnItemSelectedListener");
}
}
public void operation(int index) {
listener.onItemSelected(index);
}
}
Detail Activity :-
public class DetailActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DetailFragment details;
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
finish();
return;
}
if (savedInstanceState == null) {
// During initial setup, plug in the details fragment.
details = new DetailFragment();
details.setArguments(getIntent().getExtras());
getSupportFragmentManager().beginTransaction()
.add(android.R.id.content, details).commit();
}
Bundle extras = getIntent().getExtras();
int index = extras.getInt("index");
try {
details = (DetailFragment) getSupportFragmentManager()
.findFragmentById(R.id.detailfragment);
details.setTextView(index);
} catch (NullPointerException ex) {
ex.getStackTrace();
}
}
}
DetailFragment :-
public class DetailFragment extends Fragment {
String[] capitals;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (container == null)
return null;
capitals = new String[] { "delhi", "karachi", "colombo", "beijing",
"dhaka", "katmandu", "Afghanistan", "pyongyang", "seoul",
"tokyo" };
View v = inflater.inflate(R.layout.detail_fragment, container, false);
return v;
}
public void setTextView(int index) {
try {
TextView view = (TextView) getView().findViewById(R.id.detailView);
view.setText(capitals[index]);
} catch (NullPointerException ex) {
ex.getStackTrace();
}
}
public int getShownIndex() {
return getArguments().getInt("index", 0);
}
}
Update:- I am adding the detailFragment xml:-
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:background="#color/lightblue"
android:orientation="vertical" >
<TextView
android:id="#+id/detailView"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="#string/detail_frag" />
</RelativeLayout>
Instead of doing details.setTextView(index) in DetailActivity , set the value of TextView in the DetailFragment's onActivityCreated while passing the value to be set in fragments setArgument method in the Detailactivity...
DetailsFragment details = new DetailsFragment();
details.setArguments(getIntent().getExtras()); // pass the value of text view here
And In fragment onActivityCreated get that value via getArguments() and set it in textview..
EDIT for sending value Selected to loaded Fragment
In List Activity
detailFragment = getFragmentbyTag
if(detailFragment == null)
Create Fragment and Add it and Set Arguments here as well
else
detailFragment.setTextView(value); // fragment already loaded no need to set arguments
if you want to replace each time and not add once and use the added/loaded fragment , use setarguments each time.... and remove previous fragment and add new fragment( with Arguments) But added once and reused is preferred instead of removing and adding/ replacing on each click
Updated2
Just initialize your TextView in onCreateView() no need to create DetailFragment with parametrize just put in comment
Check the details object whether its null or not if null initialize as you do and then called setTextView()
if(details==null)
details = new DetailFragment(index);
else
setTextView(index);
TextView inside onCreateView() and used their
public class DetailFragment extends Fragment {
String[] capitals;
int index;
private TextView textView;
public DetailFragment(int index){
this.index = index;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (container == null)
return null;
capitals = new String[] { "delhi", "karachi", "colombo", "beijing",
"dhaka", "katmandu", "Afghanistan", "pyongyang", "seoul",
"tokyo" };
View v = inflater.inflate(R.layout.detail_fragment, container, false);
// Initialize textView
textView = (TextView) v.findViewById(R.id.detailView);
setTextView(index); // set value value here for first time
return v;
}
public void setTextView(int index) {
if(textView!=null)
textView.setText(capitals[index]);
}
public int getShownIndex() {
return getArguments().getInt("index", 0);
}
}
did you tried using this
TextView view = (TextView) findViewById(R.id.detailView);
instead of this
TextView view = (TextView) getView().findViewById(R.id.detailView);

Fool-proof way to handle Fragment on orientation change

public class MainActivity extends Activity implements MainMenuFragment.OnMainMenuItemSelectedListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager
.beginTransaction();
// add menu fragment
MainMenuFragment myFragment = new MainMenuFragment();
fragmentTransaction.add(R.id.menu_fragment, myFragment);
//add content
DetailPart1 content1= new DetailPart1 ();
fragmentTransaction.add(R.id.content_fragment, content1);
fragmentTransaction.commit();
}
public void onMainMenuSelected(String tag) {
//next menu is selected replace existing fragment
}
I have a need to display two list views side by side, menu on left and its content on right side. By default, the first menu is selected and its content is displayed on right side. The Fragment that displays content is as below:
public class DetailPart1 extends Fragment {
ArrayList<HashMap<String, String>> myList = new ArrayList<HashMap<String, String>>();
ListAdapter adap;
ListView listview;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if(savedInstanceState!=null){
myList = (ArrayList)savedInstanceState.getSerializable("MYLIST_obj");
adap = new LoadImageFromArrayListAdapter(getActivity(),myList );
listview.setAdapter(adap);
}else{
//get list and load in list view
getlistTask = new GetALLListTasks().execute();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.skyview_fragment, container,false);
return v;
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable("MYLIST_obj", myList );
}
}
The onActivityCreated and onCreateView are called twice. There are many examples out there using fragments. Since I am beginner in this subject, I am unable relate the example with my problem. I need a fool proof way to handle orientation change. I have NOT declared android:configChanges in manifest file. I need the activity destroy and recreate so that I can use different layout in landscape mode.
You are creating a new fragment every time you turn the screen in your activity onCreate(); But you are also maintaining the old ones with super.onCreate(savedInstanceState);. So maybe set tag and find the fragment if it exists, or pass null bundle to super.
This took me a while to learn and it can really be a pain when you are working with stuff like viewpager.
I'd recommend you to read about fragments an extra time as this exact topic is covered.
Here is an example of how to handle fragments on a regular orientation change:
Activity:
public class MainActivity extends FragmentActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
TestFragment test = new TestFragment();
test.setArguments(getIntent().getExtras());
getSupportFragmentManager().beginTransaction().replace(android.R.id.content, test, "your_fragment_tag").commit();
} else {
TestFragment test = (TestFragment) getSupportFragmentManager().findFragmentByTag("your_fragment_tag");
}
}
}
Fragment:
public class TestFragment extends Fragment {
public static final String KEY_ITEM = "unique_key";
public static final String KEY_INDEX = "index_key";
private String mTime;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_layout, container, false);
if (savedInstanceState != null) {
// Restore last state
mTime = savedInstanceState.getString("time_key");
} else {
mTime = "" + Calendar.getInstance().getTimeInMillis();
}
TextView title = (TextView) view.findViewById(R.id.fragment_test);
title.setText(mTime);
return view;
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("time_key", mTime);
}
}
A good guideline about how to retain data between orientation changes and activity recreation can be found in android guidelines.
Summary:
make your fragment retainable:
setRetainInstance(true);
Create a new fragment only if necessary (or at least take data from it)
dataFragment = (DataFragment) fm.findFragmentByTag("data");
// create the fragment and data the first time
if (dataFragment == null) {

Categories

Resources