OnClick not triggered inside Fragment - java

Got two empty Activites(A and B), which just hold two fragments inside ViewPager of Activity A.
I do not have code errors, everything seems fine.
When I lunch my app and click on button, nothing happens.I was trying just to log something, but still nothing is happening.
I am using ButterKnife, and so far everything was perfect.I got almost same Fragment and it is performing fine, but OnClick inside Fragment B is not working.I tried to add some more OnClick methods, but none of them worked for me.XML looks good,looks almost same as fragment A.
Fragment B is not complex, it just three TextViews and Button.
Here is code for my fragment B:
public class ForgotPasswordFragmentComplete extends BaseFragment
implements BaseView {
private Realm realm;
private Email model;
#Bind(R.id.btn_resend)
AppCompatButton resendEmail;
#Inject
ForgotPasswordPresenter presenter;
#OnClick(R.id.btn_resend)
public void resendButton() {
Log.d("ResendOnclick", "Checking OnClickMethod ");
Realm realm2 = getRealm();
RealmQuery<Email> queryUserResend = realm2.where(Email.class);
Email resultResend = queryUserResend.findFirst();
ForgotPasswordPayload forgotPayload = new ForgotPasswordPayload(resultResend.getUsername());
this.presenter.subscribe(forgotPayload);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DaggerForgotPasswordCompletedComponent.builder()
.applicationComponent(
((AndroidApplication) getActivity().getApplication()).getApplicationComponent())
.forgotPasswordCompletedModule(new ForgotPasswordCompletedModule())
.build()
.inject(this);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
#Override
protected void onCreateViewWidgetInitialization(View view) {
super.onCreateViewWidgetInitialization(view);
}
#Override
public void onStart() {
super.onStart();
getEmail();
}
public void getEmail(){
Realm realm = getRealm();
RealmQuery<Email> queryUser = realm.where(Email.class);
Email result1 = queryUser.findFirst();
resendEmailTxt = (AutoResizeTextView) getView().findViewById(R.id.resend_user_email);
if (resendEmailTxt != null) {
this.resendEmailTxt.setText(result1.getUsername());
}
}
#Override
public void onDestroy() {
super.onDestroy();
realm.close();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_forgot_password_fragment_complete, container, false);
}
#Override
protected int getFragmentLayoutId() {
return R.layout.fragment_forgot_password_fragment_complete;
}

You need to bind the fragment's view object before you can use it. Try putting the following code inside onCreateView() :
View rootView = inflater.inflate(R.layout.fragment_forgot_password_fragment_complete, container, false);
ButterKnife.bind(this, rootView);
return rootView;

Related

Views of Fragment Layout causing NullPointerException

I'm trying to use View Pager with Fragment State Adapter. But getting a NullPointerException when trying to invoke a Fragment method after creating its instance.
Here is the activity class and Adapter class:
public class AddScheduleActivity extends AppCompatActivity {
private FragmentOverview fragmentOverview;
private FragmentTodo fragmentTodo;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_schedule);
ViewPager2 viewPager = findViewById(R.id.viewPager_AddScheduleActivity);
viewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager(), getLifecycle()));
fragmentOverview = new FragmentOverview();
fragmentOverview.setTargetView(); //ERROR IS HERE
My view pager adapter is:
private class ViewPagerAdapter extends FragmentStateAdapter {
public ViewPagerAdapter(#NonNull FragmentManager fragmentManager, #NonNull Lifecycle lifecycle) {
super(fragmentManager, lifecycle);
}
#NonNull
#Override
public Fragment createFragment(int position) {
switch (position) {
case 0:
return fragmentOverview;
case 1:
return fragmentTodo;
default:
return null;
}
}
#Override
public int getItemCount() {
return 2;
}
}
My FragmentOverView class is:
public class FragmentOverview extends Fragment{
private FrameLayout mTargetFrameLayout;
private FrameLayout mDescriptionFrameLayout;
public FragmentOverview() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_overview, container, false);
mDescriptionFrameLayout = rootView.findViewById(R.id.descriptionView_frameLayout_OverviewFragment);
mTargetFrameLayout = rootView.findViewById(R.id.targetView_frameLayout_OverviewFragment);
return rootView;
}
public void setTargetView() {
mTargetFrameLayout.removeAllViews();
if (progress.maxProgress != null) {
//ADD A CHILD VIEW
mTargetFrameLayout.setVisibility(View.VISIBLE);
} else mTargetFrameLayout.setVisibility(View.GONE);
}
}
But when I call the setTargetView() method after creating instance of FragmentOverview, I'm getting a NullPointerException. From log I noticed that the mTargetFrameLayout is null.
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.FrameLayout.removeAllViews()' on a null object reference
I think this is because the activity lifecycle methods onCreate(), onStart(), onResume() are called before the fragment lifecycle methods onCreate() & onCreateView(). But how to overcome this problem? Or am I trying to do in a wrong way?
I think your assumption is right. The fragment layout is generated in onViewCreated() of FragmentOverview class. But this method start executing after the Activity lifecycle methods onCreate(), onStart() and onResume() are executed. You can checkout the lifecycle relation of Activity and Fragment by overwriting lifecycle methods and adding logs as mentioned by #Max_Hockeborn.
So you will always get the views i.e mTargetFrameLayout null if you call setTargetView() before executing onCreateView() in FragmentOverview.
To solve this, you can add a callback method that will be executed in parent class after executing the onCreateView() of FragmentOverveiw. And in that callback you can invoke setTargetView().
Here I'm providing a possible solution for your case:
In FragmentOverview add this lines:
public class FragmentOverview extends Fragment{
//all your fields;
private OverviewCallbacks callbacks;
public FragmentOverview(OverviewCallbacks callbacks) {
this.callbacks = callbacks;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//inflate the rootView and find all the childViews;
//I think your codes are okey;
}
//Overwrite this method;
//You can also overwrite onViewCreated() lifecycle method;
//And add call this callback method from here;
#Override
public void onResume() {
super.onResume();
callbacks.onReach();
}
public void setTargetView() {
//Do what you want to do;
}
public interface OverviewCallbacks {
void onReach();
}
}
Thats all for FragmentOverView class.
Now modify your Activity class as follows:
public class AddScheduleActivity extends AppCompatActivity {
private FragmentOverview fragmentOverview;
private FragmentTodo fragmentTodo;
#Override
protected void onCreate(Bundle savedInstanceState) {
//Your codes
fragmentOverview = new FragmentOverview(new FragmentOverview.OverviewCallbacks() {
#Override
public void onReach() {
setTargetView();
}
});
}
}
Hope this will work. Comment if anything gone wrong.
This is just a fast idea that I couldn't test yet.
You could try to change this:
public class AddScheduleActivity extends AppCompatActivity {
private FragmentOverview fragmentOverview;
private FragmentTodo fragmentTodo;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_schedule);
ViewPager2 viewPager = findViewById(R.id.viewPager_AddScheduleActivity);
viewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager(), getLifecycle()));
fragmentOverview = new FragmentOverview();
fragmentOverview.setTargetView(); //ERROR IS HERE
to this:
public class AddScheduleActivity extends AppCompatActivity {
private FragmentOverview fragmentOverview = new FragmentOverview();
private FragmentTodo fragmentTodo;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_schedule);
ViewPager2 viewPager = findViewById(R.id.viewPager_AddScheduleActivity);
viewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager(), getLifecycle()));
fragmentOverview.setTargetView(); //ERROR IS HERE
To check your assumption that your problem is based on the call order you can add some logs and check the order they are called in with Logcat (given you use android studio)
Something like this:
public class AddScheduleActivity extends AppCompatActivity {
private FragmentOverview fragmentOverview;
private FragmentTodo fragmentTodo;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_schedule);
ViewPager2 viewPager = findViewById(R.id.viewPager_AddScheduleActivity);
viewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager(), getLifecycle()));
Log.d("YOUR_TAG","Activity onCreate 1");
fragmentOverview = new FragmentOverview();
fragmentOverview.setTargetView(); //ERROR IS HERE
and
public class FragmentOverview extends Fragment{
private FrameLayout mTargetFrameLayout;
private FrameLayout mDescriptionFrameLayout;
public FragmentOverview() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_overview, container, false);
mDescriptionFrameLayout = rootView.findViewById(R.id.descriptionView_frameLayout_OverviewFragment);
mTargetFrameLayout = rootView.findViewById(R.id.targetView_frameLayout_OverviewFragment);
Log.d("YOUR_TAG","FragmentOverview onCreateView 1");
return rootView;
}
public void setTargetView() {
Log.d("YOUR_TAG","FragmentOverview setTargetView 1");
mTargetFrameLayout.removeAllViews();
if (progress.maxProgress != null) {
//ADD A CHILD VIEW
mTargetFrameLayout.setVisibility(View.VISIBLE);
} else mTargetFrameLayout.setVisibility(View.GONE);
}
}
The last one could be interesting for you to see if onCreateView (and the initiation of the variables that cause your problems) is finished before the setTargetView() function is called.

