I have one User Activity class which has drawer menu (includes home page, my profil etc..). When user clicks the one of the menu item, I will load fragment such as HomePageFragment, MyProfilFragment etc..
Here is the code example:
public void navigationItemSelectedListener(DrawerLayout drawerLayout, NavigationView navigationView) {
navigationView.setNavigationItemSelectedListener(menuItem -> {
menuItem.setChecked(true);
int menuId = menuItem.getItemId();
switch (menuId){
case R.id.home_menu_item:
loadFragment(new HomePageFragment());
break;
// goes like that
Here is the loadFragment:
public void loadFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.user_page_activity_frame_layout, fragment);
fragmentTransaction.commit();
}
}
Now I have run CountDownTimer(60 seconds) in HomePageFragment, when counter is 0, I will run some methods().
However I can not do that. Because each time user navigates new item, then when back to the HomePage menu item, new HomePageFragment() is creating, therefore CountDownTimer starts with 60s again and again. What I want CounDownTimer to run even if user navigates another menu.
Note that, I had tried to create HomePageFragment attribute as global. But it didn't work. (Like 2 timer counts down. One says 60-59... another says 30-29 ...)
Problem here is, your Fragment gets destroyed every time user navigates to another item.
To solve this
1.Either Create the Timer in your host activity instead the fragment, maybe inside navigationItemSelectedListener()
2.Make sure your fragment doesn't get destroyed everytime. Check How to resume Fragment from BackStack if exists
Related
Apparently I have a scenario where my launcher activity is splash screen which contains a handler class to show animation on start.
handler.postDelayed(new Runnable() {
#Override
public void run() {
//animation coder inside
}, 5);
After it is launched the app then navigates to next activity i.e. Home Activity. This activity is basically a fragment loader where I have a custom top bar, frame layout (to load fragment in it) and BottomAppBar. Now on main method I'm intialising all the ids and calling two methods i.e. loadFrag() which loads default fragment to display when home activity is first loaded and clicklisteners() which contains click listener implementation of image views and bottom navigation view included in top and bottom bar.
public void loadFrag() {
HomeFrag = new HomeFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.frameLayout, HomeFrag,
HomeFrag.getClass().getSimpleName()).addToBackStack("fragment").commit();
}
public void clickListeners() {
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#SuppressLint("NonConstantResourceId")
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
/* when user opens home fragment, title and back button will be set to gone
in order to display his location on home */
case R.id.homePage:
Fragment fragment = new HomeFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.frameLayout, fragment,
fragment.getClass().getSimpleName()).commit();
iv_location.setVisibility(View.VISIBLE);
tv_location.setVisibility(View.VISIBLE);
iv_edit.setVisibility(View.VISIBLE);
tv_title.setVisibility(View.GONE);
iv_back.setVisibility(View.GONE);
currentFragment = fragment;
break;
/* when user opens wallet fragment, location and edit location icon will be set to gone
in order to display tab title and back icon inside wallet fragment */
case R.id.wallet:
Fragment fragment1 = new WalletFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.frameLayout, fragment1,
fragment1.getClass().getSimpleName()).commit();
iv_location.setVisibility(View.GONE);
tv_location.setVisibility(View.GONE);
iv_edit.setVisibility(View.GONE);
tv_title.setVisibility(View.VISIBLE);
iv_back.setVisibility(View.VISIBLE);
tv_title.setText("Wallet");
currentFragment = fragment1;
break;
/* when user opens myorders fragment, location and edit location icon will be set to gone
in order to display tab title and back icon inside myorders fragment */
case R.id.myorders:
Fragment fragment3 = new MilkCheeseAndYogurtFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.frameLayout, fragment3,
fragment3.getClass().getSimpleName()).commit();
iv_location.setVisibility(View.GONE);
tv_location.setVisibility(View.GONE);
iv_edit.setVisibility(View.GONE);
tv_title.setVisibility(View.VISIBLE);
iv_back.setVisibility(View.VISIBLE);
tv_title.setText("My Orders");
currentFragment = fragment3;
break;
/* when user opens search fragment, location and edit location icon will be set to gone
in order to display tab title and back icon inside search fragment */
case R.id.search:
Fragment fragment4 = new MilkAndMilkPowderFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.frameLayout, fragment4,
fragment4.getClass().getSimpleName()).commit();
iv_location.setVisibility(View.GONE);
tv_location.setVisibility(View.GONE);
iv_edit.setVisibility(View.GONE);
tv_title.setVisibility(View.VISIBLE);
iv_back.setVisibility(View.VISIBLE);
tv_title.setText("Search");
currentFragment = fragment4;
break;
}
return true;
}
});
Now this all is happening on a single thread which is displaying home fragment after a delay of 2-6 seconds approximately on cold start. I have read about AsyncTask and Threads too but I'm unable to find any proper tutorial or code to take hint on how to implement it. If there's any approach better than that please let me know. Ask more if my question is still not clear.
I'm starting to work with fragments and ran into a problem. I have file viewing fragments(more than one) and a search fragment. To make things easier I add my file viewing fragment to backstack whenever I go to search so I could easily pop it back if I decide to just close it. Now the problem is that when I press on file in the search fragment so that I travel to the specific fragment in which that file is, the onCreateView of the first fragment(which was in backstack) always gets called even though I replaced it(?) and I don't want that. Here are things I do to change the fragments on search file press:
1.I call pop to get to previous fragment
#Override
public boolean onSearchViewClose() {
if (getActivity() != null) {
getActivity().getSupportFragmentManager().popBackStack();
return true;
}
return false;
}
2. Then I replace the remaining fragment
public void setFragment(Fragment fragment, String tag, boolean clearBackStack, boolean addToBackStack) {
// Insert the fragment by replacing any existing fragment
hideLoadingProgress();
FragmentManager fragmentManager = getSupportFragmentManager();
if (clearBackStack) {
clearBackStack(fragmentManager);
}
FragmentTransaction transaction = fragmentManager.beginTransaction().replace(R.id.content_frame, fragment, tag);
if (addToBackStack) {
transaction.addToBackStack(null);
}
transaction.commit();
}
while clearing backstack:
public void clearBackStack(FragmentManager fragmentManager) {
for (int i = 0; i < fragmentManager.getBackStackEntryCount(); ++i) {
fragmentManager.popBackStack();
}
}
Even if I don't clear backstack the problem persists.Thanks for your answers in advance.
The answer was simple - I should've just used getActivity().getSupportFragmentManager().popBackStackImmediate(); when exiting search view as the earlier method didn't work because it waited for program to return to its event loop (asynchronous).
When the map fragment opens for the first time it calls onMapReady and it adds a marker in there and zooms towards with animation.
I want if user click a button on the map, the map will restart as if its open like the begining with zoom and whatnot.
I tried using the method below which I call when I click the button, but it only recreate the map but it didn't call onMapReady because it didn't add maker or anything.!
public void reLoadFragment(Fragment fragment) {
Fragment currentFragment = fragment;
if (currentFragment instanceof MapTransportFragment_BusDriver) {
FragmentTransaction fragTransaction = getActivity().getSupportFragmentManager().beginTransaction();
fragTransaction.detach(currentFragment);
fragTransaction.attach(currentFragment);
fragTransaction.commit();
}
}
Edit #1
I call the method using all three ways belowa and it gives me the same error.
/*1*/ reLoadFragment(this);
/*2*/ reLoadFragment(MyMap.this);
/*3*/ reLoadFragment(new MyMap()); // MyMap is the name of the current fragment.
However, If you want just to restart your fragment it means you want to create new fragment. calling detach and attach doesn't destroy fragment.So try below code
public void reLoadFragment(Fragment fragment) {
Fragment currentFragment = fragment;
if (currentFragment instanceof MapTransportFragment_BusDriver) {
FragmentTransaction fragTransaction = getActivity().getSupportFragmentManager().beginTransaction();
fragTransaction.replace(R.id.YourFragmentContainer,currentFragment,"TAG");
fragTransaction.commit();
}
}
I'm running into trouble. I have a Fragment with an onclicklistener. The fragment calls "ClickMe" which is in my Activity that hosts the fragment. However, in order for ClickMe to not error out, ClickMe has to be static. But, Clickme can't be static because then getFragmentManager errors out. Essentially I'm trying to create a game. A click will put a new fragment over the top of the old one (as you have to do the same thing 10 times in a row in my game. Here's the code:
Fragment:
text1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(loc1 == 10 || loc2 ==10){
//Text if user wins
BlankFragment.counter ++;
BlankFragment.ClickMe(BlankFragment.counter);
Log.i("Win: ", "Yay");
}else{
//Text if user loses
Log.i("Lose: ", "Boo");
}
}
});
MainActivity:
public void ClickMe(int count){
Fragment newFragment;
counter = count;
if(counter > 5){
newFragment = new g3by3Fragment();
}else{
newFragment = new g3by3Fragment();
}
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.container, newFragment);
transaction.addToBackStack(null);
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
transaction.commit();
Thank you for your help!
You don't have to preform FragmentTransactions from the Activity. You can just add well preform them from the Fragment. Your detour into the Activity through ClickMe is unnecessary. I know you probably do this because the logic of your game is in the Activity but that is not optimal. Let the Fragments themselves decide which Fragment comes next or implement a Singleton which takes care of your game logic.
I have an Android application with a MainActivity and I do this to create navigational tabs in onCreate:
ActionBar myActionBar = getActionBar();
myActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
Tab tab = myActionBar.newTab().setText("FirstTab").setIcon(R.drawable.first_tab)
.setTabListener(new TabListener<FirstTabFragment>(this, "FirstTab",
FirstTabFragment.class));
... more tabs ...
The TabListener, I use this from developer.android.com:
http://developer.android.com/reference/android/app/ActionBar.html#newTab():
public static class TabListener<T extends Fragment> implements ActionBar.TabListener {
...
public TabListener(Activity activity, String tag, Class<T> clz) { ... }
}
So if a user clicks on the first tab, my fragment FirstTabFragment is called and executes onCreateView.
My problem is, if a user now clicks a button I do the following and I do not know how to switch to the next fragment:
private OnClickListener firstTabListener = new OnClickListener() {
#Override
public void onClick(View v) {
if (v == button1) {
Intent intent = new Intent(???, MyDetailsFragment.class);
startActivity(intent);
} else if (...) {
...
}
}
};
The MyDetailsFragmentshould show details to the selected item (button click), so I want to drill down to the details fragment and want to give some extra data to the new fragment, so the detail fragment knows which details of which selected item it should display.
The selected tab should not change and the back button should go back to the FirstTabFragment page.
I think I should start a new fragment, but it is not possible, the name of the method startActivity tells me that I start a new activity and not a fragment. So, I have to use the MainActivity and put into there the new fragment?
(I do not use the android-support-v4.jar library, because I only target Android 4 devices)
How can I solve this problem? Any ideas?
From the fragment, call a method on the hosting activity, telling it about the button click event. The activity can then do whatever is appropriate.
Personally, I think that totally replacing the contents of a tab is inappropriate in the vast majority of cases, but you are certainly welcome to do it.