I want to make a factory method in java class then call that method in activity to loading multiple fragments.
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.Men: {
FirstFragment firstfragment = new FirstFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, firstfragment);
transaction.commit();
break;
case R.id.Men: {
SecondFragment secondfragment = new SecondFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, secondfragment);
transaction.commit();
break;
}
}
static factory method, you can simply keep everything in fragment and no need to expose. Whoever needs to use this fragment will have a clear idea what it requires and also will not need to know what keys are. Just send the required params will be enough for them.
class FragmentFoo extends Fragment{
private static final String KEY_NAME = "name";
private String name;
public static Fragment newInstance(String name){
Bundle bundle = new Bundle();
bundle.putString(KEY_NAME, "name");
Fragment fragment = new FragmentFoo();
fragment.setArgs(bundle);
return fragment;
}
}
Related
My bottom navigation view not working. When i click on items my fragment in not loading.
beginTransaction() may produce NullPointerException.
This is my Activity :
public static void enableNavigation(Context context, final BottomNavigationViewEx view, final FragmentManager supportFragmentManager){
view.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment fragment;
switch (item.getItemId()){
case R.id.nav_home:
fragment = new FragmentMarker();
loadFragment(fragment);
return true;
case R.id.nav_bookmark:
fragment = new FragmentBookmark();
loadFragment(fragment);
return true;
case R.id.nav_blog:
fragment = new FragmentBlog();
loadFragment(fragment);
return true;
case R.id.nav_notification:
fragment = new FragmentNotification();
loadFragment(fragment);
return true;
case R.id.nav_account:
fragment = new FragmentAccount();
loadFragment(fragment);
return true;
}
return false;
}
private void loadFragment(Fragment fragment) {
// load fragment
FragmentTransaction transaction = fragment.getFragmentManager().beginTransaction();
transaction.replace(R.id.container, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
});
And this is one of my fragments :
private void setupBottomNavigationView(){
Log.d(TAG, "setupBottomNavigationView: Setting up BottomNavigationView");
BottomNavigationViewEx bottomNavigationViewEx = getView().findViewById(R.id.bottom_navigation);
BottomNavigationViewHelper.setupBottomNavigationView(bottomNavigationViewEx);
BottomNavigationViewHelper.enableNavigation(getContext(), bottomNavigationViewEx, getFragmentManager());
Menu menu = bottomNavigationViewEx.getMenu();
MenuItem menuItem = menu.getItem(ACTIVITY_NUM);
menuItem.setChecked(true);
}
I think you may be getting NullPointerException because you are trying to access a fragment's fragment manager before it has been allocated to one in the first place.
So, you need to use the one provided by the activity. So inside your loadFragment method do the following:
Before:
private void loadFragment(Fragment fragment) {
// load fragment
FragmentTransaction transaction = fragment.getFragmentManager().beginTransaction();
transaction.replace(R.id.container, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
After:
private void loadFragment(Fragment fragment) {
// load fragment
FragmentTransaction transaction = supportFragmentManager.beginTransaction();
transaction.replace(R.id.container, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
/**
* Return the FragmentManager for interacting with fragments associated
* with this fragment's activity. Note that this will be non-null slightly
* before {#link #getActivity()}, during the time from when the fragment is
* placed in a {#link FragmentTransaction} until it is committed and
* attached to its activity.
*
* <p>If this Fragment is a child of another Fragment, the FragmentManager
* returned here will be the parent's {#link #getChildFragmentManager()}.
*/
#Nullable
final public FragmentManager getFragmentManager() {
return mFragmentManager;
}
Your fragmentmanger returns null if you try to get fragmentmanager from fragment that is not attched to activity. So change your code
FragmentTransaction transaction = fragment.getFragmentManager().beginTransaction();
To
FragmentTransaction transaction = getFragmentManager().beginTransaction();
I have a fragment activity from where i can start my fragments which contain a viewpager. In my fragment activity I have added this piece of code.
fragment = new ItemPagerFragment();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.content_frame, fragment);
transaction.addToBackStack(null);
transaction.commit();
Now when I press back button only blank screen appears and it does not lead me to my fragment activity.
What wrong i might be doing?
Use this in activity that holds fragment.
#Override
public void onBackPressed() {
if (fragmentManager.getBackStackEntryCount() > 1) {
fragmentManager.popBackStack();
} else
finish();
}
Try this way,
// Create new fragment and transaction
Fragment newFragment = new ItemPagerFragment();
// consider using Java coding conventions (upper first char class names!!!)
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.content_frame, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
Modify your code
#Override
public void onBackPressed() {
if(some condition) {
// do something
} else {
super.onBackPressed();
}
}
Please follow this link
Handling back button press Inside Fragments
You have to tell to the fragment manager that the back button was pressed. Override onBackPressed on your Activity
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() == 0) {
super.onBackPressed();
} else {
getFragmentManager().popBackStack();
}
}
private void changeFragment (Fragment fragment){
String backStackName = fragment.getClass().getName();
FragmentManager manager = getSupportFragmentManager();
boolean fragmentPopped = manager.popBackStackImmediate (backStackName, 0);
if (!fragmentPopped){ //fragment not in back stack, create it.
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.addToBackStack(backStackName );
ft.commit();
}
}
While launching fragment assign a TAG to each fragment.When you want to back press check the existence of an fragment using assigned TAG name and then do corresponding action.for example:
private final static String TAG_FRAGMENT = "TAG_FRAGMENT";
//when want to add fragment to view
private void showFragment() {
final Myfragment fragment = new MyFragment();
final FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment, fragment, TAG_FRAGMENT);
transaction.addToBackStack(null);
transaction.commit();
}
//in activity back pressed check the existence of fragment by TAG
#Override
public void onBackPressed() {
final Myfragment fragment = (Myfragment) getSupportFragmentManager().findFragmentByTag(TAG_FRAGMENT);
if (fragment.allowBackPressed()) { // and then you define a method allowBackPressed with the logic to allow back pressed or not
super.onBackPressed();
}
}
So I have my navigation drawer with 5 different options. They all open a new fragment that I have created. The first one is Home, and I am trying to find a way to bring it back to the first screen that shows up under the navigation drawer. It has the id of "container", in the main_activity.xml. I do not want to use and intent to call the entire class again to load up. Also I do not want to be able to use the back button from another intent. I am confused on how to make this happen.
#Override
public void onNavigationDrawerItemSelected(int position) {
FragmentHowItWorks fragmentHow;
FragmentSettings fragmentSettings;
FragmentTransaction transaction = getFragmentManager().beginTransaction();
switch(position){
case 0:
// should I call the layout?
// this is the "Home" option
break;
case 1:
fragmentHow = new FragmentHowItWorks();
transaction.replace(R.id.container, fragmentHow);
transaction.addToBackStack(null);
transaction.commit();
break;
case 2:
fragmentSettings = new FragmentSettings();
transaction.replace(R.id.container, fragmentSettings);
transaction.addToBackStack(null);
transaction.commit();
break
case 3:
fragment = new FragmentHowItWorks();
transaction.replace(R.id.container, fragment);
transaction.addToBackStack(null);
transaction.commit();
break;
case 4:
fragment = new FragmentHowItWorks();
transaction.replace(R.id.container, fragment);
transaction.addToBackStack(null);
transaction.commit();
break;
}
}
Use methods add,hide and show,
Step1 Prepare all your fragments
Fragment fragment1 = new FragmentOne();
Fragment fragment2 = new FragmentTwo();
Fragment fragment3 = new FragmentThree();
Fragment mCurrentFragment = null;
Step2 Show/hide your fragments
#Override
public void onNavigationDrawerItemSelected(int position) {
Fragment fragment;
switch (position) {
case 1:
fragment = fragment1;
break;
case 2:
fragment = fragment2;
break;
case 3:
fragment = fragment3;
break;
}
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
if(mCurrentFragment == null) {
ft.add(R.id.container, fragment).commit();
mCurrentFragment = fragment;
} else if(fragment.isAdded()) {
ft.hide(mCurrentFragment).show(fragment).commit();
} else {
ft.hide(mCurrentFragment).add(R.id.container, fragment).commit();
}
mCurrentFragment = fragment;
}
You can do this ,
You can get the name of current fragment which is in the container . This will return name including the package + fragment name
String name = getFragmentManager().findFragmentById(container id ).getClass().getName();
When you click on the home index of drawer, check weather the current name id equal to the home.
If it is home, you don't need to perform any action.
I know that this was asked and answered long time ago but, I would like to show my approach on this problem, maybe it will help anyone else:
I added a Fragment Name over each Fragment that I use like:
public class MainFragment extends BaseFragment {
public static final String FRAGMENT_TAG = "main";
// ... all your fragment
}
And on the Drawer Layout:
public void methodThatSetsTheUi() {
mDrawerView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
getFragmentManager().findFragmentByTag("main");
String tag = getFragmentTag(position);
replaceFragment(getOrCreateFragment(tag), tag);
mDrawerLayout.closeDrawer(mDrawerView);
}
});
}
#NonNull
private String getFragmentTag(int position) {
String tag;
switch (position) {
case MAIN_FRAGMENT_DRAWER_POSITION:
tag = MainFragment.FRAGMENT_TAG;
break;
case FAVORITE_FRAGMENT_DRAWER_POSITION:
tag = FavoriteFragment.FRAGMENT_TAG;
break;
default:
throw new AssertionError("That selection is wrong");
}
return tag;
}
private BaseFragment getOrCreateFragment(String fragmentName) {
BaseFragment fragment = (BaseFragment) getFragmentManager().findFragmentByTag(fragmentName);
if(fragment == null) {
fragment = FragmentFactory.createFragment(fragmentName);
}
return fragment;
}
and well, the FragmentFactory is just a simple Factory:
public final class FragmentFactory {
public static BaseFragment createFragment(String fragmentName) {
switch(fragmentName) {
case MainFragment.FRAGMENT_TAG:
return MainFragment.newInstance();
case FavoriteFragment.FRAGMENT_TAG:
return FavoriteFragment.newInstance();
// ... all fragments here.
default:
return null;
}
}
Hope to help someone.
I have a message class
class Message
{
public String message, sender;
public Message (String msg, String from)
{
message = msg;
sender = from;
}
public String toString () { return sender+":"+message; }
}
I defined a table variable for use this class in main activity:
Hashtable<String, ArrayList<Message>> table = new Hashtable<String, ArrayList<Message>>();
I am adding data in main activity to message class with this code:
table.put("user01", new ArrayList<Message>());
table.get("user01").add(new Message("message","sender"));
And I want to use this table variable in another fragment.I am passing with this code to fragment.
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
ConversationFragment conv = new ConversationFragment();
fragmentTransaction.add(R.id.container, conv);
ConversationFragment frgObj=ConversationFragment.newInstance(table.get("user01"));
fragmentTransaction.replace(R.id.container, frgObj,"ConversationFragment");
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
And this is newInstance function in Conversation fragment
static int myData;
public static ConversationFragment newInstance(ArrayList<Message> _extractedMessages){
ConversationFragment fragment = new ConversationFragment();
myData=_extractedMessages.size();
return fragment;
}
But I am getting nullpointer exception,for _extractedMessages.size().
This code is working
System.out.println(_extractedMessages);
But this is not working
System.out.println(_extractedMessages.size());
Ps:I can use size function in main activity,I can't use only in conversation fragment.
How can I fix it ?
Typically you pass parameters to the fragment in the Bundle (and make sure the Message class implements Parcelable):
public static ConversationFragment newInstance(ArrayList<Message> _extractedMessages){
ConversationFragment fragment = new ConversationFragment();
Bundle bundle = new Bundle();
bundle.putParcelable(KEY_MESSAGES, _extractedMessages);
fragment.setArguments(bundle);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myData = getArguments().getParcelable(KEY_MESSAGES);
}
I have a Fragment, and from that Fragment I show up a DialogFragment, I want the DialogFragment to send message to the Fragment, or rech the Fragment's variables. How can I do tis?
You probably want to utilize a Listener pattern for this. Here's a quick example to get you started:
public class MyDialogFragment extends DialogFragment {
public interface MyDialogFragmentListener {
public void abstract onDialogMessage(int someValueIWantToSendToFragment);
}
private MyDialogFragmentListener mListener;
....
public void setListener(MyDialogFragmentListener listener) {
mListener = listener;
}
}
and then whenever you need to send some bit of data to your fragment from the dialog, call mListener.onDialogMessage(someValue);
Make sure that when you create your dialogfragment, you call setListener on it with an instance of MyDialogFragmentListener.
you can put this code where you want in the dialogFragment:
Bundle args = new Bundle();
args.putString("message",myMessage);
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
Fragment fragment = Fragment.instantiate(getActivity(), MyFragment.class.getName(), args);
ft.replace(R.id.details, fragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.addToBackStack(null);
ft.commit();
for example in the onCreate of dialog fragment we send a message, using bundle:
public static class MyDialogFragment extends DialogFragment {
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
String myMessage="Hello Fragment";
Bundle args = new Bundle();
args.putString("message",myMessage);
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
Fragment fragment = Fragment.instantiate(getActivity(), MyFragment.class.getName(), args);
ft.replace(R.id.details, fragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.addToBackStack(null);
ft.commit();
return new AlertDialog.Builder(getActivity())
.setIcon(R.drawable.ic_dialog_about)
.setTitle(R.string.about)
.setMessage(R.string.about_message)
// ...
.create();
}
}
in MyFragment I can get my message, using only this line:
getArguments().getString("message");