My app is simple just i have a FragmentA and FragmentB first one has a single button pass String data ("Hi i'm A") through second fragment who has a text to show this message My question is
Why my "ModifyTxt" method doesn't work ?
public class newFragmentA extends Fragment{
Button button;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.newfragmenta_layout,container,false);
}
newFragmentB newfragmentB;
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
button = getActivity().findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
newfragmentB.ModifyTxT("Hi I'm A");
}
});
}
}
And this is my second Fragment(FragmentB)
public class newFragmentB extends Fragment {
TextView textView;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.newfragmentb_layout,container,false);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
textView = getActivity().findViewById(R.id.TV);
}
public void ModifyTxT(String string){
textView.setText(string); }
}
Try this:
public class FragmentB extends Fragment {
// ...
public static FragmentB newInstance() {
return new FragmentB();
}
}
In FragmentA :
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FragmentB newFragment = FragmentB.newInstance();
newFragment.modifyTxT("Hi I'm A");
}
});
Be careful to coding rules : uppercase first letter for class name, lowercase first letter for method...
Prefer using Interface to communicate with Fragments
public class FragmentA extends Fragment{
public interface MyCallback{
void modifyTxT(String text); // method naming convention start with small letter.
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
button = getActivity().findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (newfragmentB instanceof MyCallback) {
((MyCallback)newfragmentB).modifyTxT("Hi I'm A");
}
}
});
}
}
public class FragmentB extends Fragment implements FragmentA.MyCallback{
public static FragmentB getInstance(){
return new FragmentB();
}
#Override
public void modifyTxT() {
}
}
Related
I am facing a problem where I am opening a dialog (Dialog 1) from fragment1 and there is a button (change) on Dialog1 on which if I click then: Dialog1 should be dismissed and on the same fragment1 should be replaced by fragment2(Another fragment)
public class PedigreeAnalysis extends Fragment //My Fragment1
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
showDialog();
}
// SHOW DIALOG FUNCTION IS SHOWN BELOW `
void showDialog() { //Function to show the dialog starts...
Dialog dialog= new Dialog(getActivity());
Button btn = dialog.findViewById(R.id.button);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//Code for opening new fragment and dismissing the dialog.
getActivity().getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment1, new Fragment2()).commit();
dialog.dismiss();
}
});
}//Function Ends Here....
I have even tried the reverse logic of (dismissing the dialog first and then replacing it with the function but it also doesn't works) as :
dialog.dismiss();//First dismissing the dialog
getActivity().getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment1, new Fragment2()).commit();//Replacing the fragment
Follow this...
Fragment1:
public class Fragment1 extends Fragment {
private ItemClickListener itemClickListener;
private Button addButton;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// all the views are initialized here...
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
addButton.setOnClickListener(v -> {
if (itemClickListener != null) onItemClicked.onClicked(new Plan());
});
}
public Fragment1 setItemClickListener(ItemClickListener itemClickListener) {
this.itemClickListener = itemClickListener;
return this;
}
public interface ItemClickListener {
void onItemClicked(Plan plan);
}
}
In parent Activity Class
public class PlanActivity extends AppCompatActivity {
private Fragment1 fragment1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_plan);
fragment1 = new Fragment1()
.setOnAddButtonClicked(this::openFragmentEditPlan);
openFragment1();
}
private void openFragment1() {
getSupportFragmentManager().beginTransaction()
//frameLayout_PlanActivity is the container of both fragments
.add(R.id.frameLayout_PlanActivity, fragment1)
.commit();
}
public void openFragmentEditPlan(Plan plan) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.frameLayout_PlanActivity, FragmentEditPlan.newInstance(plan))
.addToBackStack("Fragment Edit Plan")
.commit();
}
}
i have one class for bottomsheetdialog fragment.I looked at many places but I'm confused.i want to change text of button in bottom sheet.i get this error 'android.view.View android.view.View.findViewById(int)' on a null object reference.
here are my codes;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(final Bundle savedInstanceState) {
bottomSheetFragment=new BottomSheetFragment();
View viewDialog=bottomSheetFragment.getView();
assert viewDialog != null;
MaterialButton btn_titresim=viewDialog.findViewById(R.id.btn_titresim);
btn_titresim.setText("text");
}
}
Another class for BottomSheetDialogFragment
public class BottomSheetFragment extends BottomSheetDialogFragment {
public BottomSheetFragment() {}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Objects.requireNonNull(getDialog()).setOnShowListener(dialog -> {
BottomSheetDialog d = (BottomSheetDialog) dialog;
View bottomSheetInternal =
d.findViewById(com.google.android.material.R.id.design_bottom_sheet);
assert bottomSheetInternal != null;
BottomSheetBehavior.from(bottomSheetInternal).setState(BottomSheetBehavior.STATE_EXPANDED);
});
return inflater.inflate(R.layout.layout_popup, container, false);
}
}
You can solve this by having a listener interface in your fragment that returns the BottomSheet fragment's View back to your activity, so you can then access the BottomSheetDialogFragmentunderlying views normally by findViewById() method.
Here I decided to use the Singleton pattern for the BottomSheetDialogFragment to set a listener instance from the activity.
So in your fragment add a listener; it's named below FragmentListener, call the listener callback in onCreateView() or in onViewCreated()
public class BottomSheetFragment extends BottomSheetDialogFragment {
public BottomSheetFragment() {}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
interface FragmentListener {
void getView(View view);
}
static FragmentListener mFragmentListener;
public static BottomSheetFragment newInstance(FragmentListener listener) {
mFragmentListener = listener;
return new BottomSheetFragment();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Objects.requireNonNull(getDialog()).setOnShowListener(dialog -> {
BottomSheetDialog d = (BottomSheetDialog) dialog;
View bottomSheetInternal =
d.findViewById(com.google.android.material.R.id.design_bottom_sheet);
assert bottomSheetInternal != null;
BottomSheetBehavior.from(bottomSheetInternal).setState(BottomSheetBehavior.STATE_EXPANDED);
});
View view = inflater.inflate(R.layout.layout_popup, container, false);
// Trigger the listener callback to return the view back to the activity
// mFragmentListener.getView(view); // Not working in all devices
return inflater.inflate(R.layout.layout_popup, container, false);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
// Trigger the listener callback to return the view back to the activity
mFragmentListener.getView(view);
}
}
implement the listener by your activity, and change the text in your callback, and instantiate the BottomSheetDialogFragment using the singleton pattern instead.
public class MainActivity extends AppCompatActivity implements BottomSheetFragment.FragmentListener {
#Override
protected void onCreate(final Bundle savedInstanceState) {
bottomSheetFragment = BottomSheetFragment.newInstance(this);
}
#Override
public void getView(View view) {
// Setting the text
((MaterialButton) view.findViewById(R.id.btn_titresim)).setText("text");
}
}
Wish that solves your problem
I am receiving java.lang.NullPointerException, although I have binded the element correctly.
Tried to check the ID of the element, it matches, but still I receive the same exception.
MainActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Text to Speech
tts = new TextToSpeech(this, this);
speakButton = findViewById(R.id.speakButton);
speechText = findViewById(R.id.speechText);
speakButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
speakOut();
}
});
// End
loadFragment(new HomeFragment());
BottomNavigationView navigation = findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
}
TranslatorFragment.java
public class TranslatorFragment extends Fragment {
public Button speakButton;
public TranslatorFragment(){
//Empty Constructor
}
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.translator_fragment, container, false);
}
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
speakButton = view.findViewById(R.id.speakButton);
}
}
It should be running fine, But I am receiving the java.lang.NullPointerException
You button code should be declared in you fragment not in you activity as the button is in your fragment.xml. As you are accessing the button in onCreate method of the activity it will give nullpointer exception because you fragment's view is not yet rendered.The best practice is to access the view in onViewCreated function of your fragment.
MainActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadFragment(new HomeFragment());
BottomNavigationView navigation = findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
}
TranslatorFragment.java
public class TranslatorFragment extends Fragment {
public Button speakButton;
public TranslatorFragment(){
//Empty Constructor
}
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.translator_fragment, container, false);
}
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//Text to Speech
tts = new TextToSpeech(getActivity(), this);
speakButton = findViewById(R.id.speakButton);
speechText = findViewById(R.id.speechText);
speakButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
speakOut();
}
});
// End
}
void speakOut(){
}
The solution is to implement TextToSpeech.OnInitListener in the project and make the public variables to be private.
public class TranslatorFragment extends Fragment implements TextToSpeech.OnInitListener{
private Button speakButton; // public Button speakButton;
private TextToSpeech tts;
private EditText speechText; // public EditText speechText;
public TranslatorFragment(){
//Empty Constructor
}
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.translator_fragment, container, false);
}
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
tts = new TextToSpeech(getActivity(), this);
speakButton = view.findViewById(R.id.speakButton);
speechText = view.findViewById(R.id.speechText);
speakButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
speakOut();
}
});
}
private void speakOut(){
String text = speechText.getText().toString();
tts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
}
public void onInit(int status){
if(status == TextToSpeech.SUCCESS){
int result = tts.setLanguage(Locale.getDefault());
if(result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED){
Toast.makeText(getActivity(), "Language not supported!", Toast.LENGTH_SHORT).show();
} else {
speakButton.setEnabled(true);
speakOut();
}
}
else
{
Toast.makeText(getActivity(), "Initilization failed!", Toast.LENGTH_SHORT).show();
}
}
public void onDestroy() {
if(tts != null){
tts.stop();
tts.shutdown();
}
super.onDestroy();
}
}
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;
}
}
Fragment 1:
public class homePage extends Fragment {
private OnFragmentInteractionListener mListener;
private View view;
public homePage() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_home_page, container, false);
Button btnLogin = (Button) view.findViewById(R.id.login);
Button btnRegister = (Button) view.findViewById(R.id.register);
btnLogin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
loginView();
}
});
btnLogin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
registerView();
}
});
return view;
}
public static homePage newInstance() {
homePage fragment = new homePage();
Bundle args = new Bundle();
return fragment;
}
public void registerView(){}
public void loginView(){}
public interface OnFragmentInteractionListener {
}
}
Acitivty :
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
homePage homepage = new homePage();
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, homepage)
.commit();
}
}
}
My fragment1 has two buttons with the id's "login" and "register". Whenever login is clicked, I want to go to my fragment_login.xml, and when register is clicked I want to go to my fragment_register.xml. Should I create these functions in my activity or in my fragment? And how should I do this? I'm fairly new to android and I'm trying to learn these basic things atm. Thanks for the help :(
Login context: "com.example.hoofdgebruiker.winkelskortrijk.login"
Register context: "com.example.hoofdgebruiker.winkelskortrijk.register"
You have to make a communication between Fragment objects via an Interface.
The Activity that make the switch between your fragments needs to implement that Interface.
So, in your case your classes must be defined as follows. This is your Interface, it helps you to tell your activity that a button has been clicked from within your Fragment:
public interface HomeClickListener {
void onLoginClick();
void onRegisterClick();
}
Your Activity needs to implement the above interface in order to be notified when a button has been clicked:
public class HomeActivity extends Activity implements HomeClickListener {
void onLoginClick() {
// Your activity code to replace your current Fragment with your Login fragment
}
void onRegisterClick() {
// Your activity code to replace your current Fragment with your Register fragment
}
}
Your fragment is hosted by an Activity, so you need to have a reference to it and notify it via an Interface:
public class LoginFragment extends Fragment {
final HomeClickListener homeClickListener
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
homeClickListener = (homeClickListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnHeadlineSelectedListener");
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_home_page, container, false);
Button btnLogin = (Button) view.findViewById(R.id.login);
Button btnRegister = (Button) view.findViewById(R.id.register);
btnLogin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
homeClickListener.onLoginClick();
}
});
btnLogin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
homeClickListener.onRegisterClick();
}
});
return view;
}
}
More information here.