I have an Activity with two Action bar tabs with one fragment in each tab. Everything is working properly until a screen rotation. I have references to the fragments in my activity. If i call a method of the fragmet from my activity and that method call getActivity(), the getActivity() return null.
I don't know if i shouldn't have references to the fragments as member fields of my Activity class. If i can't keep that reference in the activity class, how can i get the values of some fields in the layout of a fragment.
Here is my activity class:
public class MyActivity extends ActionBarActivity implements ActionBar.TabListener {
private ViewPager viewPager;
private MyPagerAdapter pagerAdapter;
private ActionBar actionBar;
DetallesAvisoFragment fragment1;
DetallesPiezaFragment fragment2;
ActionMode actionMode;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit_avisos);
actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
viewPager = (ViewPager) findViewById(R.id.viewPager);
Intent intent = getIntent();
fragment1 = new Fragment1();
fragment2 = new Fragment2();
List<Fragment> fragmentList = new ArrayList<Fragment>();
fragmentList.add(fragment1);
fragmentList.add(fragment2);
pagerAdapter = new MyPagerAdapter(getSupportFragmentManager(), fragmentList);
viewPager.setAdapter(pagerAdapter);
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int i, float v, int i2) {
}
#Override
public void onPageSelected(int i) {
actionBar.setSelectedNavigationItem(i);
}
#Override
public void onPageScrollStateChanged(int i) {
}
});
actionBar.addTab(actionBar.newTab().setText("Frag1 Tab").setTabListener(this));
actionBar.addTab(actionBar.newTab().setText("Frag2 Tab").setTabListener(this));
}
#Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
#Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
/**
* This method work properly until screen rotation
*/
public void getValues() {
String value1 = fragment1.getValueFromSomeField();
String value2 = fragment2.getValueFromOtherField();
}
}
The FragmentPagerAdapter class:
public class MyPagerAdapter extends FragmentPagerAdapter{
List<Fragment> fragmentList;
public MyPagerAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
fragmentList = fragments;
}
#Override
public Fragment getItem(int index) {
if (index >= fragmentList.size()) {
return null;
}
return fragmentList.get(index);
}
#Override
public int getCount() {
return fragmentList.size();
}
}
And my Fragment classes:
public class Fragment1 extends Fragment {
public Fragment1() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceBundle) {
return inflater.inflate(R.layout.fragment1_layout, container, false);;
}
public String getValueFromSomeField() {
TextView testView = (TextView) getActivity().findViewById(R.id.someField);
return testView.getText().toString();
}
}
public class Fragment2 extends Fragment {
public Fragment2() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceBundle) {
return inflater.inflate(R.layout.fragment2_layout, container, false);;
}
public String getValueFromSomeOtherField() {
TextView testView = (TextView) getActivity().findViewById(R.id.someOtherField);
return testView.getText().toString();
}
}
Note: I need support for SDK 8 so I have to use Fragments using the SupportLibrary
you declare
static final String STORE_FRAGMENT1 = "fragment1";
static final String STORE_FRAGMENT2 = "fragment2";
you Override method onSaveInstanceState to save tag fragment1 and fragment 2;
#Override
protected void onSaveInstanceState(Bundle savedInstanceState) {
if (fragment1 != null) {
savedInstanceState.putString(STORE_FRAGMENT1,
fragment1.getTag());
}
if (fragment2 != null) {
savedInstanceState.putString(STORE_FRAGMENT2,
fragment2.getTag());
}
super.onSaveInstanceState(savedInstanceState);
}
when OnCreated you get tag fragment1 and fragment 2 to get fragment1 and fragment2 saved before rotation
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit_avisos);
actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
viewPager = (ViewPager) findViewById(R.id.viewPager);
Intent intent = getIntent();
//----edit-------
String TagFragment1;
String TagFragment2;
if (savedInstanceState != null) {
FragmentManager fm = getSupportFragmentManager();
TagFragment1 = savedInstanceState.getString(STORE_FRAGMENT1);
fragment1 = (SubjectFragment) fm
.findFragmentByTag(TagFragment1);
TagFragment2 = savedInstanceState.getString(STORE_FRAGMENT2);
fragment2 = (CircuitFragment) fm
.findFragmentByTag(TagFragment2);
}
else {
fragment1 = new Fragment1();
fragment2 = new Fragment2();
}
//---end--edit-----
List<Fragment> fragmentList = new ArrayList<Fragment>();
fragmentList.add(fragment1);
fragmentList.add(fragment2);
pagerAdapter = new MyPagerAdapter(getSupportFragmentManager(), fragmentList);
viewPager.setAdapter(pagerAdapter);
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int i, float v, int i2) {
}
#Override
public void onPageSelected(int i) {
actionBar.setSelectedNavigationItem(i);
}
#Override
public void onPageScrollStateChanged(int i) {
}
});
actionBar.addTab(actionBar.newTab().setText("Frag1 Tab").setTabListener(this));
actionBar.addTab(actionBar.newTab().setText("Frag2 Tab").setTabListener(this));
}
Related
so i got one main activity that has a Tablayout and a ViewPager to present diffrent fragments.
when i move between the fragments with my Tablayout everything works good, but if i use a button to open fragment, when going back to the former fragment (by pushing the cancel button) the elements of the fragment i left staying on the screen (as in the picture).
i tried to use a method viewPager.setCurrentItem(0); in the fragment to go back to the homepage from the fragment instade of ft.replace(R.id.fragment_edit_reminder, new Main_Activity_fragment()).commit(); but it didn't moved back to my home fragment (with the repalce it does go back but as i saied the elements.
this is my main:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TabLayout tableLayout = findViewById(R.id.Tablayouting);
final ViewPager viewPager = findViewById(R.id.ViewPager);
PagerAdapter pagerAdapter = new
PagerAdapter(getSupportFragmentManager(),tableLayout.getTabCount());
viewPager.setAdapter(pagerAdapter);
tableLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
}
}
this is the fragment:
public class edit_reminder_fragment extends Fragment implements View.OnClickListener {
private Button cancelButton;
public edit_reminder_fragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #return A new instance of fragment edit_reminder_fragment.
*/
public static edit_reminder_fragment newInstance() {
edit_reminder_fragment fragment = new edit_reminder_fragment();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
}
}
#RequiresApi(api = Build.VERSION_CODES.O)
public void onClick(View view)//TODO: make a utility method for switching fragments on the main_activity_fragment(see note).
{
switch (view.getId()) {//recognizing what button was pushed
case R.id.ButtonCancelReminder:
//region
FragmentTransaction ft = getFragmentManager().beginTransaction();
Main_Activity_fragment maf = new Main_Activity_fragment();
ft.replace(R.id.fragment_edit_reminder, maf).commit();
break;
//endregion
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_edit_reminder_fragment, container, false);
cancelButton = view.findViewById(R.id.ButtonCancelReminder);
cancelButton.setOnClickListener(this);
return view;
}
}
my pagerAdapted class:
public class PagerAdapter extends FragmentPagerAdapter {
//https://www.youtube.com/watch?v=HHd-Fa3DCng&ab_channel=MasterCoding
private int numOfTabs;
public PagerAdapter(FragmentManager fm, int numOfTabs) {
super(fm);
this.numOfTabs = numOfTabs;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new Main_Activity_fragment();
case 1:
return new key_words_fragment();
case 2:
return new groups_and_points_fragment();
case 3:
return new Fragment_Past_Reminders();
case 4:
return new edit_reminder_fragment();
default:
return null;
}
}
#Override
public int getCount() {
return numOfTabs;
}
}
in the picture we see the home page fragment ,on it 3 buttons (cancel, save, Add a sub reminder) that stayed from a fragment that open when clicking on the ADD NEW REMINDER button (when clicking on cancel in the second fragment it's going back to the home page):
First, try the following as an adaper:
public class PagerAdapter extends
FragmentPagerAdapter {
private final ArrayList<Fragment> mFragments = new ArrayList<>();
private final ArrayList<String> mFragmentTitle = new ArrayList<>();
public PagerAdapter(FragmentManager mManager) {
super(mManager);
}
#Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
#Override
public int getCount() {
return mFragments.size();
}
public void addFragment(Fragment fragment, String title) {
mFragments.add(fragment);
mFragmentTitle.add(title);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitle.get(position);
}
public Fragment getFragment(int position) {
if (position < mFragments.size() && position >= 0) {
return mFragments.get(position);
}
return null;
}
}
Then in your MainActivity's onCreate, initialize the following:
mTabs = (TabLayout) findViewById(R.id.tabs);
mPager = (ViewPager) findViewById(R.id.view_pager);
mMainAdapter = new PagerAdapter( getSupportFragmentManager() );
setupContents();
Then the private method setupContents() as follows:
mMainAdapter.addFragment(new FragmentOne(), getResources().getString(R.string.tab_albums));
mMainAdapter.addFragment(new FragmentTwo(), getResources().getString(R.string.tab_songs));
mMainAdapter.addFragment(new FragmentThree(), getResources().getString(R.string.tab_playlists));
// you can add as many fragments as you wish
//just follow the previous method #mMainAdapter.addFragment
mPager.setAdapter(mMainAdapter);
mTabs.setupWithViewPager(mPager);
To get the current fragment:
public Fragment getCurrentFragment() {
return mMainAdapter.getFragment(mPager.getCurrentItem());
}
To check if the current fragment is FragmentOne:
private boolean isFragmentOne() {
return getCurrentFragment() instanceof FragmentOne;
}
Problem:
I'm trying to open a custom dialog after pressing a button in my tabbed fragment.
It's seems like my MainActivity activity is sent to the dialog while i want my tabbed fragment(GroupFragment) to be sent so i can change the editText(for now) in this fragment.
Code:
public class GroupFragment extends Fragment implements AddGroupDialog.AddGroupDialogListener {
private Button addGroupButton;
private TextView textViewNoGroups;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_group, container, false);
addGroupButton = view.findViewById(R.id.addGroupButton);
textViewNoGroups = view.findViewById(R.id.textViewNoGroups);
addGroupButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
addNewGroupDialog();
}
});
scaleAnimation(addGroupButton);
return view;
}
private void scaleAnimation(View v){
Animator scale = ObjectAnimator.ofPropertyValuesHolder(v,
PropertyValuesHolder.ofFloat(View.SCALE_X, 0, 1.2f, 1),
PropertyValuesHolder.ofFloat(View.SCALE_Y, 0, 1.2f, 1)
);
scale.setDuration(600);
scale.start();
}
private void addNewGroupDialog(){
AddGroupDialog dialog = new AddGroupDialog();
assert getFragmentManager() != null;
dialog.show(getFragmentManager(), "add new group dialog");
}
#Override
public void applyString(String groupName) {
textViewNoGroups.setText(groupName);
}
}
public class AddGroupDialog extends AppCompatDialogFragment {
private EditText editTextGroupName;
private AddGroupDialogListener listener;
#NonNull
#Override
public Dialog onCreateDialog(#Nullable Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.layout_add_new_group_dialog, null);
builder.setView(view)
.setTitle("")
.setPositiveButton(R.string.confirm, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
String groupName = editTextGroupName.getText().toString();
listener.applyString(groupName);
}
});
editTextGroupName = view.findViewById(R.id.editTextGroupName);
return builder.create();
}
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
try {
listener = (AddGroupDialogListener) context;
} catch (ClassCastException e){
throw new ClassCastException(context.toString() +
"Must implement AddGroupDialogListener");
}
}
public interface AddGroupDialogListener{
void applyString(String groupName);
}
}
public class MainActivity extends AppCompatActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SectionsPagerAdapter sectionsPagerAdapter = new SectionsPagerAdapter(this, getSupportFragmentManager());
ViewPager viewPager = findViewById(R.id.view_pager);
viewPager.setAdapter(sectionsPagerAdapter);
TabLayout tabs = findViewById(R.id.tabs);
tabs.setupWithViewPager(viewPager);
}
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
#StringRes
private static final int[] TAB_TITLES = new int[]{R.string.tab_text_1, R.string.tab_text_2, R.string.tab_text_3};
private final Context mContext;
public SectionsPagerAdapter(Context context, FragmentManager fm) {
super(fm);
mContext = context;
}
#Override
public Fragment getItem(int position) {
Fragment fragment = null;
switch (position){
case 0:
fragment = new GroupFragment();
break;
case 1:
fragment = new AttendanceFragment();
break;
case 2:
fragment = new StatisticsFragment();
break;
}
return fragment;
}
#Nullable
#Override
public CharSequence getPageTitle(int position) {
return mContext.getResources().getString(TAB_TITLES[position]);
}
#Override
public int getCount() {
return TAB_TITLES.length;
}
}
Error:
java.lang.ClassCastException: com.example.attendencetaker.MainActivity#26602bcMust implement AddGroupDialogListener
I hope my explanation of the problem is clear. Thank you!
Make the activity implement your interfaces and so on and then pass all data to the fragment with an method on the fragment. You will need an reference to actual Fragment that is displayed.
In your fragment add a method similar to this:
public void updateData(String data) {
editText.setText(data);
}
And in the override method of the interface in your activity to this:
#Override
public void update(String data) {
fragment.updateData(data);
}
Update
Use this Adapter instead:
public class SectionTabAdapter extends FragmentPagerAdapter {
private ArrayList<Fragment> fragments = new ArrayList<>();
private ArrayList<String> titles = new ArrayList<>();
public SectionTabAdapter(#NonNull FragmentManager fm, int behavior) {
super(fm, behavior);
}
public void addFragment(Fragment fragment, String title) {
fragments.add(fragment);
titles.add(title);
}
#NonNull
#Override
public Fragment getItem(int position) {
return fragments.get(position);
}
#Override
public int getCount() {
return fragments.size();
}
#Nullable
#Override
public CharSequence getPageTitle(int position) {
return titles.get(position);
}
}
In your activity then do this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SectionsPagerAdapter sectionTabAdapter = new SectionTabAdapter(this, getSupportFragmentManager());
Fragment groupFragment = new GroupFragment();
Fragment attendanceFragment = new AttendanceFragment();
Fragment statisticsFragment = new StatisticsFragment();
sectionTabAdapter.addFragment(groupFragment, context.getString(R.string.title_1);
sectionTabAdapter.addFragment(attendanceFragment, context.getString(R.string.title_2);
sectionTabAdapter.addFragment(statisticsFragment, context.getString(R.string.title_3);
ViewPager viewPager = findViewById(R.id.view_pager);
viewPager.setAdapter(sectionTabAdapter);
TabLayout tabs = findViewById(R.id.tabs);
tabs.setupWithViewPager(viewPager);
}
When switching from one fragment to another fragment (within the second tab of my application), my second fragment is blank. I have tried the solutions linked here, but none seem to work:
Transaction of fragments in android results in blank screen
Android: Getting white screen with fragment transaction
MainActivity:
public class MainActivity extends AppCompatActivity {
private SectionsPagerAdapter mSectionsPagerAdapter;
private ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_activity);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter, and add pages.
mViewPager = (ViewPager) findViewById(R.id.container);
mSectionsPagerAdapter.addPage(new Received());
mSectionsPagerAdapter.addPage(new Send());
mViewPager.setAdapter(mSectionsPagerAdapter);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_alert_partners, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
/**
* The fragment argument representing the section number for this
* fragment.
*/
private static final String ARG_SECTION_NUMBER = "section_number";
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if(getArguments().getInt(ARG_SECTION_NUMBER)==1) {
View rootView = inflater.inflate(R.layout.fragment_received, container, false);
return rootView;
}
else if(getArguments().getInt(ARG_SECTION_NUMBER)==2) {
View rootView = inflater.inflate(R.layout.fragment_send, container, false);
return rootView;
}
else {//main empty fragment in case of error. Never used in normal behaviour.
View rootView = inflater.inflate(R.layout.fragment_alert_partners, container, false);
return rootView;
}
}
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
//Create an Array list that will hold the pages.
ArrayList<Fragment> pages = new ArrayList<>();
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
return pages.get(position);
}
//Add a page
public void addPage(Fragment f) {
pages.add(f);
}
#Override
public int getCount() {
// Show 2 total pages.
return 2;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return "Received";
case 1:
return "Send";
}
return null;
}
}
}
SendFragment:
public class Send extends Fragment {
private OnFragmentInteractionListener mListener;
private TextView text1;
public Send() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_send, container, false);
//Need getView() for fragment since setContentView must be set first but is not possible in fragment.
text1 = (TextView)v.findViewById(R.id.textview1);
text1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Send2 send2 = new Send2();
fragmentTransaction.addToBackStack(null);
fragmentTransaction.hide(Send.this);
fragmentTransaction.add(android.R.id.content, send2);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
});
return v;
}
public interface OnFragmentInteractionListener {
}
}
Send2Fragment:
public class Send2 extends Fragment {
private OnFragmentInteractionListener mListener;
public Send2() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
final View v = inflater.inflate(R.layout.fragment_send2, container, false);
return v;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnFragmentInteractionListener {
}
}
Had to add a framelayout at the end of the layout code for the fragment I was replacing:
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/send1frameLayoutId">
</FrameLayout>
Then used this code to switch to a fragment in the same tab of the previous fragment:
Fragment send2 = new Send2();
FragmentManager fragmentManager = getChildFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.send1frameLayoutId, send2);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
I have tried to add a fragment inside another fragment inside viewpager using getChildFragmentManager(). I got following error,
java.lang.IllegalStateException: Activity has been destroyed
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1549)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:654)
at android.support.v4.app.BackStackRecord.commitAllowingStateLoss(BackStackRecord.java:625)
at com.lakeba.gameon.userprofile.UserProfileContainerFragment.replaceFragment(UserProfileContainerFragment.java:72)
And I tried this workaround but still getting same error.
UserProfileContainerFragment.java
public class UserProfileContainerFragment extends CustomFragment {
private View rootView;
private Fragment fragment1;
public UserProfileContainerFragment() {
// Required empty public constructor
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
public static UserProfileContainerFragment newInstance() {
UserProfileContainerFragment fragment = new UserProfileContainerFragment();
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
rootView = inflater.inflate(R.layout.fragment_user_profile_container, container, false);
if(savedInstanceState == null) {
UserProfileFragment userProfileFragment = UserProfileFragment.newInstance();
getChildFragmentManager().beginTransaction()
.replace(R.id.user_profile_container, userProfileFragment)
.commitAllowingStateLoss();
}
return rootView;
}
/*#Override
public void onSaveInstanceState(Bundle outState) {
//super.onSaveInstanceState(outState);
}*/
public void replaceFragment(Fragment fragment, boolean addToBackStack){
fragment1 = fragment;
if(addToBackStack){
/*getChildFragmentManager().beginTransaction()
.replace(R.id.user_profile_container, fragment)
.addToBackStack(null)
.commit();*/
getChildFragmentManager().beginTransaction()
.replace(R.id.user_profile_container, fragment)
.addToBackStack(null)
.commit();
//.commitAllowingStateLoss();
}
else{
getChildFragmentManager().beginTransaction()
.replace(R.id.user_profile_container, fragment)
.commit();
//.commitAllowingStateLoss();
}
}
#Override
public void onDetach() {
super.onDetach();
try {
Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager");
childFragmentManager.setAccessible(true);
childFragmentManager.set(this, null);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
HomeMapActivity.java
public class HomeMapActivity extends AppCompatActivity implements UserProfileFragment.OnUserProfileFragmentListener{
private Toolbar homeToolbar;
private ViewPager homeViewPager;
private TabLayout homeTabLayout;
private UserProfileContainerFragment userProfileContainerFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home_map);
/*homeToolbar = (Toolbar) findViewById(R.id.home_toolbar);
setSupportActionBar(homeToolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);*/
homeViewPager = (ViewPager) findViewById(R.id.home_view_pager);
HomeViewPagerAdapter homeViewPagerAdapter = new HomeViewPagerAdapter(getSupportFragmentManager());
userProfileContainerFragment = new UserProfileContainerFragment();
homeViewPagerAdapter.addFragment(new UserProfileContainerFragment(),"Profile");
homeViewPager.setAdapter(homeViewPagerAdapter);
homeTabLayout = (TabLayout) findViewById(R.id.home_tabs);
homeTabLayout.setupWithViewPager(homeViewPager);
setTabIcons(homeTabLayout);
homeTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
int tabPosition = tab.getPosition();
tab.setIcon(tabIconsArrayActivated[tabPosition]);
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
int tabPosition = tab.getPosition();
tab.setIcon(tabIconsArray[tabPosition]);
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
int tabPosition = tab.getPosition();
tab.setIcon(tabIconsArrayActivated[tabPosition]);
}
});
homeTabLayout.getTabAt(1).select();
}
private void setTabIcons(TabLayout homeTabLayout) {
homeTabLayout.getTabAt(0).setIcon(tabIconsArray[0]);
homeTabLayout.getTabAt(1).setIcon(tabIconsArray[1]);
homeTabLayout.getTabAt(2).setIcon(tabIconsArray[2]);
homeTabLayout.getTabAt(3).setIcon(tabIconsArray[3]);
}
#Override
public void onUserProfileEditButtonClicked() {
userProfileContainerFragment.replaceFragment(EditUserProfileFragment.newInstance(),true);
}
private class HomeViewPagerAdapter extends FragmentStatePagerAdapter{
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public HomeViewPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
#Override
public CharSequence getPageTitle(int position) {
//return mFragmentTitleList.get(position);
return null;
}
public void addFragment(Fragment fragment,String title){
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
}
}
If you look at the code in your onCreate() method you'll see the lines:
userProfileContainerFragment = new UserProfileContainerFragment();
homeViewPagerAdapter.addFragment(new UserProfileContainerFragment(),"Profile");
You first initialize the userprofileContainerFragment field with a new instance of UserProfileContainerFragment and then right below you create a new instance of UserProfileContainerFragment to be used in the ViewPager(you can easily observe this by placing a log statement in the constructor of UserProfileContainerFragment...you'll see two instances being created). Later in your code you try to use the field userProfileContainerFragment which will lead to a failure as that instance of UserProfileContainerFragment is not attached to the activity at all(this isn't the fragment used by the ViewPager).
Your code should look like below, to maintain the proper reference and not create detached fragments:
userProfileContainerFragment = new UserProfileContainerFragment();
homeViewPagerAdapter.addFragment(userProfileContainerFragment,"Profile");
I have really browsed through stackoverflow for this solution.
Im trying to access a fragment from another fragment and an error is thrown that
java.lang.ClassCastException: com.noel.myapplication99.IncomeTax cannot be cast to com.noel.myapplication99.IncomeDialog
at com.noel.myapplication99.MainActivity.createOutput(MainActivity.java:119)
at com.noel.myapplication99.IncomeTax$1.onClick(IncomeTax.java:77)
at android.view.View.performClick(View.java:4785)
at android.view.View$PerformClick.run(View.java:19869)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:155)
at android.app.ActivityThread.main(ActivityThread.java:5696)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
These are my codes
MainActivity.java
public class MainActivity extends AppCompatActivity
implements IncomeTax.OnFragmentInteractionListener, ResidentialIncomeTax.OnFragmentInteractionListener, NavigationDrawerFragment.NavigationDrawerCallbacks, IncomeTax.IncomeTaxListener {
public void onFragmentInteraction(Uri uri){
}
private NavigationDrawerFragment mNavigationDrawerFragment;
private CharSequence mTitle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mNavigationDrawerFragment = (NavigationDrawerFragment)
getSupportFragmentManager().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
Fragment fragment=null;
switch(position)
{
case 0:
fragment = new IncomeTax();
mTitle = getString(R.string.title_section1);
break;
case 1:
fragment = new ResidentialIncomeTax();
mTitle = getString(R.string.title_section2);
break;
}
if(fragment!=null)
{
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.container, fragment, "Tag").commit();
}
}
public void onSectionAttached(int number) {
switch (number) {
}
}
public void restoreActionBar() {
ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
actionBar.setDisplayShowTitleEnabled(true);
actionBar.setTitle(mTitle);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
if (!mNavigationDrawerFragment.isDrawerOpen()) {
getMenuInflater().inflate(R.menu.main, menu);
restoreActionBar();
return true;
}
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void createOutput(int i, int f) {
IncomeDialog incomeDialog = (IncomeDialog) getSupportFragmentManager().findFragmentByTag("Tag");
incomeDialog.setOutputText(i, f);
}
public static class PlaceholderFragment extends Fragment {
private static final String ARG_SECTION_NUMBER = "section_number";
public static PlaceholderFragment newInstance(int sectionNumber) {
PlaceholderFragment fragment = new PlaceholderFragment();
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
fragment.setArguments(args);
return fragment;
}
public PlaceholderFragment() {
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
((MainActivity) activity).onSectionAttached(
getArguments().getInt(ARG_SECTION_NUMBER));
}
}
}
IncomeTax.java
public class IncomeTax extends Fragment implements AdapterView.OnItemSelectedListener {
IncomeTaxListener activityCommander;
float selectedIncomeType;
public interface IncomeTaxListener{
public void createOutput(int i, int f);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try{
activityCommander = (IncomeTaxListener) context;
}catch(Exception e){
throw new ClassCastException(toString());
}
}
private OnFragmentInteractionListener mListener;
public IncomeTax() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
}
}
Button btnIcCalc;
EditText salary, insuaranceRelief;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_income_tax, container, false);
salary = (EditText) view.findViewById(R.id.tvSalary);
insuaranceRelief = (EditText) view.findViewById(R.id.tvReliefCalc);
btnIcCalc = (Button)view.findViewById(R.id.btnIcCalc);
final int iSalary=0;
final int iInsuranceRelief=1;
btnIcCalc.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Dialog box here
activityCommander.createOutput(iSalary, iInsuranceRelief);
FragmentManager manager = getActivity().getSupportFragmentManager();
IncomeDialog myDialog = new IncomeDialog();
myDialog.setTargetFragment(IncomeTax.this, 0);
myDialog.show(manager, "IncomeDialog");
}
});
setSpinnerContent(view);
return view;
}
private void setSpinnerContent( View view )
{
Spinner spinner = (Spinner) view.findViewById( R.id.incomeTypeSpinner );
ArrayAdapter incomeSpinnerArrayAdapter = ArrayAdapter.createFromResource(this.getActivity(), R.array.income_type_array, android.R.layout.simple_spinner_item);
spinner.setAdapter(incomeSpinnerArrayAdapter );
spinner.setOnItemSelectedListener(this);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnFragmentInteractionListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
switch (position){
case 0:
selectedIncomeType = 1;
break;
case 1:
selectedIncomeType = 1;
break;
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
IncomeDialog.java
public class IncomeDialog extends DialogFragment {
public IncomeDialog() {
// Required empty public constructor
}
TextView netPay, insuranceRelief;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_income_dialog, null);
netPay = (TextView) view.findViewById(R.id.tvNetPay);
insuranceRelief = (TextView) view.findViewById(R.id.tvPersonalRelief);
return view;
}
public void setOutputText(int i, int f){
netPay.setText(i);
insuranceRelief.setText(f);
}
If you want to send data to DialogFragmet then try like this:
Bundle bundle = new Bundle();
bundle.putInt("key1", i);
bundle.putInt("key2", f);
IncomeDialog incomeDialog = new IncomeDialog();
incomeDialog.setArguments(bundle);
Now carry out FragmentTransaction to add this incomeDialog. That will show the dialog.
To receive the bundle data in IncomeDialog:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_income_dialog, null);
netPay = (TextView) view.findViewById(R.id.tvNetPay);
insuranceRelief = (TextView) view.findViewById(R.id.tvPersonalRelief);
Bundle bundle=getArguments();
int i = bundle.getInt("key1");
int f = bundle.getInt("key2");
return view;
}