Switching between fragments in drawer menu does nothing - java

I am really new to android and I am really frustrated with it. I want to switch between fragments in drawer menu. However, the screen stays the same. In the drawer it says that I am on a particular fragment but I see no change. I set a different background to differentiate between them.
I believe that fragment manager is deprecated based on what people are saying but I don't know how to change it with. Also the thin is I don't know which tutorials are out of date because I have very little knowledge about android development.
Fragment code:
public class ToolsFragment extends Fragment {
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_tools, container,false);
}
}
Main activity code:
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);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
drawer = findViewById(R.id.drawer_layout);
NavigationView navigationView = findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar,
R.string.navigation_drawer_open,R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new CharacterFragment());
navigationView.setCheckedItem(R.id.nav_characters);
}
}
#Override
public void onBackPressed() {
if (drawer.isDrawerOpen(GravityCompat.START)){
drawer.closeDrawer(GravityCompat.START);
} else{
super.onBackPressed();
}
}
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()){
case R.id.nav_characters:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new CharacterFragment());
break;
case R.id.nav_episodes:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new EpisodesFragment());
break;
case R.id.nav_tools:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new EpisodesFragment());
break;
}
drawer.closeDrawer(GravityCompat.START);
return true;
}
}

You forgot to call commit()
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new CharacterFragment()).commit();

Related

Load all fragments at once (including fragments which are inside fragments)

So this is my main activity class
public class NewMainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener{
DrawerLayout drawerLayout;
NavigationView navigationView;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.new_main_activity);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowTitleEnabled(false);
getWindow().setStatusBarColor(ContextCompat.getColor(this, R.color.purple_500));
BottomNavigationView bottomNav = findViewById(R.id.bottom_navigation);
getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, new HomeFragment()).commit();
bottomNav.setOnNavigationItemSelectedListener(navListener);
//NewNav
drawerLayout = findViewById(R.id.drawer_layout);
navigationView = findViewById(R.id.navView);
navigationView.bringToFront();
ActionBarDrawerToggle toggle=new ActionBarDrawerToggle(this,drawerLayout,toolbar,R.string.navigation_drawer_open,R.string.navigation_drawer_close);
drawerLayout.addDrawerListener(toggle);
toggle.syncState();
navigationView.setNavigationItemSelectedListener(this);
navigationView.setCheckedItem(R.id.mm_home);
}
private BottomNavigationView.OnNavigationItemSelectedListener navListener =
new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment selectedFragment = null;
switch (item.getItemId()){
case R.id.nav_home:
selectedFragment = new HomeFragment();
break;
case R.id.nav_faq:
selectedFragment = new FAQFragment();
break;
case R.id.nav_price:
selectedFragment = new PriceMarketFragment();
break;
case R.id.nav_news:
selectedFragment = new NewsFragment();
break;
}
getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, selectedFragment).commit();
return true;
}
};
I have a frame layout in my mainactivity xml which i have given ID fragment_container.
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="#id/appBarLayout"
app:layout_constraintBottom_toTopOf="#id/navBottom"/>
In bottom navigation, I have 4 fragments, in which 3 fragments (Home, Price and News), I have tablayouts (more fragments within fragments).
When the mainactivity starts (the application starts) i want all of the parent fragments and child fragments to be loaded. and then i only need to navigate through them.
How can i do this please help.

ActionBar Back button opens drawer instead of going back

In my app I have problem like this. Note that I'm working with fragments and I have drawer too.
That's the method in my MainActivity for drawer open/close.
public void drawerInit() {
toolbar = (Toolbar) findViewById(R.id.toolbar_actionbar);
setSupportActionBar(toolbar);
drawer = (DrawerLayout) findViewById(R.id.drawer);
view = findViewById(R.id.mainView);
toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close) {
#Override
public void onDrawerSlide(View drawerView, float slideOffset) {
super.onDrawerSlide(drawerView, slideOffset);
float moveFactor = (drawerView.getWidth() * slideOffset);
view.setTranslationX(moveFactor);
}
#Override
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
}
};
drawer.addDrawerListener(toggle);
toggle.syncState();
}
Example I have 3 fragments (F1, F2, F3). F1 is my main fragment where I can open and close the drawer. When I'm opening F2 or F3 fragments, I need to change the drawer icon to back arrow. I'm doing this part successfully, but the problem is when I'm clicking on this back arrow, that opens the navigation drawer instead of going back. So how can I fix this part?
Here the part, where I'm changing the icon to back arrow in fragment.
((AppCompatActivity) getActivity()).getSupportActionBar().show();
((AppCompatActivity) getActivity()).getSupportActionBar().setDisplayShowTitleEnabled(false);
((AppCompatActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
((AppCompatActivity) getActivity()).getSupportActionBar().setHomeButtonEnabled(true);
Add in your Activity
public void crateMenuButton(){
toggle.setDrawerIndicatorEnabled(true);
if(toolbarDrawable == null) {
toolbarDrawable = toolbar.getNavigationIcon();
}
toolbar.setNavigationIcon(toolbarDrawable);
invalidateOptionsMenu();
toggle.syncState();
}
public void createBackButton() {
toggle.setDrawerIndicatorEnabled(false);
toggle.setToolbarNavigationClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//if the drawerToggle is disabled, fall off to the home button action
if (!toggle.isDrawerIndicatorEnabled()) {
// pop fragment here
FragmentManager fragmentManager = getSupportFragmentManager();
if (fragmentManager.getBackStackEntryCount() > 0) {
fragmentManager.popBackStack();
}
} else {
if (drawerLayout.isDrawerOpen(navigationView)) {
drawerLayout.closeDrawer(navigationView);
} else {
drawerLayout.openDrawer(navigationView);
}
}
}
});
toolbar.setNavigationIcon(getResources().getDrawable(R.drawable.ic_arrow_back_white));
}
Download Back Arrow
Then call from your fragment as your need
((YourActivity) getActivity()).createBackButton();
OR
((YourActivity) getActivity()).crateMenuButton();

