I will ultimately need to send information from InteractionFragment to DisplayFragment. To my understanding, this needs to go through the container activity first, so I'm trying to send from InteractionFragment to MainActivity.
public class MainActivity extends AppCompatActivity {
Fragment fragmentInteraction, fragmentHistory, fragmentDisplay;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FragmentManager fm = getSupportFragmentManager();
fragmentInteraction = fm.findFragmentById(R.id.upper_container);
if (fragmentInteraction == null) {
fragmentInteraction = new InteractionFragment();
fm.beginTransaction()
.add(R.id.upper_container, fragmentInteraction)
.commit();
}
fragmentDisplay = fm.findFragmentById(R.id.lower_container);
if (fragmentDisplay == null) {
fragmentDisplay = new DisplayFragment();
fm.beginTransaction()
.add(R.id.lower_container, fragmentDisplay)
.commit();
}
public void onStart() {
super.onStart();
Intent intent = getIntent();
String intentContents = intent.getStringExtra("editTextString");
}
}
public class InteractionFragment extends Fragment implements View.OnClickListener {
Button buttonScramble, buttonHistory;
EditText mEditText;
Activity context;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
// Inflate the layout for this fragment
context = getActivity();
View v = inflater.inflate(R.layout.fragment_interaction, parent, false);
return v;
}
public void onStart() {
super.onStart();
buttonScramble = (Button) getActivity().findViewById(R.id.buttonScramble);
buttonScramble.setOnClickListener(this);
buttonHistory = (Button) getActivity().findViewById(R.id.buttonHistory);
buttonHistory.setOnClickListener(this);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.buttonScramble:
//set x to number of letters in word
break;
case R.id.buttonHistory:
//call other fragment
break;
default:
break;
}
//use this to send user input to display fragment
//display fragment will use this info to shuffle letters
mEditText = (EditText) getActivity().findViewById(R.id.edit_text_display);
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra("editTextString", mEditText.getText().toString());
startActivity(intent);
}
intentContents returns null and no other solutions I've found for similar problems are working for me. Any suggestions would be greatly appreciated! Thanks!
Did you try using OnFragmentInteractionListener?
This answer: How to implement OnFragmentInteractionListener might help.
Related
I have two fragments and I want to show them in my screen one by one. They are managed by MainActivity. The first fragment contains a TextView and a Button. The second fragment contains an EditText and a Button. What I am trying to do is: The first fragment shows on screen, and when the user press the button I want my activity to show the second fragment, and when the user press the button from this fragment I want to send the text from the EditText to the first fragment and display it on the TextView. I used interface for listeners.
public class MainActivity extends AppCompatActivity implements Listener, ListenerTwo{
FragmentTransaction fragmentTransaction;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragmentPlaceholder, new FragmentOne());
fragmentTransaction.commit();
}
#Override
public void onButtonSelected() {
fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragmentPlaceholder, new FragmentTwo());
fragmentTransaction.commit();
}
#Override
public void onButtonPressed(String text) {
FragmentOne fragmentOne = (FragmentOne)getSupportFragmentManager().findFragmentById(R.id.fragmentPlaceholder);
if (fragmentOne != null)
fragmentOne.setTextt(text);
}
}
In my FragmentOne:
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Button button = view.findViewById(R.id.button);
textView = view.findViewById(R.id.textView);
Listener listener = (Listener) getActivity();
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getContext(), "button clicked", Toast.LENGTH_SHORT).show();
if (listener != null)
listener.onButtonSelected();
}
});
}
public void setTextt (String text) {
textView.setText(text);
}
In FragmentTwo:
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Button button = view.findViewById(R.id.button2);
EditText editText = view.findViewById(R.id.editText);
ListenerTwo listener = (ListenerTwo) getActivity();
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getContext(), "button clicked", Toast.LENGTH_SHORT).show();
if (listener != null)
listener.onButtonPressed(editText.getText().toString());
}
});
}
inside Activity in onButtonPressed method you are casting currently set FragmentTwo to FragmentOne. note that whe you are setting Fragment you are using fragmentTransaction.replace( <- REPLACE! you are loading fragments into R.id.fragmentPlaceholder, when new one is set, then previous is going to be destroyed
inside onButtonPressed you have to set again FragmentOne
fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragmentPlaceholder, new FragmentOne());
fragmentTransaction.commit();
these lines are common, are placed also in onCreate so they may be packed into one method called in these two places
for transfering some data into fragment you may use passing this object in a constructor, but better way would be to use Bundle, so:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
showFragmentOne(null);
}
#Override
public void onButtonPressed(String text) {
showFragmentOne(text);
}
private void showFragmentOne(String text) {
Fragment fragment = new FragmentOne();
if (text!=null){
Bundle bundle = new Bundle();
bundle.putInt("text", text);
fragment.setArguments(bundle);
}
fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragmentPlaceholder, fragment);
fragmentTransaction.commit();
}
inside onViewCreated at the end of method check Bundle and set text
Bundle bundle = this.getArguments();
if (bundle != null) {
String text = bundle.getString("text", null);
if(text!=null) setTextt(text); // or just textView.setText(text);
}
**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();
}
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've made 2 Activities. The first Activity contains a button, which intents to second Activity. In the second Activity I have two buttons and a container. Each button adds and replaces a fragment into the container. Each fragment in the container contains button, which intents back to first activity.
My question is: I press button2 in my second activity, that reveals fragment2 in the container, and I press fragment2, it takes me to the first activity. When I press the button of the first activity, it intents to second activity, and the container is empty again. I want to see in the container the already pressed fragment2 (i gave a background color to be visible). How can I do that?
First activity java:
public class MainActivity extends AppCompatActivity {
ImageButton bbbb;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bbbb = findViewById(R.id.bbbb);
bbbb.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this,Main2Activity.class);
startActivity(intent);
}});}}
Second activity java:
public class Main2Activity extends FragmentActivity {
private ImageButton snipe;
private ImageButton aim;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
snipe = (ImageButton) findViewById(R.id.snipe);
aim = (ImageButton) findViewById(R.id.aim);
final View.OnClickListener mListener = new View.OnClickListener() {
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.snipe:
FragmentManager FM = getSupportFragmentManager();
FragmentTransaction FT = FM.beginTransaction();
BlankFragment F1 = new BlankFragment();
FT.add(R.id.fragment_container1, F1);
FT.replace(R.id.fragment_container1, F1);
FT.commit();
break;
case R.id.aim:
FragmentManager FM1 = getSupportFragmentManager();
FragmentTransaction FT1 = FM1.beginTransaction();
BlankFragment2 F11 = new BlankFragment2();
FT1.add(R.id.fragment_container1, F11);
FT1.replace(R.id.fragment_container1, F11);
FT1.commit();
break; }}};
findViewById(R.id.snipe).setOnClickListener(mListener);
findViewById(R.id.aim).setOnClickListener(mListener); }}
One of the fragments java (both have the same code):
public class BlankFragment extends Fragment{
ImageButton b1;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View rootView = inflater.inflate(R.layout.fragment_blank, container, false);
b1 = (ImageButton) rootView.findViewById(R.id.b1);
b1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(getActivity(), MainActivity.class);
startActivity(intent); }});
return rootView; }}
I am sending the data between activities, through PutExtra. It's working perfectly.
The problem is when you click the back button, give an error and for the activity.
I've already tried to implement the StarActivityForResult option, and I can not get it to work.
Images below. Code "12345" is used as an example, and is sent to the three screens as PutExtra
Code:
Activity1:
public class MainActivity extends AppCompatActivity {
private Button btnIrAct2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnIrAct2 = (Button) findViewById(R.id.btnIrAct2);
btnIrAct2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent2 = new Intent(MainActivity.this, Activity2.class);
intent2.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent2.putExtra("id_empresa", "12345");
startActivity(intent2);
}
});
}
}
Activity 2:
public class Activity2 extends AppCompatActivity {
private Button btnIrAct3;
private String mId_Empresa = null;
static final int SERVICO_DETALHES_REQUEST = 1;
private TextView tvResultado;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_2);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
/* Recebe id de outra tela*/
mId_Empresa = getIntent().getExtras().getString("id_empresa");
tvResultado = (TextView) findViewById(R.id.tvAct2);
tvResultado.setText(mId_Empresa);
btnIrAct3 = (Button) findViewById(R.id.btnIrAct3);
btnIrAct3.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent3 = new Intent(Activity2.this, Activity3.class);
intent3.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent3.putExtra("id_empresa", "12345");
startActivityForResult(intent3, SERVICO_DETALHES_REQUEST );
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (requestCode == SERVICO_DETALHES_REQUEST && resultCode == RESULT_OK) {
String resultBack = data.getStringExtra("id_empresa");
}
}
}
Activity 3:
public class Activity3 extends AppCompatActivity {
private String idEmpresa = null;
private TextView resultado;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_3);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
/* Recebe id de outra tela*/
idEmpresa = getIntent().getExtras().getString("id_empresa");
resultado = (TextView) findViewById(R.id.tvAct3);
resultado.setText(idEmpresa);
}
#Override
public void finish()
{
Intent data = new Intent();
data.putExtra("id_empresa", "12345");
setResult(Activity.RESULT_OK, data);
super.finish();
}
}
I need to resolve the conflict. Because on my return I need to send a data like PutExtra, at the same time that this Activity already has a piece of code that already receives a PutExtra.
If I understand the issue correctly, you should to use fragments instead of activities and save all the data in main activity but if you want to continue with this way try onBackPressed() method to choose what to do when the user pressed back button.
Insert this code in Activity 2
if(getIntent().getExtras().getString("id_empresa") != null)
{
mId_Empresa = getIntent().getExtras().getString("id_empresa");
}
Checking the data before setting it to the textview is must. If the string you are putting to textview is null, it will generate an error which will lead to crash.
Hope it helps!