17

My class extends DialogFragment like this:

public class DatePickerFragment extends DialogFragment implements DatePickerDialog.OnDateSetListener {

    EditText editDate;
    private Calendar dateTime = Calendar.getInstance();
    private SimpleDateFormat dateFormatter = new SimpleDateFormat("dd MMMM yyyy");

    public DatePickerFragment(EditText editText) {
        editDate = editText;
    }

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    // Use the current date as the default date in the picker
    final Calendar c = Calendar.getInstance();
    int year = c.get(Calendar.YEAR);
    int month = c.get(Calendar.MONTH);
    int day = c.get(Calendar.DAY_OF_MONTH);

    // Create a new instance of DatePickerDialog and return it
    return new DatePickerDialog(getActivity(), this, year, month, day);

}

@Override
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
        dateTime.set(year, monthOfYear, dayOfMonth);
        editDate.setText(dateFormatter
                .format(dateTime.getTime()));
    }

}

And this is how i am using it in Activity:

public void showDatePickerDialog(View v) {
        new DatePickerFragment((EditText) v).show(getSupportFragmentManager(), "datePicker");
    }

And calling like this:

    <EditText
        android:id="@+id/editDate"
        android:onClick="showDatePickerDialog" />

But I am always getting :

Error: This fragment should provide a default constructor (a public constructor with no arguments)
Oreo
  • 2,586
  • 8
  • 38
  • 63
  • Android Fragment should always have a default no arg constructor. If you really want to ignore it, you can disable lint warning on your IDE. If you could mention why are you passing the EditText, there can be multiple ways to satisfy your needs. – Milan Apr 21 '15 at 04:34
  • In one of my Fragment i am using EditText to show Date Picker ... @Milanix – Oreo Apr 21 '15 at 04:38
  • What you could do is to implement a callback listener like interface OnDateSetListener{on dateSet(Date date);} on your calling activity/fragment. You could then set it on the caller using setTargetFragment() and retrieve it in your dialog fragment getTargetFragment. And then when you are complete with date selection, fire back that listener. – Milan Apr 21 '15 at 04:43
  • add this constructor too as u have already used Setter for edittext. public DatePickerFragment() { editDate = null; } – Jivraj S Shekhawat Apr 21 '15 at 05:13
  • @uncertain-eer can you show me the way, i have tried many things to sort out this small issue, but yet not resolved – Oreo Apr 21 '15 at 05:34
  • Fragments have no constructor. – Piyush Apr 21 '15 at 05:43
  • please share onCreateDialog code so as to get the logic of using edittext here and hence the solution. i aint getting any good from edittext here. thanks – Jivraj S Shekhawat Apr 21 '15 at 05:51
  • @uncertain-eer i have posted check now – Oreo Apr 21 '15 at 05:53
  • what exactly want to do, it is not clear to me @Oreo – Prabhakar Apr 21 '15 at 06:34
  • Solution works for me [check this](http://stackoverflow.com/questions/17420637/error-non-default-constructors-in-fragments/39608360#39608360) – Naeem Ibrahim Sep 21 '16 at 06:09
  • I would say this question is similar/same to the stackoverflow question asked here: https://stackoverflow.com/questions/10450348/do-fragments-really-need-an-empty-constructor - and yes fragments always need a default zero argument constructor as well according to the official documentation: https://developer.android.com/reference/android/app/Fragment – becke-ch Jan 22 '22 at 22:35

4 Answers4

25

The newer version of Android SDK forces you to get a empty, no-args constructor. It's now a good practice to do this. This allows you to save the instance state into bundle and Android will recreate your fragment calling the default constructor.

In this case, you have the following solutions:

First, create the default constructor:

public DatePickerFragment() {}

Create the instance and set the EditText via setter method:

DatePickerFragment fragment = new DatePickerFragment();
fragment.setEditText(v); // create this setter
fragment.show();

Since EditText is parcelable, you can also set as arguments:

DatePickerFragment fragment = new DatePickerFragment();
Bundle bundle = new Bundle();
bundle.putExtra("EditText", v); 
fragment.setArguments(bundle); // setArguments is a method that already exists in fragments.
fragment.show(getSupportFragmentManager(), "DatePicker");

[EDIT] As suggested, try to ignore these errors configuring build.gradle like this:

lintOptions { 
  abortOnError false 
  checkReleaseBuilds false 
} 

This will not stop the build of your application by using non-default constructor in fragments.

Chin
  • 19,717
  • 37
  • 107
  • 164
Deividi Cavarzan
  • 10,034
  • 13
  • 66
  • 80
  • 1
    where i have to make changes ? – Oreo Apr 21 '15 at 04:42
  • Create the default constructor in `DatePickerFragment`. The you choose to set EditText via setter or arguments, its your choise – Deividi Cavarzan Apr 21 '15 at 04:44
  • please check my updated code suggested by you, I posted above – Oreo Apr 21 '15 at 04:55
  • @Oreo Sure, I forgot that this methods need the fragmentManager and a TAG, upated now – Deividi Cavarzan Apr 21 '15 at 04:58
  • ok but still getting cannot resolve method setText(java.lang.String) at this line: editText.setText(dateFormatter.format(dateTime.getTime())); please check DatePickerFragment class – Oreo Apr 21 '15 at 05:05
  • `public void setEditText(View editText) {` need to be `public void setEditText(EditText editText) {`. EditText, not View – Deividi Cavarzan Apr 21 '15 at 05:08
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/75765/discussion-between-oreo-and-deividi-cavarzan). – Oreo Apr 21 '15 at 05:12
  • hey post it as your answer: lintOptions { abortOnError false checkReleaseBuilds false } – Oreo Apr 22 '15 at 08:51
  • @Oreo what is it? It seems to be another issue that what was asked, right? – Deividi Cavarzan Apr 22 '15 at 13:49
  • no i have used lintOptions { abortOnError false checkReleaseBuilds false } in build.gradle and i my issue resolved, so once you will update it as your answer then i will accept that.. and i hope this would help many developers in future ..... – Oreo Apr 23 '15 at 04:00
  • Ok, thanks. But be careful using `checkReleaseBuilds false`. I didn't know what behavior this is going to be – Deividi Cavarzan Apr 23 '15 at 14:22