How to set a default fragment shown in the main activity?

So i've encountered a small problem today. I was making a bottom navigation view in my app, and after clicking buttons, it replaces the fragment on the screen (and it works perfectly!).
But just after launching the app, and without clicking any button, there is no fragment on the screen.
I've realized that the fragments are shown only after clicking a button, and I'd like to have a default fragment (kalkulatorFragment).
I've been trying my best to somehow set it up, but no success...
public class Main extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
}
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
kalkulatorFragment kalkulator_fragment = new kalkulatorFragment();
wzoryFragment wzory_fragment = new wzoryFragment();
definicjeFragment definicje_fragment = new definicjeFragment();
switch (item.getItemId()) {
case R.id.kalkulator:
ft.replace(android.R.id.content, kalkulator_fragment);
ft.commit();
return true;
case R.id.wzory:
ft.replace(android.R.id.content, wzory_fragment);
ft.commit();
return true;
case R.id.definicje:
ft.replace(android.R.id.content, definicje_fragment);
ft.commit();
return true;
}
return false;
}
Ok i just figured it out.
I moved the ft.replace to the onCreate() method, so the kalkulatorFragment is going to be shown just after creating an Activity.
public class Main extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
kalkulatorFragment kalkulator_fragment = new kalkulatorFragment();
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(android.R.id.content, kalkulator_fragment);
ft.commit();
BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
}
You need to use this code OUTSIDE of OnCreate Method:
navigation.setSelectedItemId(R.id.IdOFYourItemFromBottomNavigationMenuItems);
I don't know why, but it wont work inside OnCreate method. You can declare and initialize it inside OnCreate method, just can't set the default item in there.
In my case I am using it inside OnCreateOptionsMenu.

Why is accessing TextView of a Fragment inside Activity throwing an error

MainActivity class:
/* all necessary imports */
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
/* Other variable initialized here... */
FragOne fo;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
fo.setTextViewText("This is added from Activity");
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.addDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
viewPager = (ViewPager) findViewById(R.id.viewpager);
setupViewPager(viewPager);
tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
}
private void setupViewPager(ViewPager viewPager) {
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFragment(new FragOne(), "My Tracker");
adapter.addFragment(new FragTwo(), "Team Tracker");
viewPager.setAdapter(adapter);
}
class ViewPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public ViewPagerAdapter(FragmentManager manager) {
super(manager);
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_manage) {
} else if (id == R.id.nav_share) {
} else if (id == R.id.nav_send) {
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
}
Fragment class:
/* all necessary imports */
public class FragOne extends Fragment {
TextView tvCName;
public FragOne() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_frag_one, container, false);
return view;
//return inflater.inflate(R.layout.fragment_frag_one, container, false);
}
#Override
public void onViewCreated(View view , Bundle savedInstanceState) {
tvCName = (TextView) view.findViewById(R.id.tvctq);
}
public void setTextViewText(String value){
tvCName.setText(value);
}
}
Fragment XML Layout:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.mytip.FragOne">
<TextView
android:text="TextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/tvctq" />
</FrameLayout>
I am trying to access the TextView inside the Fragment from MainActivity like this:
FragOne fo;
fo.setTextViewText("This is added from Activity");
I keep getting a NullPointerExceptionError. I looked at all the articles to see how to access, however none of them helped me.
Can someone please let me know what am I doing wrong and how to fix it?
I also plan on adding other Views inside my Fragment that I would need to access in the future.
Because fo hasn't been initialized in the following code snippet:
FragOne fo;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
fo.setTextViewText("This is added from Activity");
...
}
fo.setTextViewText() reasonably throws NPE.
You have to pay attention to the Activity lifecycle - you seem to be setting everything up correctly, but making a few mistakes accessing the correct instance of the fragment at the time it's actually ready. Things you should do
Get proper instance of the fragment from your ViewPager, like #ginomempin suggested;
Only try to set your text no earlier then your activities onStart method has been called - I usually do it onResume method (you can override it if you haven't already). Doing it in onResume method in the activity makes sure your Fragment has already gone through it's lifecycle up till onResume as well, and data will refresh if it has been brought to the background previously.
Here's a lifecycle diagram for your reference:
You need to use your Fragment factory method when creating your Fragment in your activity. Please see below:
**
Back Stack
**
The transaction in which fragments are modified can be placed on an internal back-stack of the owning activity. When the user presses back in the activity, any transactions on the back stack are popped off before the activity itself is finished.
For example, consider this simple fragment that is instantiated with an integer argument and displays that in a TextView in its UI:
public static class CountingFragment extends Fragment {
int mNum;
/**
* Create a new instance of CountingFragment, providing "num"
* as an argument.
*/
static CountingFragment newInstance(int num) {
CountingFragment f = new CountingFragment();
// Supply num input as an argument.
Bundle args = new Bundle();
args.putInt("num", num);
f.setArguments(args);
return f;
}
/**
* When creating, retrieve this instance's number from its arguments.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mNum = getArguments() != null ? getArguments().getInt("num") : 1;
}
/**
* The Fragment's UI is just a simple text view showing its
* instance number.
*/
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.hello_world, container, false);
View tv = v.findViewById(R.id.text);
((TextView)tv).setText("Fragment #" + mNum);
tv.setBackgroundDrawable(getResources().getDrawable(android.R.drawable.gallery_thumb));
return v;
}
}
A function that creates a new instance of the fragment, replacing whatever current fragment instance is being shown and pushing that change on to the back stack could be written as:
void addFragmentToStack() {
mStackLevel++;
// Instantiate a new fragment.
Fragment newFragment = CountingFragment.newInstance(mStackLevel);
// Add the fragment to the activity, pushing this transaction
// on to the back stack.
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.simple_fragment, newFragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();
}
After each call to this function, a new entry is on the stack, and pressing back will pop it to return the user to whatever previous state the activity UI was in.
Source: https://developer.android.com/reference/android/app/Fragment.html
You need to get the same instance of FragOne from the viewpager.
First, you can only access the FragOne instance after the ViewPager is setup.
Then, try this:
fo = adapter.getItem(0)
Note:
Since you already have fragments, it would be better to let the fragment itself handle the UI-related actions (such as setting the textview) rather than from the Activity.

