Map fragment is not hidden when switch between fragments Android Studio - java

I'm trying to switch between fragments using a bottom navigation. However, if I switch to other fragments from the map fragment, the map fragment is still in the background while other fragment is being shown on the front.
Please see my code here:
public class MainActivity extends AppCompatActivity {
private FragmentManager fragmentManager;
private Fragment messageFragment = new MessageFragment();
private Fragment mapFragment = new MapsFragment();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().add(R.id.hostFragment, mapFragment, null).commit();
fragmentManager.beginTransaction().add(R.id.hostFragment, messageFragment, null).commit();
BottomNavigationView bottomNavigationView = findViewById(R.id.bottomNavigationView);
//bottomNavigationView.setSelectedItemId(R.id.mapsFragment);
bottomNavigationView.setOnNavigationItemSelectedListener(navListener);
}
private BottomNavigationView.OnNavigationItemSelectedListener navListener = new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.mapsFragment:
fragmentManager.beginTransaction().hide(messageFragment).show(mapFragment).commit();
break;
case R.id.messageFragment:
fragmentManager.beginTransaction().hide(mapFragment).show(messageFragment).commit();
break;
}
return true;
}
};
}

Your Problem
You are adding both fragments to the same container, R.id.hostFragment.
fragmentManager.beginTransaction().add(R.id.hostFragment, mapFragment, null).commit();
fragmentManager.beginTransaction().add(R.id.hostFragment, messageFragment, null).commit();
Per the documentation for hide and show, this means that you are hiding and then showing the same container.
A Solution
Use two different container views:
fragmentManager.beginTransaction().add(R.id.mapContainer, mapFragment, null).commit();
fragmentManager.beginTransaction().add(R.id.messageContainer, messageFragment, null).commit();
Another Solution
Use replace instead of hiding and showing.
fragmentManager.beginTransaction().add(R.id.hostFragment, mapFragment, null).commit();
// Don't add this in `onCreate`
// fragmentManager.beginTransaction().add(R.id.hostFragment, messageFragment, null).commit();
...
// Replace the fragment currently being displayed
switch (item.getItemId()) {
case R.id.mapsFragment:
fragmentManager.beginTransaction().replace(R.id.hostFragment, mapFragment).commit();
break;
case R.id.messageFragment:
fragmentManager.beginTransaction().replace(R.id.hostFragment, messageFragment).commit();
break;
}

Related

BottomNavigation, FragmentManager has not been attached to a host

I have moved BottomNavigation codes from MainActivity to A class I have created for the BottomNaviction to make the code more organizing. When I moved the codes I got this error java.lang.RuntimeException: Unable to start activity ComponentInfo{com.moataz.mox/com.moataz.mox.ui.view.activity.MainActivity}: java.lang.IllegalStateException: FragmentManager has not been attached to a host. Short error message FragmentManager has not been attached to a host.
And The error In this line of code
// The error is here
final FragmentManager fragmentManager = fragmentActivity.getSupportFragmentManager();
Here's My BottomNavigation Class
public class BottomNavigation extends BottomNavigationView {
FragmentActivity fragmentActivity = new FragmentActivity();
final Fragment homeFragment = new HomeFragment();
final Fragment searchFragment = new SearchFragment();
final Fragment videosFragment = new VideosFragment();
final Fragment favouriteFragment = new FavouriteFragment();
final Fragment premiumFragment = new PremiumFragment();
// The error is here
final FragmentManager fragmentManager = fragmentActivity.getSupportFragmentManager();
Fragment mainFragment = homeFragment;
public BottomNavigation(#NonNull Context context) {
super(context);
}
#SuppressLint("NonConstantResourceId")
public void initializeBottomNavigation() {
// first one transaction to add each Fragment
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.fragment_layout, premiumFragment, "5").hide(premiumFragment);
fragmentTransaction.add(R.id.fragment_layout, favouriteFragment, "4").hide(favouriteFragment);
fragmentTransaction.add(R.id.fragment_layout, videosFragment, "3").hide(videosFragment);
fragmentTransaction.add(R.id.fragment_layout, searchFragment, "2").hide(searchFragment);
fragmentTransaction.add(R.id.fragment_layout, homeFragment, "1");
// commit once! to finish the transaction
fragmentTransaction.commit();
// show and hide them when click on BottomNav items
BottomNavigationView navigationView = findViewById(R.id.bottom_navigation);
navigationView.setOnItemSelectedListener(item -> {
// start a new transaction
FragmentTransaction localFragmentTransaction = fragmentManager.beginTransaction();
// TODO: ADD Animations
switch (item.getItemId()) {
case R.id.home_item:
localFragmentTransaction.hide(mainFragment).show(homeFragment).commit();
mainFragment = homeFragment;
return true;
case R.id.search_item:
localFragmentTransaction.hide(mainFragment).show(searchFragment).commit();
mainFragment = searchFragment;
return true;
case R.id.videos_item:
localFragmentTransaction.hide(mainFragment).show(videosFragment).commit();
mainFragment = videosFragment;
return true;
case R.id.saved_item:
localFragmentTransaction.hide(mainFragment).show(favouriteFragment).commit();
mainFragment = favouriteFragment;
return true;
case R.id.premium_item:
localFragmentTransaction.hide(mainFragment).show(premiumFragment).commit();
mainFragment = premiumFragment;
return true;
}
return false;
});
}
And here I haved Called my class and method In MainActivity
private void initializeBottomNavigation() {
BottomNavigation bottomNavigation = new BottomNavigation(this);
bottomNavigation.initializeBottomNavigation();
}
I have tried to find a sloution and anderstand the error but I didn't found sothing In my case. So what is the problem here and How can I fix It?
You cannot make a new instance of an activity; activity instances are built only by Android itself. The only thing you can do in order to obtain an activity reference is to use an existing one.
public class BottomNavigation extends BottomNavigationView {
final FragmentActivity fragmentActivity;
...
final FragmentManager fragmentManager;
public BottomNavigation(#NonNull Context context, #NonNull FragmentActivity activity) {
super(context);
fragmentActivity = activity;
fragmentManager = fragmentActivity.getSupportFragmentManager();
}
...
}
And pass your existing reference of your activity:
private void initializeBottomNavigation() {
FragmentActivity activity = this; // Or your activity reference
BottomNavigation bottomNavigation = new BottomNavigation(this, activity);
bottomNavigation.initializeBottomNavigation();
}
Note that you still need to attach your BottomNavigation to a view parent in the activity to make it visible.

