I have trouble why learning Android fragments.
In my app I have one activity with 3 fragments. Each fragment is to replace previous after some user action. My main xml layout is simple FrameLayout with ID 'container'. What I do in MainActivity onCreate() method is adding default fragment to container:
public class HolderActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
....
FragmentList listFragment = new FragmentList();
// Add the fragment to the 'container'
getSupportFragmentManager().beginTransaction()
.add(R.id.container, listFragment).commit();
Initial screen works just fine.
Then I add other fragment, based on button click:
// Go to settings fragment
FragmentSettings mFragmentSettings = new FragmentSettings();
getFragmentManager().beginTransaction().replace(R.id.container, mFragmentSettings).commit();
The problem is that when I click needed button App doesn't replace fragments, it just adds new fragment over the old one, so they collapse. Could You please tell me what I am doing wrong here?
EDIT:
When I try to use getSupportFragmentManager() in my onOptionsItemSelected method like this:
#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();
if (id == R.id.action_settings) {
// Go to settings fragment
FragmentSettings mFragmentSettings = new FragmentSettings();
getFragmentManager().beginTransaction()
.replace(R.id.container, mFragmentSettings).commit();
}
return super.onOptionsItemSelected(item);
}
I get this error:
"The method replace(int, Fragment) in the type FragmentTransaction is not applicable for the arguments (int, FragmentSettings)"
Why are you using a supportFragmentManager and then the normal FragmentManager?
getSupportFragmentManager() and getFragmentManager().
If you're using ActionBarActivity, then use support one. If Activity then the normal one.
Related
I have a simple BottomNavigationView with two menu items (Home Fragment, Settings Fragment) in an activity.
I have implemented onNavigationItemSelectedListener and onNavigationItemSelected.
Also bottomNavigationView.setOnNavigationItemSelectedListener(this);
App page lands on the Home Fragment.
onNavigationItemSelected is being called when I switch between menu items but When I first launch the app and tap on the same menu Item i.e. Home Fragment, onNavigationItemSelected is not being called.
I would need to show a toast whenever the user clicks on the home page when user is already in home page but onNavigationItemSelected event is not triggered.
As Mike M mentioned,
setOnNavigationItemReselectedListener did the trick.
First of all we do this in the MainActivity
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
int v = item.getItemId();
if(v==R.id.home)
{
getSupportActionBar().setTitle("Home");
Fragment fragment = new HomeFragment();
FragmentManager fm = getSupportFragmentManager();
fm.beginTransaction().replace(R.id.frame_layout, fragment).commit();
}
else if (v==R.id.dash_board)
{
getSupportActionBar().setTitle("Dashboard");
Fragment fragment = new DashboardFragment();
FragmentManager fm = getSupportFragmentManager();
fm.beginTransaction().replace(R.id.frame_layout, fragment).commit();
}
return true;
}
};
This is a example here
If you want to know in detail then click here
I have a NavigationViewer activity which has 3 fragments. I want that every time the user selects an item from NavigationViewersliding menu items the app will transact a new fragment object of the selected kind.
for Example I have a NavigationViewer menu item Called "MyFragment"
So I am trying this Code on that item:
MyFragment myFragment = new MyFragment();
fragmentTransaction.replace(R.id.RR, myFragment , "nav_MyFragment ").commit();
But this causes a problem that if user selected "MyFragment" from menu while it is active [seen to user] it will create a new object.
and I want to create that new object only if transacting from some fragment to another.
Any Suggestions?
Edit: retrieving the fragment by tag and then checking if isVisble() or if isAdded() gives null exception
You can keep a Fragment variable and assign your active fragment there, and then check the getClassName() and if it's the clicked one is the same as the one you are currently displaying, you don't load a new one.
I'm going to use the code from this app I have in github.
Then in your Activity declare a Fragment variable like this:
Fragment active;
In your onOptionsItemSelected() method, you have to do the checking for the item pressed.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.nav_item1) {
if (active.getClass().getSimpleName().equals("FragmentA")) {
// then this fragment is already being shown, therefore do nothing
} else {
FragmentA fragtoadd = new FragmentA();
getFragmentManager().beginTransaction()
.remove(fragtoadd)
.commit();
active = fragtoadd; // the magic is here, everytime you add a new fragment, keep the reference to it to know what fragment is being shown
}
return true;
} else if (id == R.id.nav_item2) {
// do the same as above but for FragmentB, and so on
return true;
}
// ... check all your items
return super.onOptionsItemSelected(item);
}
If you have your code in Github so that I can have a look it would be better.
Hope it helps!
U have to add fragment instance into backstack
getSupportedFragmentManager.addToBackStack(fragment.gettag)
I assume you can detect the actual item clicks, so what I do is this:
private static final String TAG_FRAGMENT_SOME_NAME = "something";
mFragmentManager = getSupportFragmentManager(); // or getFragmentManager() if not using support library
mFragmentTransaction = mFragmentManager.beginTransaction();
Fragment myFragment = mFragmentManager.findFragmentByTag(TAG_FRAGMENT_SOME_NAME);
if (myFragment == null) {
myFragment = MyFragment.newInstance();
}
mFragmentTransaction.replace(R.id.RR, myFragment, TAG_FRAGMENT_SOME_NAME).commit();
I have only one activity in my application which contains navigation view to navigate through 3 fragments.
When I navigate to a fragment I get the hamburger menu icon changed to the up button in the onNavigationItemSelected method like this:
actionBarDrawerToggle.setDrawerIndicatorEnabled(false);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
The up button appears well but has no effect yet.
I wanna navigate to the previous fragment in the stack when the button is clicked but I can't get to add a listener to that button.
I've tried using:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
but this is never called. I think it's not called because I have no parent activity in the manifest.
Thanks in advance.
You should not call onBackPressed, you should use fragment transaction method to to transact between fragments like I replaced my current fragment with previous fragment using replace method. container is the layout containing the fragments.
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, newFragment);
transaction.commit();
I hope, it give you some direction.
if (id == android.R.id.home) {
//put the code like above here.
return true;
}
Android Studio 0.5.8
Hello,
I have one activity (MainActivity) that will host 2 fragments (ListAddressBookFragment, AddAddressBookFragment) (only one at a time). The initial fragment will be the ListAddressBookFragment and will be inflated when MainActivity onCreate gets called.
/* MainActivity.java */
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/* Add and display fragment */
FragmentManager fragmentManager = getSupportFragmentManager();
Fragment fragment = fragmentManager.findFragmentById(R.id.flFragmentContainer);
/* Create new fragment if this hasn't already been done */
if(fragment == null) {
fragment = new ListAddressBookFragment();
fragmentManager.beginTransaction()
.add(R.id.flFragmentContainer, fragment)
.commit();
}
}
In the ListAddressBookFragment I have a option menu to add a new addressbook item. So this will call call MainActivity. So I want to replace ListAddressBookFragment with AddAddressBookFragment. However, because the code above is hardcoded I am wondering is there anyway to do this on the fly?
/* ListAddressBookFragment.java */
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();
if (id == R.id.new_addressbook) {
Intent intent = new Intent(getActivity(), MainActivity.class);
startActivity(intent);
return true;
}
return super.onOptionsItemSelected(item);
}
Many thanks for any suggestions,
I would recommend you to read this article, Communicating with fragments
Basically, you need to call
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, newFragment);
Also, consider using interface within fragment that activity implements.
Why don't you pass data to the MainActivity to indicate the mode you want the activity to be in?
intent.putExtra("mode", "addressbook");
In the MainActivity, you do the below.
String mode = (String)getIntent().getStringExtra("mode");
if ("addressbook".equals(mode)) {
// Address book fragment
} else {
// ListAddressBookFragment
}
Good Luck
I have a simple app that has two fragments and when in landscape mode, both fragments are shown side by side and in portrait I show Fragment A and then if they select an option, start an Activity that shows Fragment B. My problem is when I am in Portrait mode and showing Fragment B, if the user selects a menu option I want to refresh or redraw the View that is associated with Fragment B and can’t understand how to make this work. I tried the getView method and getLayoutInflater method but the screen doesn’t change because I think I am creating a new view. I also tried to get a reference to Fragment A thinking I could call its routine to build a new fragment and replace Fragment B but can’t get a reference to it because it is not being displayed. What I really need to do is just force the onCreateView method to be called again to inflate the new view but I have tried several methods to try to do this but can’t get the onCreateView to be called again. Any thoughts on how to this?
You will want to perform a FragmentTransaction and use the replace() method
This shouldn't be too hard to do, but the answer will depend on where your Menu is located (i.e. is your onOptionsItemSelected() call back inside your parent Activity or is it in either Fragment A/B?).
Suppose for simplicity's sake, your menu implementation and onOptionsItemSelected() is in the parent activity, and you want to reshape the fragments in the event that menu_option1 is chosen. It would look something like this:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
//...
switch (item.getItemId()) {
case R.id.menu_option1:
//do something
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Fragment newFragment = new YourFragmentClass();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.your_fragment_id, newFragment);
transaction.addToBackStack(null);
transaction.commit();
return true;
case R.id.menu_option2:
//do something else;
return true;
default:
return super.onOptionsItemSelected(item);
}
}
Alternatively, if your menu is a child of one of your Fragments (which it should be for the sake of more reusable code), then one method is to require that host Activity to implement an interface defined by the Fragment, that can be used as a call back.
And in the onOptionsItemSelected() callback inside your fragment class, you simply make a call to this callback method.
Although it sounds like a mouthful, you only really need to do a couple of things. Pretend that this is your Fragment class
public static class FragmentA extends ListFragment {
OnSelectedListener mListener;
// Container Activity must implement this interface
public interface OnSelectedListener {
public void onSelected();
}
...
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
//This is to ensure that the Activity has implemented the interface we set up above
try {
mListener = (OnSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnSelectedListener");
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
//...
switch (item.getItemId()) {
case R.id.menu_option1:
//do something
getActivity().onSelected();
return true;
case R.id.menu_option2:
//do something else;
return true;
default:
return super.onOptionsItemSelected(item);
}
}
...
}
Then in the Activity, you would see something like:
public class MainActivity extends Activity implements FragmentA.onSelectedListener{
...
public void onSelected(){
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Fragment newFragment = new YourFragmentClass();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.your_fragment_id, newFragment);
transaction.addToBackStack(null);
transaction.commit();
}
}
if the user selects a menu option I want to refresh or redraw the View that is associated with Fragment B and can’t understand how to make this work
In onOptionsItemSelected(), have the activity call a method on the fragment that causes it to update its widgets with the new content. Or, have the activity execute a FragmentTransaction to replace the fragment (if the fragment was originally set up via a FragmentTransaction).