Navigation drawer changes in rotation

I have two fragments MainFragment and First_Fragment. First fragment contains a video view but whenever I try to rotate, nav drawer always goes back to its main fragment. How could I save or restore my fragment state ? so it would stop going back to its main fragment.
Here's my code for the MainActivity
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
VideoView videoView;
NavigationView navigationView = null;
Toolbar toolbar = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MainFragment first = new MainFragment();
FragmentTransaction fragmentTransaction =
getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.content_frame, first);
fragmentTransaction.commit();
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) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
}
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_camera) {
// Handle the camera action
MainFragment first = new MainFragment();
FragmentTransaction fragmentTransaction =
getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.content_frame, first);
fragmentTransaction.commit();
} else if (id == R.id.nav_gallery) {
First_Fragment first = new First_Fragment();
FragmentTransaction fragmentTransaction =
getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.content_frame, first);
fragmentTransaction.commit();
} else if (id == R.id.nav_slideshow) {
}
When you're not handling the activity change like orientation, keyboard, etc. it will automatically recreates the activity. Therefore you're fragment does not save your previous instance. To solve that, I only encounter two solution.
The first one is already mentioned by Zeeshan that handle your orientation change by following this step:
Handle the orientation change in your AndroidManifest
<activity
android:name="com.example.Activity"
android:label="Activity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:windowSoftInputMode="stateHidden|adjustResize"
android:theme="#style/Theme.AppCompat.Light" />
Handle the event in the onConfiguration Change method
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
The second one is to save the fragment state. Refer here https://stackoverflow.com/a/17135346/5870896
You can do setRetainInstance(true) in your fragments, but a BottomNavigationBar will work incorrectly. In this case you can use some boolean flag in activity and save/restore it with Bundle like this:
In onCreate:
if (savedInstanceState != null) {
isMapFragmentVisible = savedInstanceState.getBoolean("isMainVisible");
} else {
navigator.navigateToFragment(fragmentLocation);
}
In onSavedInstanceState:
outState.putBoolean("isMainVisible", isMapFragmentVisible);
In onNavigationSelectedListener:
case R.id.bottom_navigation_map:
if (isMapFragmentVisible) {
break;
} else {
navigator.navigateToFragment(fragmentMap);
isMapFragmentVisible = true;
}
return true;
case R.id.bottom_navigation_location:
if (!isMapFragmentVisible) {
break;
} else {
navigator.navigateToFragment(fragmentLocation);
isMapFragmentVisible = false;
}
return true;
For me it works perfect. Are there any more elegant ways?
Activity recreates when you rotate the device. you need to mention in your manifest that you will handle the orientation change in your code so that system don't do it like this:
<activity name="MainActivity" android:configChanges="keyboardHidden|orientation|screenSize"/>
and then handle the event
#Override
public void onConfigurationChanged(Configuration newConfig) {
}
in your activity
Write this in manifests.xml
android:configChanges="orientation"
like this:-
<activity
android:name=".fragmentLayouts.MainActivity"
android:configChanges="orientation" />
Add this to your java code:-
#Override
public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
drawerListener.onConfigurationChanged(newConfig);
}

Categories