Unable to set text in fragment

I am trying to call a function from my mainActivity to change a TextView in one of my fragments. I have read a couple posts on the best way of doing it but for some reason, none of them seem to work for me. I know the function is working because once a press the button the toast comes up but for some reason the text won't change. I was wondering what the issue could be, or if I am just missing an additional step.
here is the method being called in my mainActivity
public class MainActivity extends AppCompatActivity implements Tab1Fragment.OnCalcClickListener{
private static final String TAG = "MainActivity";
private SectionsPageAdapter mSectionsPageAdpater;
private ViewPager mViewPager;
Tab1Fragment tab1Fragment = new Tab1Fragment();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate: Starting");
//initializing FragmentManager so the fragments can communicate
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.container, tab1Fragment);
fragmentTransaction.commit();
//declare sections page adapter
mSectionsPageAdpater = new SectionsPageAdapter(getSupportFragmentManager());
//Set up the view pager with the sections adapter
mViewPager = (ViewPager) findViewById(R.id.container);
setUpViewPager(mViewPager);
//create a tab layout object and set it's id to tabs (mainActivity.xml)
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
//
}
// create a sections page view adapter
private void setUpViewPager(ViewPager viewPager){
SectionsPageAdapter adapter = new SectionsPageAdapter(getSupportFragmentManager());
adapter.addFragment(new Tab1Fragment(), "Day");
adapter.addFragment(new Tab2Fragment(), "Info");
adapter.addFragment(new Tab3Fragment(), "Week");
viewPager.setAdapter(adapter);
}
//initialise calculator object
Calculator mainCalculator = new Calculator();
#Override
public void calculateClick(int to_calculate) {
switch (to_calculate){
case 1:
Toast.makeText(getBaseContext(),"working", Toast.LENGTH_SHORT).show();
mainCalculator.freqDay = mainCalculator.freqDay + 1;
mainCalculator.freqWeek = mainCalculator.freqWeek + 1;
mainCalculator.getTotalDay();
tab1Fragment.updateInfo();
break;
}
}
Here is the code for my fragment
public class Tab1Fragment extends Fragment implements
View.OnClickListener{
private static final String TAG = "Tab1Fragment";
//Establishing the buttons & Methods
Button btn1;
Button btn2;
TextView dayView;
OnCalcClickListener onCalcClickListener;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.tab1_fragment, container, false);
//Connecting the buttons to the xml
btn1 = (Button) view.findViewById(R.id.btn_1);
btn1.setOnClickListener(this);
btn2 = (Button) view.findViewById(R.id.btn_2);
btn2.setOnClickListener(this);
dayView = (TextView) view.findViewById(R.id.total_Sales_Day);
return view;
}
//Onclick listener for buttons
public void setOnClickListener(View.OnClickListener listener) {
btn1.setOnClickListener(listener);
btn2.setOnClickListener(listener);
}
//method that will bring data back from activity and set the text
public void updateInfo(){
Toast.makeText(getContext(),"65", Toast.LENGTH_SHORT).show();
dayView.setText("test");
}
To make calls to methods from your fragment in the activity class you need something like this:
public static class MainActivity extends Activity
implements HeadlinesFragment.OnHeadlineSelectedListener{
...
public void onArticleSelected(int position) {
// The user selected the headline of an article from the HeadlinesFragment
// Do something here to display that article
ArticleFragment articleFrag = (ArticleFragment)
getSupportFragmentManager().findFragmentById(R.id.article_fragment);
if (articleFrag != null) {
// If article frag is available, we're in two-pane layout...
// Call a method in the ArticleFragment to update its content
articleFrag.updateArticleView(position);
} else {
// Otherwise, we're in the one-pane layout and must swap frags...
// Create fragment and give it an argument for the selected article
ArticleFragment newFragment = new ArticleFragment();
Bundle args = new Bundle();
args.putInt(ArticleFragment.ARG_POSITION, position);
newFragment.setArguments(args);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack so the user can navigate back
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
}
}
}
Here the activity is calling the updateArticleView method from the fragment, instead of your updateInfo method, but you will get the idea.
Also pay attention to the one-pane scenario, where you need to swap the content and push the arguments using a Bundle object.
See Deliver a Message to a Fragment for more details.
When you add the fragment set a tag to it like this:
MyFragment frag = new MyFragment();
frag.setArguments(getIntent().getExtras());
getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, frag, "TAG").commit();
While updating the textview get the instance of fragment using findFragmentByTag()
MyFragment fragment = (MyFragment) getSupportFragmentManager().findFragmentByTag("TAG");
fragment.updateInfo();

