**Re-attached the relevant code
When I run the email app in FragmentB, the activity's 'onStop' is called.
At this time, FragmentA's method in 'onStop' does not work.
※ FragmentA and FragmentB have the same parent Activity
※ No error occurs when the app is terminated in FragmentB.
MainActivity.java
public class MainActivity extends FragmentActivity {
public Fragment fragmentA, fragmentB;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (findViewById(R.id.fragment_container) != null) {
if (savedInstanceState != null) {
return;
}
fragmentA = new FragmentA();
fragmentB = new FragmentB();
fragmentA.setArguments(getIntent().getExtras());
getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, fragmentA).commit();
}
}
#Override
protected void onStop() {
super.onStop();
((FragmentA) getSupportFragmentManager().findFragmentById(R.id.fragment_container)).saveData();
}
}
FragmentA.java
View view;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_timer, container, false);
if(isLoadData){ loadData(); }
return view;
}
public void saveData() {
SharedPreferences timerSharedPref = getActivity().getSharedPreferences("timer", Context.MODE_PRIVATE);
//...
SharedPreferences.Editor editor = timerSharedPref.edit();
String json = jsonArray.toString();
editor.putString("jsonString", json);
editor.apply();
}
FragmentB.java
public class FragmentB extends Fragment implements View.OnClickListener {
View view;
CardView cvContactUs;
MainActivity activity;
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
activity = (MainActivity) getActivity();
}
#Override
public void onDetach() {
super.onDetach();
activity = null;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_b, container, false);
cvContactUs = view.findViewById(R.id.cv_contact_us);
return view;
}
#Override
public void onStart() {
super.onStart();
cvContactUs.setOnClickListener(this);
}
#Override
public void onClick(View v) {
int id = v.getId();
if (id == R.id.cv_contact_us) {
sendEmail(getActivity(), "Ask a question", new String[]{"help_center#gmail.com"});
}
}
public static void sendEmail(Context context, String title, String[] receivers){
Intent email = new Intent(Intent.ACTION_SEND);
email.putExtra(Intent.EXTRA_SUBJECT, title);
email.putExtra(Intent.EXTRA_EMAIL, receivers);
email.setType("message/rfc822");
context.startActivity(email);
}
}
You say you are getting a ClassCastException. The only class cast from the code you posted is
(FragmentA) getSupportFragmentManager().findFragmentById(...)
So check whether findFragmentById might return FragmentB or something else. Maybe you want to
either cast to the common parent activity
check whether the returned value is an instance of FragmentA before casting
You have two Fragments in the stack and a single ID and the findFragmentByID() method returns the last fragment added to the container. very well when the application ends with the FragmentA I believe that you don't have any error because in the onStop() method you are casting with the FragmentA, but if you end with the FragmentB in this case you are casting the FragmentB by the FragmentA which throws the ClassCastException exception. so I suggest you use the findFragmentByTag() method here is an example
When you add fragments:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/*
* rest of your code
*/
// when you add the Fragment A
getSupportFragmentManager()
.beginTransaction()
.add(R.id.fragment_container, new FragmentA(), "A")
.commit();
// when you add the Fragment A
getSupportFragmentManager()
.beginTransaction()
.add(R.id.fragment_container, new FragmentB(), "B")
.commit();
}
and when you call the onStop() methode:
#Override
protected void onStop() {
super.onStop();
// ((FragmentA) getSupportFragmentManager().findFragmentByTag("A")).save();
// ((FragmentB) getSupportFragmentManager().findFragmentByTag("B")).save();
Fragment f = getSupportFragmentManager().findFragmentByTag("A");
// you check if the fragment is add
if (f != null)
((FragmentA) f).save();
}
Related
I have two different classes that i will show
public class Iniziale extends AppCompatActivity {
Button credits,gioca,giocamyquiz,newquestion;
TextView testo;
public boolean whatgame;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_iniziale);
gioca = findViewById(R.id.gioca);
giocamyquiz = findViewById(R.id.giocamyquiz);
newquestion= findViewById(R.id.newquestions);
whatgame=true;
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
gioca.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
whatgame=true;
Intent homeIntent = new Intent(Iniziale.this, MainActivity.class);
startActivity(homeIntent);
finish();
}
});
giocamyquiz.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
whatgame=false;
Intent homeIntent = new Intent(Iniziale.this, MainActivity.class);
startActivity(homeIntent);
finish();
}
});
}
public boolean FragmentMethod() {
return whatgame;
}
}
and a fragment
public class MainActivityFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.fragment_main_activity, container, false);
what=true; //sceglie a quale quiz giocare
what=((Iniziale) getActivity()).FragmentMethod();
I want use method FragmentMethod() in my Fragment class because I need the value of the whatgame variable.
How the code is write it doesn't work.
In Iniziale class I have 2 buttons and based of what button i click I will modify my whatgame variable and modify some parameters in fragment class
I have a fragment that I call like so from my activities onCreate
android.app.FragmentManager fragmentManager = getFragmentManager();
DeviceControlFragment newFragment = new DeviceControlFragment();
newFragment.device = device;
fragmentManager.beginTransaction()
.replace(R.id.content_frame, newFragment)
.commit();
In the fragment I can either pop the back stack or hit back like so:
getFragmentManager().popBackStack();
OR
getActivity().onBackPressed();
But I need something in the activity so that I know we have returned there, is there something similar to onActivityResult that I can override in the activity to know when the fragment has been 'finished'
Declare a interface inside fragment and implement it in your activity and send response to activity inside onDetach(),onDestroy or onPaused method of fragment, any of them which suits you. I will prefer onDetach or onDestroy
Here is sample for that:
public class MyFragment extends Fragment {
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return super.onCreateView(inflater, container, savedInstanceState);
}
private Test mListener;
public interface Test{
void imLeavingYou();
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
mListener = (Test) context;
}
#Override
public void onDetach() {
super.onDetach();
if(mListener != null){
mListener.imLeavingYou();
}
}
}
And in your Activity do this:
public class MyActivity extends AppCompatActivity implements MyFragment.Test {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
}
#Override
public void imLeavingYou() {
// Okay thanks for informing
}
}
You should probably set a onBackStackChanged() listener on your fragment manager.
Example:
getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
//here you can check stuff. like:
final Fragment mCurrentFragment = getFragmentManager().findFragmentById(R.id.container);
//or get the number of fragments currently on your stack:
getFragmentManager().getBackStackEntryCount()
}
});
There are lot of (duplicate) questions and answers are available, I went through almost all of them and failed. On reference of this question, I made some changes recently.
Brief : In my app, MainActivity holds Fragment View Pager and FrangmentA,B and C. FrangmentA Shows a DialogFragment CDialog onClik. After dismissing CDialog I need to Call FragmentA's doReload() which is not happening here.
MainActivity
protected void onCreate(Bundle savedInstanceState){
...
mSectionsPageAdapter = new FragmentAdapter(getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.container);
setupViewPager(mViewPager);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
int defaultValue = 0;
int page = getIntent().getIntExtra("One", defaultValue);
mViewPager.setCurrentItem(page);
}
private void setupViewPager(ViewPager viewPager)
{
FragmentAdapter adapter = new
FragmentAdapter(getSupportFragmentManager());
adapter.addFragment(new FragmentA(), "FragA");
adapter.addFragment(new FragmentB(), "FragB");
adapter.addFragment(new FragmentC(), "FragC");
viewPager.setAdapter(adapter);
}
FragmentA
public class FragmentA extends Fragment implements CDialog.Dismissed{
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
...
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
FragmentManager fm = getActivity().getFragmentManager();
DialogFragment f = new CDialog();
f.show(fm, "CDialog");
}
});
#Override
public void dialogDismissed() {
Log.e(DFD_1, "dialogDismiss Called" );// <-- This is not working*
doReload();
}
}
And CDialogue
public class CDialog extends DialogFragment{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
....
return v;
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
...
dfd_1.setOnClickListener(
new View.OnClickListener() {
public void onClick(View v) {
getDialog().dismiss(); //<--when this happens*
}
});
}
#Override
public void onDismiss(DialogInterface dialog) {
if (getActivity() != null && getActivity() instanceof Dismissed) {
((Dismissed) getActivity()).dialogDismissed();
}
super.onDismiss(dialog);
}
public interface Dismissed {
public void dialogDismissed(); //<-- FragmentA implements this
}
}
You can always have direct callback to your Fragment itself.
First step, is to set targetFragment using setTargetFragment():
DialogFragment#setTargetFragment(Fragment fragment, int requestCode);
I do it this way:
public void showDialogFragment(Fragment targetFragment, AppCompatDialogFragment appCompatDialogFragment, int requestCode) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
appCompatDialogFragment.setTargetFragment(targetFragment, requestCode);
fragmentTransaction.add(appCompatDialogFragment, appCompatDialogFragment.getClass().getSimpleName());
fragmentTransaction.commitAllowingStateLoss();
}
and then call to this method to open dialog fragment as:
public static final int RC_CDIALOG = 111;
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
showDialogFragment(FragmentA.this, new CDialog(), RC_CDIALOG);
}
});
Then, in your DialogFragment's onDismissListener(), have some code like below:
#Override
public void onDismiss(DialogInterface dialog) {
super.onDismiss(dialog);
if (getTargetFragment() instanceof FragmentA)
((FragmentA) getTargetFragment()).doReload();
}
What you did this way is:
Show Dialog Fragment "CDialog" along with telling it that your target fragment is "FragmentA" whose reference you can use incase you have something to do with it. In your case you had to call doReload();
I have 3 main fragments inside viewpager and they have couple of buttons. I want each button to navigate to another fragment and back button to get back to main fragment. I tried to add fragment transaction but it does not work. What am I doing wrong here?
this is one of the main fragments
public class OneFragment extends Fragment implements View.OnClickListener{
public OneFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_one, container, false);
}
#Override
public void onClick(View v) {
switch (v.getId()){
case R.id.aButton:
FragmentManager manager = getFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.fragment_one, AFragment.newInstance());
transaction.commit();
break;
}
}
}
this is the fragment I want to navigate
public class AFragment extends Fragment{
public AFragment() {
}
public static AFragment newInstance() {
AFragment fragment = new AFragment();
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.a_fragment, container, false);
}
}
First, define a public method in your Activity to switch tabs in the ViewPager, and also define the onBackPressed() override, which will select the first index when the back button is pressed:
public void selectIndex(int newIndex) {
mViewPager.setCurrentItem(newIndex);
}
#Override
public void onBackPressed() {
int currentPosition = mViewPager.getCurrentItem();
if (currentPosition != 0) {
mViewPager.setCurrentItem(0);
} else {
super.onBackPressed();
}
}
Then, modify the click listener in the Fragment in order to call the selectIndex() method:
#Override
public void onClick(View v) {
switch (v.getId()){
case R.id.aButton:
//select the index of AFragment:
((MainActivity)getActivity()).selectIndex(1);
break;
}
}
I m new to android and i m having trouble with fragment communication, reading about it discovered the standard method of creating an interface and implementing it from the parentActivity which doesn't work in my case which is as follows.
I have an Activity named as ActivityA which extends fragment activity,in which i have a view pager for i want to keep two fragments namely fragmentA and fragmentB which should be swipable fragments.
fragmentA has a button which onClicked should make a change in fragmentB, to be precise on click it should add a string in the listView in fragmentA.
Now i have created the both the fragments's layouts as well as added the viewPAger to my FragmentActivity, they work great on swiping, the function is executed onButtonClick of fragmentA and logic works perfectly, after this is i want the changes to be reflected in fragmentB.
Using the interface method i can't find the reference to my fragment by id as it is added by viewPager to ActivityA
How do i do this??
help me out.
Stackoverflow says don't ask questions with out code so
Here is the Sample code
Activity A which has a virewPAger, need help how to get my fragment's Reference from the viewPager
public class ActivityA extends FragmentActivity implements FragmentA.Communicator
{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_A);
viewPager= (ViewPager) findViewById(R.id.pager);
fragmentManager=getSupportFragmentManager();
viewPager.setAdapter(new myAdapter(fragmentManager));
}
class myAdapter extends FragmentPagerAdapter{
public myAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
#Override
public Fragment getItem(int i) {
Fragment fragment = null;
switch (i){
case 0: fragment = new listOfIDsScanned();
break;
case 1: fragment = new displayCounter();
break;
default: //something witch won't crush the app
break;
}
return fragment;
}
#Override
public int getCount() {
return 2;
}
}
This is fragmentA , actual fragment name is something else just for simple representation calling it fragmentA, which has an interface Communicator to communicate between fragments
public class fragmentA extends android.support.v4.app.Fragment implements View.OnClickListener
{
TextView counter;
Button scanStudentID;
int count=0;
String name=null,rollNo=null;
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.display_counter,container,false);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
scanStudentID= (Button) getActivity().findViewById(R.id.startScanning);
scanStudentID.setOnClickListener(this);
}
#Override
public void onClick(View v)
{
switch(v.getId()){
case R.id.startScanning:
startScanning();
break;
}
}
public void startScanning()
{
startActivityForResult(new Intent(getActivity(),Barcode.class),1);
}
public interface Communicator
{
// necessary methods
}
}
now finally fragmentB, in which methodToBeCalled(parameters) has to be invoked on the button click in fragementA
public class fragementB extends android.support.v4.app.Fragment
{
ListView listView;
ArrayList<String> rollNo= new ArrayList<>();
ArrayList<String> studentName= new ArrayList<>();
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_list_of_ids_scanned,container,false);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
listView= (ListView) getActivity().findViewById(R.id.listView);
}
public void methodToBeCalled(String rollNo,String studentName)
{
if(!alreadyScanned(rollNo))
{
}
else
{
}
}
boolean alreadyScanned(String rollNo)
{
return true;
}
}