I have 3 Fragment (Fragment Home, Fragment A, Fragment B and Fragment C). First time app run will display Fragment Home (Set in Mainactivity). From Navigation Draw Item can choose every fragment. Every selected item will display detail Fragment.
I have problems to handle data and retain fragment :
(1). When I select a fragment (for example Fragment A) will show the page of Fragment A. But when I rotate the device, why my fragment back to Fragment Home and not stay at current Fragment ??How to handle it ?
(2). In Fragment B, I show image in GridView. But when I rotate the device, why my fragment back to Fragment Home and not stay at current Fragment ??How to handle it and still display this fragment with existing Data?
This is my code :
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
private static final String LOG_TAG = MainActivity.class.getSimpleName();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
displaySelectedItem(R.id.nav_home);
}
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
displaySelectedItem(item.getItemId());
return true;
}
private void displaySelectedItem (int itemId) {
Fragment fragment = null;
switch (itemId){
case R.id.nav_home:
fragment = new FragmentHome();
break;
case R.id.nav_a:
fragment = new FragmentA();
break;
case R.id.nav_b:
fragment = new FragmentB();
break;
case R.id.nav_c:
fragment = new FragmentC();
break;
case R.id.nav_d:
fragment = new FragmentD();
break;
}
FragmentManager fragmentManager = MainActivity.this.getSupportFragmentManager();
List<Fragment> fragments = fragmentManager.getFragments();
if (fragments != null) {
for(Fragment f : fragments){
fragmentManager.popBackStack();
}
}
//replace the fragment
if (fragment != null) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.content_frame, fragment, "TAG_FRAGMENT");
fragmentTransaction.commit();
}
DrawerLayout drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
drawerLayout.closeDrawer(GravityCompat.START);
}
Fragment A :
public class FragmentA extends Fragment {
public FragmentA() {
super();
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_a, container, false);
return rootView;
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getActivity().setTitle("Fragment A");
}
}
Fragment B :
public class FragmentB extends Fragment {
private static final String LOG_TAG = FragmentB.class.getSimpleName();
private ImageAdapter imageAdapter;
private ArrayList<Movie> movieList;
public FragmentNowPlaying() {
super();
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_b, container, false);
GridView gridView = (GridView) rootView.findViewById(R.id.gridviewNowPlaying);
imageAdapter = new ImageAdapter(getContext(), R.layout.fragment_b, movieList);
if (savedInstanceState == null) {
movieList = new ArrayList<Movie>();
}else{
movieList = (ArrayList<Movie>) savedInstanceState.get("MovieList");
}
gridView.setAdapter(imageAdapter);
return rootView;
}
#Override
public void onSaveInstanceState(Bundle outState) {
outState.putParcelableArrayList("MovieList",movieList);
super.onSaveInstanceState(outState);
}
Solved this issue. In MainActivity add this :
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(STATE_SELECTED_POSITION, mCurrentSelectedPosition);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mCurrentSelectedPosition = savedInstanceState.getInt(STATE_SELECTED_POSITION, 0);
Menu menu = navigationView.getMenu();
menu.getItem(mCurrentSelectedPosition).setChecked(true);
}
In every fragment add condition to check savedInstanceState null or not.
Thanks everybody
You need to override onConfigurationChanged(Configuration newConfig) method in your Fragments A and B to tell them to stay there when the app configuration change. For example:
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// get current fragment
Fragment fragment = mAdapter.getItem(currentItem);
if(fragment!=null){
fragment.onResume();
}
}
Because every time you rotate the screen the onCreate() method is called.
work around
in onCreate() method check whether the savedInstanceState() is null or not
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(null == savedInstanceState){
//set you initial fragment object
}
else
{
//Load the fragment by tag
}
}
and to save the instance state just before onPause() in all fragments
#Override
protected void onSaveInstanceState(Bundle bundle1)
{
super.onSaveInstanceState(bundle1); Log.i(tag,"inside onSaveInstanceState");
bundle1.putInt("tag",n);
}
Related
I am trying to implement tablayout in a fragment which is already part of BottomNavigationView, I am facing a problem while navigating through navigation bar, There is a recycler view in a fragment which is the part of tablayout, now when I navigate between fragments via BottomNavigation the recyclerview becomes empty, and there is nothing in the logcat.
MainActivity
public class MainActivity extends AppCompatActivity {
private BottomNavigationView navigation;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getSupportActionBar().hide();
initComponent();
loadFragment(new HomeFragment());
}
private void initComponent() {
navigation = findViewById(R.id.navigation);
BottomNavigationViewHelper.disableShiftMode(navigation);
navigation.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
// ViewAnimation.fadeOutIn(fragme);
Fragment fragment = null;
switch (item.getItemId()) {
case R.id.home_main:
fragment = new HomeFragment();
break;
case R.id.search:
fragment = new SearchFragment();
break;
case R.id.notifications:
fragment = new NotificationsFragment();
break;
case R.id.favourite:
fragment = new FavouriteFragment();
break;
}
return loadFragment(fragment);
}
});
findViewById(R.id.bt_menu).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
}
private boolean loadFragment(Fragment fragment) {
if (fragment != null) {
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container, fragment)
.commit();
return true;
}
return false;
}
HomeFragment
public class HomeFragment extends Fragment {
private ViewPager view_pager;
private TabLayout tab_layout;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_home, null);
view_pager = view.findViewById(R.id.view_pager);
setupViewPager(view_pager);
tab_layout = view.findViewById(R.id.tab_layout);
tab_layout.setupWithViewPager(view_pager);
return view;
}
private void setupViewPager(ViewPager viewPager) {
SectionsPagerAdapter adapter = new SectionsPagerAdapter(getActivity().getSupportFragmentManager());
adapter.addFragment(new PresetsFragment(), "Presets");
/* adapter.addFragment(new PresetsFragment(), "Tutorials");
adapter.addFragment(new PresetsFragment(), "Categories");*/
viewPager.setAdapter(adapter);
}
#Override
public void onDestroy() {
super.onDestroy();
tab_layout = null;
view_pager = null;
}
PresetsFragment
public class PresetsFragment extends Fragment {
RecyclerView recyclerView;
PresetsAdapter presetsAdapter;
String[] presetList = {"s", "s", "d", "d"};
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_presets, container, false);
recyclerView = view.findViewById(R.id.presetsRecyclerView);
presetsAdapter = new PresetsAdapter(presetList, getActivity());
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerView.setAdapter(presetsAdapter);
//presetsAdapter.notifyDataSetChanged();
return view;
}
#Override
public void onResume() {
super.onResume();
}
}
I have spent so many hours to figure it out but still unable to get it..
from your loadFragment method you are using FrameLayout and replacing fragment on BottomNavigation selection when you do so you are creating a new fragment every time if you used a ViewPager it will work fine with you
I have Navigation drawer.and in First fragmant of Navigation drawer there is viewpager and there is information coming from network.Viewpager has 2 fragments also.When I switch fragment to Settings fragment of navigation drawer and coming back to this fragment everything is gone..There is no any information..How can i save state of this fragment?Or in which method can i send request to take information from network again
MainActivity
public class MainActivity extends AppCompatActivity implements
NavigationView.OnNavigationItemSelectedListener {
private DrawerLayout drawer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.motherFragments, FragmentMainPage.newInstance("MainPage"))
.commit();
}
#Override
public void onBackPressed() {
drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home: {
drawer.openDrawer(GravityCompat.START);
break;
}
}
return super.onOptionsItemSelected(item);
}
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
Fragment fragment = null;
if (item.isChecked()) {
drawer.closeDrawer(GravityCompat.START);
return false;
}
switch (item.getItemId()) {
case R.id.home: {
fragment = new FragmentMainPage().newInstance("Sample");
break;
}
case R.id.settings:{
Intent intent = new Intent(this,SettingsActivity.class);
startActivity(intent);
break;
}
case R.id.incoming:{
fragment = new FragmentIncomingPage().newInstance("Sample");
break;
}
}
if (fragment != null) {
getSupportFragmentManager()
.beginTransaction().replace(R.id.motherFragments, fragment)
.commit();
item.setChecked(true);
}
drawer.closeDrawer(GravityCompat.START);
return true;
} }
Fragment1 of Navigation drawer
public class FragmentMainPage extends Fragment implements
ViewPager.OnPageChangeListener {
private Toolbar toolbar;
private MainActivity activity;
private TabLayout tabLayout;
private ViewPager viewPager;
String[] names = {
"Sample 1",
"Sample 2"
};
private static FragmentMainPage myInstance;
public static FragmentMainPage newInstance(String testString){
Bundle bundle = new Bundle();
bundle.putString("test",testString);
if(myInstance == null){
myInstance = new FragmentMainPage();
}
myInstance.setArguments(bundle);
return myInstance;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
activity = ((MainActivity) context);
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_fragment_main,container,false);
toolbar = (Toolbar) view.findViewById(R.id.toolbar);
activity.setSupportActionBar(toolbar);
activity.setTitle(getResources().getText(R.string.bosh_sahifa));
activity.getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_menu_white_24dp);
activity.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
viewPager = (ViewPager) view.findViewById(R.id.viewpager);
setupViewpager(viewPager);
tabLayout = (TabLayout) view.findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
viewPager.addOnPageChangeListener(this);
setupTabName();
return view;
}
private void setupViewpager(ViewPager viewPager) {
MyAdapter adapter = new MyAdapter(getActivity().getSupportFragmentManager());
adapter.addFragement(new Fragment_home1());
adapter.addFragement(new Fragment_home2());
viewPager.setAdapter(adapter);
}
private void setupTabName() {
tabLayout.getTabAt(0).setText(names[0]);
tabLayout.getTabAt(1).setText(names[1]);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
}
#Override
public void onPageScrollStateChanged(int state) {
}
private class MyAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
public MyAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
public void addFragement(Fragment fragment){
mFragmentList.add(fragment);
}
}
}
Fragment 2 of Navigation drawer
public class FragmentIncomingPage extends Fragment {
private Toolbar toolbar;
private MainActivity activity;
private static FragmentIncomingPage myInstance;
public static FragmentIncomingPage newInstance(String testString){
Bundle bundle = new Bundle();
bundle.putString("test",testString);
if(myInstance == null){
myInstance = new FragmentIncomingPage();
}
myInstance.setArguments(bundle);
return myInstance;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
activity = ((MainActivity) context);
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_fragment_incoming,container,false);
toolbar = (Toolbar) view.findViewById(R.id.toolbar);
activity.setSupportActionBar(toolbar);
activity.setTitle(getResources().getText(R.string.Incoming));
activity.getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_menu_white_24dp);
activity.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
return view;
}
}
Have 3 fragments and swipe to 3rd fragment then back to 1st fragment, the 1st fragment's data is gone?
You can use fragment.addToBackStack(null) method.
like,
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, A);
ft.addToBackStack(null);
ft.commit();
There is few ways to achieve it.
You can use SharedPreferences to save current Fragment by mViewPager.getCurrentItem() and set it again once you come to the ViewPager activity by navigation drawer button.
Use BaseFragment and implement your fragments from the Base Fragment, keep current visible fragment of the view pager in side the Base Fragment as protected variable.
As Base Fragment which is describe above, You can use Bas Activity class.
I am using Navigation drawer layout and have 2 items in side menu. I used fragment for each item to show while navigate.
Let's consider Fragment1 & Fragment2. When i auto-rotate the screen from Fragment2, it destroy the fragment and showing Fragment1 's content.
With few youTube tutorials, I tried using onSaveInstanceState. But i was not able to find the correct solution.
JavaHomeActivity.java //Fragment1
public class JavaHomeActivity extends Fragment{
// created for save state in orientation change
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState==null)
{
}
else{
savedInstanceState.getString("home_text");
}
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getActivity().setTitle("Home");
}
// created for save state in orientation change
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("home_text", String.valueOf(R.id.nav_home));
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.java_home_layout,container,false);
}
}
JavaBasicActivity //Fragment2
public class JavaBasicActivity extends Fragment{
TextView text;
String data;
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getActivity().setTitle("Java Basics");
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("basic_text", String.valueOf(R.id.nav_basics));
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view= inflater.inflate(R.layout.java_basic_layout,container,false);
if(savedInstanceState==null)
{
}
else{
data=savedInstanceState.getString("basic_text");
TextView myText= (TextView) view.findViewById(R.id.basicText);
myText.setText(data);
}
return view;
}
}
Fragment1's XML
<TextView
android:id="#+id/homeText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_gravity="start"
android:padding="15dp"
android:text="#string/java_home_content"
android:textAlignment="textStart"
android:textColor="#color/text_color" />
Fragment2's XML
<TextView
android:id="#+id/basicText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_gravity="start"
android:drawableBottom="#drawable/jvm_arc"
android:padding="15dp"
android:text="#string/java_basic_content"
android:textAlignment="textStart"
android:textColor="#color/text_color" />
JavaMainPageActivity.java //navigation Drawer Activity
public class JavaMainPageActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_java_main_page);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
displaySelectedScreen(R.id.nav_home);
}
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.java_main_page, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
private void displaySelectedScreen(int id){
Fragment fragment= null;
switch(id)
{
case R.id.nav_home:
fragment= new JavaHomeActivity();
break;
case R.id.nav_basics:
fragment= new JavaBasicActivity();
break;
}
if(fragment!=null)
{
FragmentTransaction ft= getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_main, fragment);
ft.commit();
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
}
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
displaySelectedScreen(id);
return true;
}
}
Can anyone please help me? Where i am doing error and which i have to change to get the solution.?
You are adding the Fragment in your onCreate through displaySelectedScreen(R.id.nav_home); and this gets executed even after orientation change.
So this overrides the actual system recreated Fragment.
Change the code like this in onCreate:
if (savedInstanceState == null) {
displaySelectedScreen(R.id.nav_home);
}
Here is your solution.
Your Fragment would look something like this:
public class Fragment1 extends Fragment {
private View mView;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
// created for save state in orientation change
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("Fragment1", "My First Fragment");
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
mView = inflater.inflate(R.layout.fragment_1, container, false);
return mView;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
TextView mText = (TextView) mView.findViewById(R.id.text);
if (savedInstanceState == null) {
} else {
String saved = savedInstanceState.getString("Fragment1");
mText.setText(saved);
}
}
}
And your activity should be like this :
public class MainActivity extends AppCompatActivity {
private Fragment mCurrentFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState != null) {
//Restore the fragment's instance
mCurrentFragment = getSupportFragmentManager().getFragment(savedInstanceState, "Fragment1");
} else {
mCurrentFragment = new Fragment1();
addFragment(mCurrentFragment);
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
getSupportFragmentManager().putFragment(outState, "Fragment1", mCurrentFragment);
}
public void addFragment(Fragment fragment) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
if (mCurrentFragment != null) {
Fragment f = getSupportFragmentManager().findFragmentByTag(mCurrentFragment.getClass().getName());
if (f != null) {
fragmentTransaction.remove(f);
}
}
fragmentTransaction.add(R.id.fragment, fragment, fragment.getClass().getName());
fragmentTransaction.commit();
mCurrentFragment = fragment;
}
}
As it is already said that activity will recreate, you need to save your fragment's state too in your activity as in above code.
Hope it will help you and more clear to you.
I have one activity that uses two fragments, MainFragment and DetailFragment. The MainFragment has an expandable list view that has company names as groups and location names as children. When the user selects a category from the navigation drawer it updates the data in the adapter and updates the expandable list, displaying the correct companies.
When the user selects a location it opens the DetailFragment with information about that location and employees. The problem I'm having is when I step back. When I hit the back button it resets to the default category, and I've figured out that it's because it's calling the onViewCreated() method again, which is where I set up my views and adapter. The strange thing is, it remembers what list items were expanded, by index. So if I had the third item expanded in a different category, the third item in the default category is still expanded.
What I'd like to know is, how can I have it maintain the setup I had when I press back?
My MainFragment
public class MainFragment extends Fragment implements ExpandableListView.OnChildClickListener, NavigationSelectedListener {
private CompaniesExpandableListAdapter adapter;
public MainFragment() {
// Required empty public constructor
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_main, container, false);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
connectViews(view);
}
private void connectViews(View view) {
final ExpandableListView companyListView = (ExpandableListView) view.findViewById(R.id.companyListView);
final Navigation navigationItem = ((MainActivity) getActivity()).getNavigationItems().first();
getActivity().setTitle(navigationItem.getTitle());
adapter = new CompaniesExpandableListAdapter(navigationItem.getCompanies());
companyListView.setAdapter(adapter);
companyListView.setOnChildClickListener(this);
}
// ExpandableListView.OnChildClickListener
#Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
final DetailFragment detailFragment = new DetailFragment();
final Bundle args = new Bundle();
args.putInt(getString(R.string.extra_location_key), ((Locations) adapter.getChild(groupPosition, childPosition)).getPrimaryKey());
detailFragment.setArguments(args);
getFragmentManager()
.beginTransaction()
.replace(R.id.contentFrame, detailFragment, getString(R.string.tag_fragment_detail))
.addToBackStack(null)
.commit();
return false;
}
// NavigationSelectedListener
#Override
public void onNavigationItemSelected(Navigation navigationItem) {
// Go back to the main fragment.
getFragmentManager().popBackStack(getString(R.string.tag_fragment_main), FragmentManager.POP_BACK_STACK_INCLUSIVE);
// Send the selected item to the adapter.
adapter.updateData(navigationItem.getCompanies());
getActivity().setTitle(navigationItem.getTitle());
}
}
And my MainActivity
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
private NavigationSelectedListener navigationCallback;
private DrawerLayout drawerLayout;
private RealmResults<Navigation> navigationItems;
private MainFragment mainFragment = new MainFragment();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
buildNavigationDrawer();
connectViews();
}
#Override
public void onBackPressed() {
if (drawerLayout.isDrawerOpen(GravityCompat.START)) drawerLayout.closeDrawer(GravityCompat.START);
else super.onBackPressed();
}
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
navigationCallback.onNavigationItemSelected(navigationItems.get(item.getItemId()));
drawerLayout.closeDrawer(GravityCompat.START);
return true;
}
private void connectViews() {
navigationCallback = mainFragment;
getFragmentManager()
.beginTransaction()
.replace(R.id.contentFrame, mainFragment, getString(R.string.tag_fragment_main))
.commit();
}
private void buildNavigationDrawer() {
final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
final ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close) {
#Override
public void onDrawerStateChanged(int newState) {
super.onDrawerStateChanged(newState);
// Hides the device keyboard when the navigation drawer is opened.
if (getCurrentFocus() != null) ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
}
};
drawerLayout.addDrawerListener(toggle);
toggle.syncState();
fillNavigationDrawer();
}
public RealmResults<Navigation> getNavigationItems() {
return navigationItems;
}
}
You should use add instead of replace in your transaction.
As mentioned in my previous question I had some problem with showing Fragments inside a ViewPager after opening another Fragment from one of the Fragments inside the ViewPager.
I somehow managed to resolve the problem by using add() in the FragmentTransaction. Unfortunately this creates another problem:
I am using the ActionBar in my app. When I am selecting the same menu item twice I encounter the same problem as before, it doesn't show any Fragments inside the ViewPager.
Home Activity Code(where action bar on click events are call)
public class HomePageActivity extends SherlockFragmentActivity implements ICallback {
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
private SherlockActionBarDrawerToggle mDrawerToggle;
private CharSequence mDrawerTitle;
private CharSequence mTitle;
private String[] mChampionsMenuItems;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme(R.style.Theme_Sherlock);
setContentView(R.layout.activity_home_page);
mTitle = mDrawerTitle = getTitle();
mChampionsMenuItems = getResources().getStringArray(R.array.champions_array);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerList = (ListView) findViewById(R.id.left_drawer);
mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
mDrawerList.setAdapter(new ArrayAdapter<String>(this, R.layout.drawer_list_item, mChampionsMenuItems));
mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setBackgroundDrawable(getResources().getDrawable(R.color.navy_blue));
getSupportActionBar().setDisplayShowTitleEnabled(false);
mDrawerToggle = new SherlockActionBarDrawerToggle(this, mDrawerLayout, R.drawable.menu_icon, R.string.drawer_open, R.string.drawer_close) {
public void onDrawerClosed(View view) {
getSupportActionBar().setTitle(mTitle);
supportInvalidateOptionsMenu();
}
public void onDrawerOpened(View drawerView) {
getSupportActionBar().setTitle(mDrawerTitle);
supportInvalidateOptionsMenu();
}
};
mDrawerLayout.setDrawerListener(mDrawerToggle);
if (savedInstanceState == null) {
onFragmentChange(new HomeActivityFragment(), true);
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
switch (item.getItemId()) {
default: return super.onOptionsItemSelected(item);
}
}
private class DrawerItemClickListener implements ListView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
selectItem(position);
}
}
private void selectItem(int position) {
switch (position) {
case 0:
onFragmentChange(new Fragment1(), false);
break;
case 1:
onFragmentChange(new Fragment2(), false);
break;
case 2:
onFragmentChange(new MyPointFragment3(), false);
break;
case 3:
// onFragmentChange(new HomeActivityFragment(), true);
break;
case 4:
onFragmentChange(new QueriesFragment(), false);
break;
case 5:
onFragmentChange(new GalleryFragment(), false);
break;
default:
break;
}
mDrawerList.setItemChecked(position, true);
mDrawerLayout.closeDrawer(mDrawerList);
}
#Override
public void setTitle(CharSequence title) {
mTitle = title;
getSupportActionBar().setTitle(mTitle);
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
mDrawerToggle.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mDrawerToggle.onConfigurationChanged(newConfig);
}
#Override
public void onFragmentChange(Fragment fragment, boolean flag) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.add(R.id.content_frame, fragment, fragment.getClass().getName());
transaction.commit();
}
}
This is the Fragment which contains the ViewPager:
public class Fragment1 extends Fragment implements OnClickListener {
ICallback callback;
private LinearLayout headerContainer;
private ImageView headerLogo;
private TextView headerName;
private Button menuBarButton;
MyAdapter adapter;
ViewPager pager;
ActionBar actionBar;
private Button progOverview, progStr, bonusPoint;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof ICallback) {
this.callback = (ICallback) activity;
}
actionBar = activity.getActionBar();
actionBar.show();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = setUpView(inflater, container);
return rootView;
}
private View setUpView(LayoutInflater inflater, ViewGroup container) {
View rootView = inflater.inflate(R.layout.fragment_about_champions_club, container, false);
headerContainer = (LinearLayout) rootView.findViewById(R.id.second_top_header);
headerContainer.setBackgroundColor(getResources().getColor(R.color.prog_str_blue));
headerLogo = (ImageView) rootView.findViewById(R.id.header_logo);
headerLogo.setBackgroundResource(R.drawable.about_champions_ticon);
headerName = (TextView) rootView.findViewById(R.id.header_name);
headerName.setText(R.string.about_champ_title);
adapter = new MyAdapter(getFragmentManager());
pager = (ViewPager) rootView.findViewById(R.id.pager);
pager.setAdapter(adapter);
return rootView;
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null) {
// Restore last state for checked position.
}
}
}
}
This is one of the Fragments inside the ViewPager:
public class ProgramOverViewFragment extends Fragment {
ICallback callback;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof ICallback) {
this.callback = (ICallback) activity;
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_program_overview, container, false);
TextView termsAndCond = (TextView) rootView.findViewById(R.id.terms_and_condition_button);
termsAndCond.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.content_frame, fragment);
fragment.setRetainInstance(true);
transaction.addToBackStack(null);
transaction.commit();
}
});
return rootView;
}
}
My FragmentStatePagerAdapter:
public class MyAdapter extends FragmentStatePagerAdapter {
public MyAdapter(FragmentManager fm) {
super(fm);
}
#Override
public android.support.v4.app.Fragment getItem(int index) {
switch (index) {
case 0: return new ProgramOverViewFragment();
case 1: return new ProgramStructureFragment();
case 2: return new BonusPointFragment();
}
return null;
}
#Override
public int getCount() {
return 3;
}
}
Thanks for your help!
What do you want to do exactly? Are you trying to replace a Fragment inside the ViewPager? Or are you trying to replace a Fragment inside a Fragment inside the ViewPager? Or are you trying to do something different altogether? I can only give you an accurate solution if you explain what you are trying to do in detail. Anyway here is what I am guessing might be wrong:
I think your problem is that you use the wrong FragmentManager. There are multiple different FragmentManagers, but essentially there are two cases:
You want to add/replace/remove a Fragment from an Activity
You want to add/replace/remove a Fragment from another Fragment
As long as I don't see your layout files I can't be sure which of those two options fits your situation.
Solution if you want to replace a Fragment inside of another Fragment
If you want to perform a FragmentTransaction on a Fragment inside of another Fragment, then you need to use the child FragmentManager! You can use the child FragmentManager inside a Fragment like this:
FragmentManager fragmentManager = getChildFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.content_frame, fragment);
fragment.setRetainInstance(true);
transaction.addToBackStack(null);
transaction.commit();
As you can see you just need to use getChildFragmentManager() instead of getSupportFragmentManager()
As I already said, without any further information about your situation I cannot give you a more accurate answer. So please try to explain what you want to do as best as you can to me and I'm confident we can solve this.
Finally i found what i did wrong in my code :
i'm using this below code for setting adapter for view Pager inside a fragment :
adapter = new MyAdapter(getFragmentManager());
pager = (ViewPager) rootView.findViewById(R.id.pager);
pager.setAdapter(adapter);
and by replacing getFragmentManager() to getChildFragmentManager() we resolve this problem. As per my understanding i'm using view pager inside a fragment that's why i have to use getChildFragment manager to store transitions of my viewPager.
Might this help someone and this question is still open for better solutions.