how to settext button in bottom sheet dialog fragment?

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

How to send to texts to listview using fragment activity

I have created fragment activity using viewpager with two tabs, and created listview with two textviews. I want to sent the two texts from tab one to tab two as title and description. I have successfully sent the description, but I failed to send the title (]I can only send one text to listview).
My fragment_one.java :
public void onViewCreated(final View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
viewPager = (ViewPager)view.findViewById(R.id.viewPager);
Button btnPassData = (Button) view.findViewById(R.id.btnPassData);
final ListView list=(ListView)view.findViewById(R.id.list_view);
final EditText inData = (EditText) view.findViewById(R.id.inMessage);
btnPassData.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
SM.sendData(inData.getText().toString().trim());
}
});
}
interface SendMessage {
void sendData(String message);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
SM = (SendMessage) getActivity();
} catch (ClassCastException e) {
throw new ClassCastException("Error in retrieving data. Please try again");
}
}
}
my fragment_two.java :
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(
R.layout.fragment_two, container, false);
return rootView;
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
listView = (ListView) view.findViewById(R.id.list_view);
adapter = new ArrayAdapter<String>(getActivity(), R.layout.single_item,R.id.tvdesc, arrayList);
listView.setAdapter(adapter);
}
protected void displayReceivedData(String message) {
arrayList.add(0,message);
adapter.notifyDataSetChanged();
}
}
You should use call back data from fragment_one to main activity , and send data from activity to fragment_two (and refresh view)
Callback fragment to activity you can use How to make a callback between Activity and Fragment?
and Fragment_two you can set this value in Activity,
EX,
private Fragment mFragmentTwo;
.........
mFragmentTwo= new Fragment();
and can set value by funtion : mFragmentTwo.displayReceivedData(yourString)

