I've got an Activity that acts like a presentation, I want to put some buttons so I can go directly to particular fragment (the one I choose from the MainActivity).
I've tried with getSupportFragment and Activity.getSupportFragment but nothing works. And, obviously, neither with a simple intent.
Thanks.
This is the MainActivity "Splash":
public class Splash extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.lay_splash);
}
}
The start of the FragmentActivity. It's not complete, so it contain errors. This is the Activity that contains the Fragments
public class FragmentActivity extends ActionBarActivity
implements NavigationDrawerFragment.NavigationDrawerCallbacks {
/**
* Fragment managing the behaviors, interactions and presentation of the navigation drawer.
*/
private NavigationDrawerFragment mNavigationDrawerFragment;
/**
* Used to store the last screen title. For use in {#link #restoreActionBar()}.
*/
private CharSequence mTitle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mNavigationDrawerFragment = (NavigationDrawerFragment)
getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
mTitle = getTitle();
To switch between Views, I use:
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
FragmentManager fragmentManager = getSupportFragmentManager();
Fragment views=null;
switch (position) {
case 0:
//news
views= new news();
break;
case 1:
//time
views=new time();
break;
case 2:
//Ins
views=new Ins() ;
break;
}
fragmentManager.beginTransaction()
.replace(R.id.container, views)
.commit();
}
Ok, i can try giving you a solution: instead of creating a new view, you can add all fragments to the SplashActivity following this guide.
Than set all fragment to be with View.GONE.
Once an user click a button, change the View property of the related fragment to Visible and all others to Gone.
Doing this everytimes an user clicks a button, all Fragments disappears except the one you need.
This should work but i suggest to have a look to official documentation or this guide on how to use NavigationDrawer propertly.
Hope i helped, good luck!
Related
The background
I have single activity in my App which loads 2 fragments based on some menu item selection
public class ActivityMain extends AppCompatActivity{
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState == null) {
loadFragment(1); // DEFAULT FRAGMENT, AT THE BEGINNING
}
}
..........................
..........................
// This method is called above, ALSO onItemClick in the Navigation Drawer (code not included for brevity)
public void loadFragment(int position) {
Fragment fragment = null;
switch (position) {
case 1:
fragment = new Fragment1();
break;
case 2:
fragment = new Fragment2();
break;
default:
break;
}
if (fragment != null) {
getFragmentManager().beginTransaction().replace(R.id.fragment_container, fragment, "frag_" + position).addToBackStack(null).commit();
}
}
}
"Fragment1" is a simple fragment with a fixed text in a TextView. "Fragment2" uses SlidingTabLayout to load a Fragment "FragmentViewPager" in a viewpager using FragmentStatePagerAdapter.
The issue I am facing:
Even if I remove "Fragment2" from the Activity's Frame Layout (using getFragmentManager().beginTransaction().remove), Fragment "FragmentViewPager" does not get destroyed, rather it resumes every time Activity resumes.
Question
Why FragmentViewPager is not destroyed with "Fragment2"?
If you are using FragmentStatePagerAdapter then this will not destroy fragment and when you swipe and come back to that fragment it will show old data without refresh. Because of not destroyed by viewpager.
Situation:
I have an activity with a FrameLayout in which I change fragments.
I use:
getSupportFragmentManager().beginTransaction()
.replace(R.id.content, fragment)
.addToBackStack("name")
.commit)
All works fine the problem is when I go back in the stack the previous fragment is reloaded and all the data is lost.
Possible solution:
restore fragment state - I want to avoid this because most of the data is retrieved from the server and it takes a lot of time
use .add(R.id.content, fragment) instead of .add(R.id.content, fragment) but in this case my fragments must have a solid background otherwise they overlay each other. The problem is that I can't set a solid background because of some design constraints.
Question:
How can i use '.add(R.id.content,fragment)' and somehow hide the fragment below it so it won't overlay and I can go back to the previous fragment in the state I left it.
First I would say that there's no need to add the fragment to the backstack if you don't want the user to go back to a previous fragment.
To answer the other question, the FragmentManager has a "hide" method that you can use to keep a fragment in the FragmentManager, but hide it from the user. Then use "show" to reveal it again.
final Fragment oldFragment = methodToGetFragment();
getSupportFragmentManager().beginTransaction()
.add(R.id.content, fragment)
.hide(oldFragment)
.addToBackStack("name")
.commit)
Like stated in the first sentence, the Fragment is going to be popped and the old fragment will be shown when the user presses "back". If you don't want that to happen, then simply remove addToBackStack().
for save data
you can use Activity when replacing fragments, activity is live .
public class MotherActivity extends ActionBarActivity {
private Data data = null;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_adv);
Fragment oldFragment = methodToGetFragment();
getSupportFragmentManager().beginTransaction()
.add(R.id.content, fragment)
.hide(oldFragment)
.addToBackStack("name")
.commit)
}
public void setData(Data data){
....
}
public void getData(){
....}
}
public class FirstFragment extends Fragment {
private AdvActivity act;
......
public void onAttach(Activity activity) {
super.onAttach(activity);
// get data from internet
Data data=getData();
// and save data in mother activity
activity.setData(data);
}
second fragment:
public class SecondFragment extends Fragment {
private AdvActivity act;
private Data data;
......
public void onAttach(Activity activity) {
super.onAttach(activity);
// get data from mother activity
data=activity.getData();
}
I'm looking for a way to se a default fragment in my navigation drawer which is not the item # 0. I've seen some solutions based on checking if savedInstanceState is null or not but I feel like I don't have access to this in my onNavigationDrawerItemSelected method. Here is my class:
public class Main extends ActionBarActivity
implements NavigationDrawerFragment.NavigationDrawerCallbacks {
/**
* Fragment managing the behaviors, interactions and presentation of the navigation drawer.
*/
private NavigationDrawerFragment mNavigationDrawerFragment;
/**
* Used to store the last screen title. For use in {#link #restoreActionBar()}.
*/
private CharSequence mTitle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mNavigationDrawerFragment = (NavigationDrawerFragment)
getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
mTitle = getTitle();
// Set up the drawer.
mNavigationDrawerFragment.setUp(
R.id.navigation_drawer,
(DrawerLayout) findViewById(R.id.drawer_layout));
}
#Override
public void onNavigationDrawerItemSelected(int position) {
// update the Main content by replacing fragments
Fragment fragment = null;
switch (position) {
case 0:
fragment = new HomeFragment();
break;
case 1:
fragment = new HomeFragment();
break;
case 2:
fragment = new HomeFragment();
break;
default:
fragment = new DiscoverFragment();
}
if (fragment != null) {
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.container, fragment).commit();
}
}
The answer is rather simple. Since the DrawerLayout leaves you to manage fragments on your own, you can just use the basic FragmentManager APIs that would be used in a normal FragmentActivity.
I use the following method to make it a little simpler, which will replace the current fragments even if there are none currently added to the container. Just call this method with the fragment you want to be default in your onCreate() method.
public void setFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.container, fragment)
.commit();
}
Note that it is technically more correct to use .add(fragment) for the first call rather than .replace since you aren't replacing anything, but it really doesn't matter because internally, it basically just removes any existing fragments and adds the new one using .add() for you
http://developer.android.com/reference/android/app/FragmentTransaction.html#replace(int,android.app.Fragment,java.lang.String)
I used Navigation Drawer to setup a Drawer.
In my MainActivity on the onCreate method, I have the following setup
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FrameLayout frame = new FrameLayout(this);
frame.setId(CONTENT_VIEW_ID);
setContentView(frame, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
if (savedInstanceState == null) {
setFragment(0);
}
}
And my setFragment Method, within the Main Activity is this:
public void setFragment(int id) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
switch(id){
case 0:
fragmentTransaction.add(CONTENT_VIEW_ID, FragOne.newInstance()).commit();
break;
case 1:
fragmentTransaction.replace(CONTENT_VIEW_ID,FragTwo.newInstance()).commit();
break;
}
}
note I've declared CONTENT_VIEW_ID as:
private static final int CONTENT_VIEW_ID = 666;
When the application starts, it loads the fragment one and it works fine.
When I swipe open the Navigation drawer and select the position 1, it replaces the current fragment with the FragTwo, but right after that the navigation drawer freezes, I can't access it anymore.
Can anyone help me resolve this issue, I been searching online for awhile now and couldn't find a solution to my problem, that why I have decided to ask here, thank you in advanced :)
Asuming you have all the other needed code t make a drawerLayout work fine, I think you should use .replace(...) in both cases. It works for me, even though it freezes a little while fragment is being load before it finishes closing.
Firstly, I know these subjects have been created a lot of time on stackoverflow, but I don't have found the solution to my problems. Secondly, I'm french, so my english is not perfect, sorry per advance and tell me if you don't understand something. And to finish this introduction, it's the first time that I'm dealing with fragments, so, sorry if there is something that I don't have well understand !
I have three buttons, that allow to switch between three fragments.
Inside one of these fragments, I have a view pager with two fragments. For the moment, each fragments (there are 5), only contains a TextView.
I'm using the latest version of android-support-v4 (I have read a lot of subject in stackoverflow that say that the latest version of support solve the "Recursive entry to executePendingTransactions" error that I have).
My two problems :
When I click two times in one button, I have an IllegaleStateException "can't change tag of fragment". I was able to fix that by creating a new fragment on onButtonSelected method, but I don't want to recreate fragment each time, for memory reasons and for functional reasons : fragment have to keep her state. This problem is not my main problem, indeed, i know that to disable the button when user is already on fragment is possible, but it's strange to have an exception when this management is not done, no ?.
When I go out from the fragment with the view pager, and I go back to this fragment, I have an IllegalStateException "Recursive entry to executePendingTransactions". I can fix this by setting my adapter on an handler, or use FragmentStatePagerAdapter instead of FragmentPageAdapter (see Display fragment viewpager within a fragment), but even if my application don't crash, when I go back to my fragment with the view pager, the view pager has disapear !
Can you help me ?
Java source code is bellow, layout source code is, I think, useless.
MainActivity :
public class MainActivity extends SherlockFragmentActivity{
private SherlockFragment fragmentOne, fragmentTwo, fragmentThree;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// this.fragmentOne = new fragmentOne();
// this.fragmentTwo = new fragmentTwo();
// this.fragmentThree = new fragmentThree();
// Call new or instanciate ? What's the correct way ?
this.fragmentOne = (SherlockFragment) SherlockFragment.instantiate(this, FragmentOne.class.getName());
this.fragmentTwo = (SherlockFragment) SherlockFragment.instantiate(this, FragmentTwo.class.getName());
this.fragmentThree = (SherlockFragment) SherlockFragment.instantiate(this, FragmentThree.class.getName());
// Add fragment
FragmentTransaction transaction = (
this.getSupportFragmentManager().beginTransaction()
);
transaction.add(
R.id.tab_fragment,
this.fragmentOne,
this.fragmentOne.toString()
);
transaction.commit();
}
public void onButtonSelected(View v){
switch (v.getId()){
case R.id.button_one_tab:{
showFragment(this.fragmentThree);
break;
}
case R.id.button_two_tab:{
showFragment(this.fragmentOne);
break;
}
case R.id.button_three_tab:{
showFragment(this.fragmentTwo);
break;
}
default:{
break;
}
}
}
public void showFragment(SherlockFragment fragmentToShow){
FragmentTransaction transaction = (
this.getSupportFragmentManager().beginTransaction()
);
transaction.replace(R.id.tab_fragment, fragmentToShow, fragmentToShow.toString());
transaction.commit();
}
}
Fragment two and three only inflate a layout that only contains a TextView.
Fragment one (note that i'm using a DirectionalViewPager - a lib - instead of a ViewPager):
public class FragmentOne extends SherlockFragment{
private FragmentOneAdapter fragmentOneAdapter;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Set up the pager
final DirectionalViewPager pager = (DirectionalViewPager)getActivity().findViewById(R.id.pager);
if (this.fragmentOneAdapter== null){
this.fragmentOneAdapter= new FragmentOneAdapter (getActivity().getSupportFragmentManager());
}
pager.setAdapter(fragmentOneAdapter);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_landing_page, container, false);
}
FragmentOneAdapter :
public class FragmentOneAdapter extends FragmentPagerAdapter{
private ArrayList<SherlockFragment> fragmentsList;
public FragmentOneAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
SherlockFragment fragmentFour = new FragmentFour();
SherlockFragment fragmentFive = new FragmentFive();
this.fragmentsList = new ArrayList<SherlockFragment>();
this.fragmentsList.add(fragmentFour);
this.fragmentsList.add(fragmentFive);
}
#Override
public Fragment getItem(int position) {
return this.fragmentsList.get(position);
}
#Override
public int getCount() {
return this.fragmentsList.size();
}
}
Thanks per advance for your help !
I have solved my problem !
I have simply replace getSupportFragmentManager() on FragmentOne to getChildFragmentManager(). Then, I have edited my onButtonSelected's method by creating a new instance of fragment each time instead of using my three different instances (if I don't do that, I have an exception : java.lang.IllegalStateException: Activity has been destroyed).
I have still a problem with this solution : I lose the state of each fragment each time I'm switching between fragmentOne, fragmentTwo and fragmentThree. Do you have a solution for that ?