5

You need to remove this constructor

public DatePickerFragment(EditText editText) {
    editDate = editText;
}

You should not pass a View reference to Fragment. If you want to update an EditText in Activity or elsewhere then use listener.

inmyth
  • 8,880
  • 4
  • 47
  • 52
  • 1
    Could you tell me why we shouldn't pass in Views in a constructor of a Fragment or Activity? and is it only Views? I figure that this is not a bad Java coding practice but a bad Android practice? –  Oct 07 '16 at 22:09
  • 2
    First you shouldn't customize Fragment constructor, period. [http://stackoverflow.com/questions/10450348/do-fragments-really-need-an-empty-constructor]. And you should only pass data to Fragment, not Views. Why ? Because of lifecycle. When running a long process (like rest api) that updates a view, it's possible the view is already gone because the activity or fragment holding it has been destroyed. This will give you Null Pointer Exc. So view interaction should be done with listener with null check. But today much better way is to use Event Bus / Otto libraries. – inmyth Oct 08 '16 at 04:50
2
      public DatePickerFragment() {}

        @Override
        public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
                dateTime.set(year, monthOfYear, dayOfMonth);
             //   editDate.setText(dateFormatter
             //         .format(dateTime.getTime()));
            Intent intent = new Intent();
            intent.setAction("CUSTOM_INTENT_FOR_SETTING_EDITTEXT");
            Bundle bundle = new Bundle();
            bundle.putString("my_data", dateTime.getTime.toString());
            intent.putExtras(bundle);
            sendBroadcast(intent);
            }




public class SubmitFragment extends Fragment {

    View view;
    EditText editDate;
    String strDate;
    Button btnSubmit;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.fragment_submit, container, false);

        editDate = (EditText) view.findViewById(R.id.editDate);

        btnSend = (Button) view.findViewById(R.id.buttonSend);
        btnSend.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                strDate = editDate.getText().toString();
                Log.v("strDate..... >>>", strDate);

            }
        });

        return view;
    }


        // Our handler for received Intents. This will be called whenever an Intent
        // with an action named "CUSTOM_INTENT_FOR_SETTING_EDITTEXT" is broadcasted.
        private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
          @Override
          public void onReceive(Context context, Intent intent) {
            // Get extra data included in the Intent
            String message = intent.getStringExtra("my_data");
            Log.d("receiver", "message: " + message);
        *****// Use this message to set Edittext here...*****
          }
        };


        @Override
        protected void onPause() {
          // Unregister since the activity is about to be closed.
          LocalBroadcastManager.getInstance(getactivity()).unregisterReceiver(mMessageReceiver);
          super.onDestroy();
        }


        @Override
        protected void onResume() {
          // register the receiver here..
       super.onResume(); LocalBroadcastManager.getInstance(getactivity()).registerReceiver(mMessageReceiver,
              new IntentFilter("CUSTOM_INTENT_FOR_SETTING_EDITTEXT"));
        }
}

Hope this helps..what exactly i am doing here is using localBroadcast to do the needful..another way would have been using a interface to the settext but one wrong thing about that approach is that when app is in background for so long , it will return null when oncreateview is called again.

  • very clean idea, but confusions for me, still i am using showDatePickerDialog(View v) { ... } in main Activity, but calling this method when user do tap on EditText in xml of one of my Fragment.. so don't where to place and what to place in Activity and Fragment(where i have EditText) that's why i have posted code of , both the classes, main Activity and Fragment, check and update your code ... – Oreo Apr 21 '15 at 06:56
  • no in Fragment, i have placed Fragment code as well now its more clear, please check now – Oreo Apr 21 '15 at 07:08
  • i am using this example: http://www.exoguru.com/android/material-design/navigation/android-sliding-tabs-with-material-design.html, you may try at your end, just use a EditText in one of the Fragment, and try to show date using DatePicker ... i am trying my best – Oreo Apr 21 '15 at 07:18
  • have u updated your code ..if yes can u see the log there..add some more logs to check the precise behaviour. – Jivraj S Shekhawat Apr 21 '15 at 07:22
  • try adding toast message there.. in OnRecieve with the message as params . – Jivraj S Shekhawat Apr 21 '15 at 07:31
2

Add @SuppressLint("ValidFragment")

before your class,

public class DatePickerFragment extends

I hope it helps you