Spinner Fragment continually crashes

I am making a program that will include a Spinner within a fragment rather than an activity. I have researched why this may be crashing, but to no avail. My initial concern was a .getView().findViewById(), but now I'm not so sure that's the problem because . Here's the code.
public class Add extends Fragment {
public Add() {
// Required empty public constructor
}
ArrayList<String> ingredients = new ArrayList<>();
SpinnerDialog spinnerDialog;
Button add;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
add = (Button) getView().findViewById(R.id.add);
add.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
spinnerDialog.showSpinerDialog();
}
});
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_add, container, false);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
spinnerDialog = new SpinnerDialog(getActivity(), ingredients, "Select An Ingredient");
spinnerDialog.bindOnSpinerListener(new OnSpinerItemClick() {
#Override
public void onClick(String Ingredient, int i) {
Toast.makeText(Add.super.getContext(), "Selected ", Toast.LENGTH_SHORT).show();
}
});
Without seeing the stack trace I cannot say for sure, but I suspect this line is crashing:
add = (Button) getView().findViewById(R.id.add);
This is because getView() will return the View instance returned by onCreateView()... but you're currently inside onCreateView(), so getView() will return null.
You can re-write your onCreateView() as follows and it should work.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_add, container, false);
add = (Button) root.findViewById(R.id.add);
add.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
spinnerDialog.showSpinerDialog();
}
});
return root;
}

Call a fragmentMethod from another fragment, but can't refer to them in parentFragmentActivity's View pager

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;
}
}

Categories

Resources