ButterKnife doesn't bind views after syncing gradle - NullPointerException

I have a problem with ButterKnife library. My views stopped binding after syncing gradle - before it was working without any problem.
I attached some code.
build.gradle (app)
compile 'com.jakewharton:butterknife:8.6.0'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.6.0'
MainActivity
public class MainActivity extends AppCompatActivity {
#BindView(R.id.navigation)
BottomNavigationView navigation;
private Fragment fragment;
private FragmentManager fragmentManager;
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_home:
fragment = new HomeFragment();
break;
case R.id.navigation_dashboard:
fragment = new GraphFragment();
break;
case R.id.navigation_notifications:
fragment = new ProfileFragment();
break;
}
final FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.content, fragment).commit();
return true;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.setDebug(true);
ButterKnife.bind(this);
fragmentManager = getSupportFragmentManager();
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
}}
ButterKnife logs
D/ButterKnife: Looking up binding for
com.example.azkb.instproject.refactor.MainActivity D/ButterKnife: Not
found. Trying superclass android.support.v7.app.AppCompatActivity
D/ButterKnife: MISS: Reached framework class. Abandoning search.
The problem occured when I added Kotlin to my project.
Solution:
kapt 'com.jakewharton:butterknife-compiler:8.7.0'
Thanks for downvoting :)

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.

Set a ContentView in the navigationdrawer

I'm kinda new into android programming, and I couldn't find the answer on the internet.
I have set up a Navigation drawer in Android Studio, and I want to change the content view if that section is selected, for example, if I select a view "Tools" in the navigation drawer, I want that you can see the layout "Tools" but that you also can go back to the navigation drawer. I have tried to put setContentView into the case 1, etc but that gave an error.
I have tried this code for the setContentView:
public class MainActivity extends Activity
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)
getFragmentManager().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
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.container, PlaceholderFragment.newInstance(position + 1))
.commit();
}
public void onSectionAttached(int number) {
switch (number) {
case 1:
//This is where I thought I could implement the setContentView
setContentView(R.layout.activity_tools);
mTitle = "Tools";
break;
case 2:
mTitle = "Weapons";
break;
case 3:
mTitle = "Mobs";
break;
case 4:
mTitle = "Food";
break;
case 5:
mTitle = "Blocks";
break;
}
}
ContentView is not what you want to change on drawer item selection. ContentView sets your activity layout (the one which holds NavigationDrawer view). What you really want is to replace fragments.Lets say you have a different fragment with its own layout for every item in the navigation menu. In this case you could implement something like:
public void onNavigationDrawerItemSelected(int position) {
Fragment fragment;
Bundle args = new Bundle();
String tag;
switch (position) {
case 1:
fragment = new FragmentTools();
tag = "Tools";
args.putString(KEY_FRAGMENT_TITLE, tag);
break;
case 2:
fragment = new FragmentWeapons();
tag = "Weapons";
args.putString(KEY_FRAGMENT_TITLE, tag);
break;
case 3:
...
}
FragmentTransaction transaction = getFragmentManager().beginTransaction();
fragment.setArguments(args);
transaction.replace(R.id.fragment_container, fragment, tag);
transaction.commit();
}
The above is just an example. You select which fragment to show and set its arguments. Of cource it could be the same fragment with different layouts. In that case you could pass layout id as an argument, or select appropriate layout in Fragment itself based on its title.

Categories