I've been wracking my brain for the greater part of the weekend, trying to solve an issue related to Android Studio. The assignment is to create a list fragment that will update when the user clicks buttons in the overhead bar, but despite my best efforts only one of the fragments actually displays (and it's the same no matter which button the user clicks). I've narrowed it down to the point where I'm fairly certain the problem has to do with the constructor's handling of bundles, but I'm not sure where the error is. Here's the related code:
public static ItemFragment newInstance(String title, int position) {
ItemFragment fragment = new ItemFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1,title);
args.putInt(ARG_PARAM2,position);
fragment.setArguments(args);
return fragment;
}
And later on, the call to getArguments():
public void onCreate(Bundle savedInstanceState) {
setRetainInstance(true);
if (getArguments() != null) {
mTitle=getArguments().getString(ARG_PARAM1);
mPosition=getArguments().getInt(ARG_PARAM2);
getActivity().setTitle(mTitle);
}
if (mPosition == 0) {
setListAdapter(new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, android.R.id.text1, listItems));
} else if (mPosition == 1) {
setListAdapter(new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, android.R.id.text1, newGoalItems));
} else if (mPosition == 2) {
setListAdapter(new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, android.R.id.text1, markProgressItems));
} else if (mPosition == 3) {
setListAdapter(new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, android.R.id.text1, settingsItems));
}
}
This is the related code in MainActivity:
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_list) {
list=ItemFragment.newInstance("List", 0);
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager
.beginTransaction();
fragmentTransaction.add(R.id.list_frame, new ItemFragment());
fragmentTransaction.commit();
}
else if (id==R.id.action_newGoal) {
newGoal=ItemFragment.newInstance("New Goal", 1);
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager
.beginTransaction();
fragmentTransaction.add(R.id.list_frame, new ItemFragment());
fragmentTransaction.commit();
}
else if (id==R.id.action_markProgress) {
markProgress=ItemFragment.newInstance("Mark Progress", 2);
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager
.beginTransaction();
fragmentTransaction.add(R.id.list_frame, new ItemFragment());
fragmentTransaction.commit();
}
else if (id==R.id.action_settings) {
settings=ItemFragment.newInstance("Settings", 3);
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager
.beginTransaction();
fragmentTransaction.add(R.id.list_frame, new ItemFragment());
fragmentTransaction.commit();
}
return super.onOptionsItemSelected(item);
}
I know from testing that the code simply crashes through the if statement above. What I don't know is why... It looks to me like there should be some values in getArguments that prevent it from returning null.
Write this piece of code in fragments onCreate method() it will work
if (getArguments() != null) {
mTitle=getArguments().getString(ARG_PARAM1);
mPosition=getArguments().getInt(ARG_PARAM2);
getActivity().setTitle(mTitle);
}
It sounds like you are trying to read the arguments in your Fragment's constructor. The context will not be established yet in the constructor, so you should be reading from the bundle in the onCreate() method.
public static Fragment newInstance(String title, int position) {
Fragment fragment = new ItemFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1,title);
args.putInt(ARG_PARAM2,position);
fragment.setArguments(args);
return fragment;
}
Change this line ItemFragment fragment = new ItemFragment(); to this Fragment fragment = new ItemFragment(); and all your code is perfect.
I finally figured this out! So the issue was that during the process of loading the fragments into the frame (the third section of code), the professor gave us a line of code that instantiated a new fragment instead of using the one that we'd just created a few lines above. I simply replaced
fragmentTransaction.add(R.id.list_frame, new ItemFragment());
with
fragmentTransaction.add(R.id.list_frame, list);
and now everything runs. Thanks for all the help everyone!
Related
I want to handle onBackPressed in fragment
I use following code in my activity but this return 0
#Override
public void onBackPressed() {
int count = getFragmentManager().getBackStackEntryCount();
Toast.makeText(getBaseContext(), ""+count, Toast.LENGTH_SHORT).show();
if (count == 1) {
super.onBackPressed();
//additional code
} else {
getFragmentManager().popBackStack();
}
}
Just add .addToBackStack(null) in your Activity or Fragment . When you adding or replacing fragment. Like below
getSupportFragmentManager().beginTransaction().replace(R.id.parent_layout, new MyFragment()).addToBackStack(null).commit();
Note:- you don't have to do anything in your onBackPressed() method.
Just app this line when you want to replace any fragment and manage backsack on Fragment.
ClientHome per = new ClientHome();
Bundle bundle = new Bundle();
bundle.putString("usertype", "client");
per.setArguments(bundle);
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.setCustomAnimations(R.anim.slide_from_left, R.anim.slide_to_right);
fragmentTransaction.replace(R.id.content_frame, per, "tag");
fragmentTransaction.addToBackStack("tag");
fragmentTransaction.commit();
Below is the adapter code of first fragment , here and sending data to second fragment StoreDetails.
holder.cv.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
StoreDetails fragment = new StoreDetails();
Bundle bundle = new Bundle();
bundle.putString("store_id",pojo.getSTORE_ID());
bundle.putString("store_name",pojo.getSTORE_NAME());
bundle.putString("address",pojo.getSTORE_ADDRESS());
// bundle.putString("status",pojo.getSTATUS());
// bundle.putString("teammember",pojo.getSTATUS());
fragment.setArguments(bundle);
FragmentManager manager=fragment.getFragmentManager();
// in below line I am getting error
FragmentTransaction ft = manager.beginTransaction().replace(R.id.container,fragment,"fragment");
ft.addToBackStack("fragment");
ft.commit();
}
});
Below is the StoreDetails fragment
Bundle bundle = getArguments();
mstore_id = bundle.getString("store_id");
mstore_name =bundle.getString("store_name");
mstoreaddress= bundle.getString("address");
mstorestatus = bundle.getString("status");
mteammember = bundle.getString("teammember");
The error I'm receiving is
java.lang.NullPointerException: Attempt to invoke virtual method
'android.app.FragmentTransaction
android.app.FragmentManager.beginTransaction()' on a null object
reference at Adapter.Tab1_Adapter$1.onClick(Tab1_Adapter.java:78)
FragmentManager will be null until it is attached to the activity.
instead of using
FragmentManager manager=fragment.getFragmentManager();
use
getActivity().getFragmentManager() or getActivity().getSupportFragmentManager();
My application had a bottom navigation bar which has 5 tabs.
So according to these tabs, I have 5 fragments
When I click on the tab, the fragment changed according to that tab.
I can switch fragment by using the method beginTransaction().replace...
I dont want the fragment to be destroyed and recreated again each time I switch tabs, so my solution is sth like this
//I init 5 fragments
Fragment1 frag1 = new Fragment1();
Fragment2 frag2 = new Fragment2();
Fragment3 frag3 = new Fragment3();
Fragment4 frag4 = new Fragment4();
Fragment5 frag5 = new Fragment5();
//When I click on tab, for example tab1, I hide all fragments except tab1
//hide all fragments
getSupportFragmentManager()
.beginTransaction()
.hide(fragment1) //Fragment2, 3, 4, 5 as well
.commit();
//show fragment 1
getSupportFragmentManager()
.beginTransaction()
.show(fragment1)
.commit();
It works very well, but the problem is sometimes 2 fragments show at once time (I dont know why because I hide all fragments)
Any other way to achieve that? Switch fragment without destroying it and creating it again.
for adding fragment I make this code for my project, hope it will be help.
public static void replaceFragment(Fragment fragment, FragmentManager fragmentManager) {
String backStateName = fragment.getClass().getName();
String fragmentTag = backStateName;
Fragment currentFrag = fragmentManager.findFragmentById(R.id.frame_container);
Log.e("Current Fragment", "" + currentFrag);
// boolean fragmentPopped = fragmentManager.popBackStackImmediate(backStateName, 0);
int countFrag = fragmentManager.getBackStackEntryCount();
Log.e("Count", "" + countFrag);
if (currentFrag != null && currentFrag.getClass().getName().equalsIgnoreCase(fragment.getClass().getName())) {
return;
}
FragmentTransaction ft = fragmentManager.beginTransaction();
// if (!fragmentPopped) {
ft.replace(R.id.frame_container, fragment);
ft.addToBackStack(backStateName);
ft.commit();
// }
currentFrag = fragmentManager.findFragmentById(R.id.frame_container);
Log.e("Current Fragment", "" + currentFrag);
}
hope this will be help you, and use this method in entire project for replacing fragment.
Using ViewPager with FragmentPagerAdapter suits for you in this case.
Then use ViewPager#setOffsetPageLimit(5). This will help you show/hide your fragments without recreating it again.
Follow this tutorial
Let try it, then tell me if your problem is solved or not. ;)
you don't have to need to hide the fragment just replace the fragment like this method:
public void setFragment(Fragment fragmentWhichYouWantToShow) {
fm = getSupportFragmentManager();
ft = fm.beginTransaction();
ft.replace(R.id.container, fragmentWhichYouWantToShow);
ft.commit();
}
Try to make it in a singe transaction.
protected void showAsRootFragment(Fragment fragment, #NonNull String tag) {
FragmentManager supportFragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = supportFragmentManager.beginTransaction();
if (supportFragmentManager.getFragments() != null) {
for (Fragment attachedFragment : supportFragmentManager.getFragments()) {
if (attachedFragment != null && !tag.equals(attachedFragment.getTag())) {
transaction.hide(attachedFragment);
attachedFragment.setUserVisibleHint(false);
}
}
}
if (!fragment.isAdded()) {
transaction.add(R.id.frame_container, fragment, tag);
fragment.setUserVisibleHint(true);
} else {
transaction.show(fragment);
fragment.setUserVisibleHint(true);
}
transaction.commit();
}
I find myself switching between a lot of Fragments in my card game app.
When my user creates a deck he goes through the following fragments:
Deck List Fragment (Click on 'New Deck') -> Class Selection Fragment (Mage, Warrior etc.) -> Name Selection Fragment -> Back to Deck List Fragment with our new deck listed.
I do this in order to have a smooth deck creation process but here are my two questions:
1) Is it recommended to use more Fragments than required if it makes the UX better and smoother?
2) Note that I do the following in order to switch Fragment:
Fragment fragment = new MyFragment();
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
// Set argument(s) - Not all fragments set arguments
Bundle args = new Bundle();
args.putString("deckName", deckName);
fragment.setArguments(args);
fragmentTransaction.replace(R.id.content_frame, fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
Instead of having similar methods from one Fragment to the other, I wish to create a generic method that takes a variable amount of parameters and the type of Fragment to create and switches to said Fragment.
But I can't seem to figure out how to do it.
Please excuse this lengthy post, and thank you.
Check out my code :
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
replaceFragment(new HomeFragment());
}
public void replaceFragment(final Fragment fragment) {
getFragmentManager()
.beginTransaction()
.replace(R.id.container, fragment, fragment.getClass().getSimpleName())
.commit();
}
public void addFragment(final Fragment fragment) {
final Fragment hideFragment = getFragmentManager().findFragmentById(R.id.container);
getFragmentManager()
.beginTransaction()
.add(R.id.container, fragment, fragment.getClass().getSimpleName())
.hide(hideFragment)
.addToBackStack(hideFragment.getClass().getSimpleName())
.commit();
}
}
Call above methods in Fragment :
final HomeFragment homeFragment = new HomeFragment();
final Bundle bundle = new Bundle();
bundle.putString("KEY","VALUE");
homeFragment.setArguments(bundle);
((MainActivity) getActivity()).addFragment(homeFragment);
I'm learning from the book from big nerd ranch.
FragmentManager fm = getFragmentManager();
Fragment fragment = fm.findFragmentById(R.id.fragmentContainer);
if (fragment == null) {
fragment = new CrimeFragment();
fm.beginTransaction().add(R.id.fragmentContainer, fragment).commit();
}
Got a type mismatch error.
However, if I call
CrimeFragment fragment = fm.findFragmentById(R.id.fragmentContainer);
it will not work. So my question is how to call a CustomFragment(CrimeFragment) using an id from the layout?
Thanks in advance.
I usually do it like this:
CrimeFragment fragment = new CrimeFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragmentContainer, fragment).commit();
or
transaction.add(R.id.fragmentContainer, fragment).commit();
More information:
The screen orientation change will cause the fragment update once more if it is create in onCreate method.
you can prevent this here:
if (savedInstanceState == null){
CrimeFragment fragment = new CrimeFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragmentContainer, fragment, "fragment").commit();
}else{
CrimeFragment homeFragment = (CrimeFragment) getSupportFragmentManager().findFragmentByTag("fragment");
}