Use interface implementation in a Fragment

Asked

Viewed 451 times

1

I’m trying to implement an interface I created within a fragment, but I’m not succeeding. My fragment is being defined with the following code:

package fragments;

import pickers.DateTimePickerFragment;
import pickers.DateTimePickerFragment.DateTimeSetListener;
import singletons.SingletonUser;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.Toast;
import br.bytecode.tarefas.R;
import classes.Event;
import database.Database;

public class NewEventFragment extends Fragment implements DateTimeSetListener {

    EditText name, place, date, contact;

    public NewEventFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {

        setHasOptionsMenu(true);
        View rootView = inflater.inflate(R.layout.fragment_new, container,
                false);

        name = (EditText) rootView.findViewById(R.id.new_input_name);
        place = (EditText) rootView.findViewById(R.id.new_input_place);
        date = (EditText) rootView.findViewById(R.id.new_input_datetime);
        contact = (EditText) rootView.findViewById(R.id.new_input_contact);

        return rootView;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        date.setOnTouchListener(new OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                DateTimePickerFragment dtp = new DateTimePickerFragment();
                dtp.show(getFragmentManager(), "date_time_picker");
                return false;
            }
        });
        super.onActivityCreated(savedInstanceState);
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.menu_newevent, menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();

        switch (id) {
        case R.id.menu_newevent_save:
            Event event = new Event();

            event.setUserId(SingletonUser.getInstance().getId());
            event.setName(name.getText().toString());
            event.setPlace(place.getText().toString());
            event.setDate(date.getText().toString());
            event.setContact(contact.getText().toString());

            Database db = new Database(getActivity());
            db.addEvent(event);

            Toast.makeText(getActivity(), "Evento criado com sucesso.",
                    Toast.LENGTH_SHORT).show();
            getActivity().finish();

        case R.id.menu_newevent_discard:
            getActivity().finish();
            // getActivity().getFragmentManager().popBackStack();
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onDateTimeSet(int dia, int mes, int ano, int hora, int minuto) {

    }

}

Note in the class declaration of fragment that it implements the interface I need. However, when running the program, I get the following error:

06-23 10:57:04.698: E/AndroidRuntime(18295): FATAL EXCEPTION: main
06-23 10:57:04.698: E/AndroidRuntime(18295): Process: br.bytecode.tarefas, PID: 18295
06-23 10:57:04.698: E/AndroidRuntime(18295): java.lang.ClassCastException: activities.ManagementActivity@424699e8 deve implementar DateTimeSetListener
06-23 10:57:04.698: E/AndroidRuntime(18295):    at pickers.DateTimePickerFragment.onAttach(DateTimePickerFragment.java:42)
06-23 10:57:04.698: E/AndroidRuntime(18295):    at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:849)
06-23 10:57:04.698: E/AndroidRuntime(18295):    at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1062)
06-23 10:57:04.698: E/AndroidRuntime(18295):    at android.app.BackStackRecord.run(BackStackRecord.java:684)
06-23 10:57:04.698: E/AndroidRuntime(18295):    at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1447)
06-23 10:57:04.698: E/AndroidRuntime(18295):    at android.app.FragmentManagerImpl$1.run(FragmentManager.java:443)
06-23 10:57:04.698: E/AndroidRuntime(18295):    at android.os.Handler.handleCallback(Handler.java:733)
06-23 10:57:04.698: E/AndroidRuntime(18295):    at android.os.Handler.dispatchMessage(Handler.java:95)
06-23 10:57:04.698: E/AndroidRuntime(18295):    at android.os.Looper.loop(Looper.java:136)
06-23 10:57:04.698: E/AndroidRuntime(18295):    at android.app.ActivityThread.main(ActivityThread.java:5086)
06-23 10:57:04.698: E/AndroidRuntime(18295):    at java.lang.reflect.Method.invokeNative(Native Method)
06-23 10:57:04.698: E/AndroidRuntime(18295):    at java.lang.reflect.Method.invoke(Method.java:515)
06-23 10:57:04.698: E/AndroidRuntime(18295):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
06-23 10:57:04.698: E/AndroidRuntime(18295):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
06-23 10:57:04.698: E/AndroidRuntime(18295):    at dalvik.system.NativeStart.main(Native Method)

It is as if the interface had not been implemented at any time within the fragment, because the mistake happens inside the Activity that contains it. Is there any solution to this? How can I make Android understand that the interface is in fragment and not in the Activity? The class that needs an interface is this:

package pickers;

import java.util.Calendar;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.os.Bundle;
import android.text.format.Time;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.DatePicker;
import android.widget.DatePicker.OnDateChangedListener;
import android.widget.TimePicker;
import android.widget.TimePicker.OnTimeChangedListener;
import br.bytecode.tarefas.R;

public class DateTimePickerFragment extends DialogFragment {

    Time now = new Time();
    private int dia, mes, ano, hora, minuto;
    private DateTimeSetListener mListener;
    boolean changedTime = false, changedDate = false;

    public DateTimePickerFragment() {
    }

    public interface DateTimeSetListener {
        public void onDateTimeSet(int dia, int mes, int ano, int hora,
                int minuto);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            mListener = (DateTimeSetListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " deve implementar DateTimeSetListener");
        }
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {

        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        LayoutInflater inflater = getActivity().getLayoutInflater();
        View rootView = inflater.inflate(R.layout.date_time_picker, null);

        TimePicker tPicker = (TimePicker) rootView
                .findViewById(R.id.timePicker1);
        DatePicker dPicker = (DatePicker) rootView
                .findViewById(R.id.datePicker1);

        now.setToNow();

        dPicker.init(now.year, now.month, now.monthDay,
                new OnDateChangedListener() {

                    @Override
                    public void onDateChanged(DatePicker view, int year,
                            int monthOfYear, int dayOfMonth) {
                        changedDate = true;
                        ano = year;
                        mes = monthOfYear;
                        dia = dayOfMonth;
                    }
                });

        tPicker.setIs24HourView(true);
        tPicker.setOnTimeChangedListener(new OnTimeChangedListener() {

            @Override
            public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
                changedTime = true;
                hora = hourOfDay;
                minuto = minute;
            }
        });

        builder.setView(rootView);
        builder.setTitle("Escolher data e hora");

        builder.setPositiveButton("OK", new OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int id) {
                if (mListener != null) {
                    if (changedTime == false) {
                        hora = now.hour;
                        minuto = now.minute;
                    }
                    if (changedDate == false) {
                        dia = Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
                        mes = Calendar.getInstance().get(Calendar.MONTH);
                        ano = Calendar.getInstance().get(Calendar.YEAR);
                    }
                    mListener.onDateTimeSet(dia, mes, ano, hora, minuto);
                }
            }
        });
        builder.setNegativeButton("Cancelar", new OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
            }
        });
        return builder.create();
    }

}

1 answer

1


The problem is that when you display the DateTimePickerFragment for NewEventFragment, the NewEventFragment is never passed as parameter in onAttach (Due to the life cycle of Fragment, he is bound/Attached to Activity before it is displayed/added to the layout), and yes to Activity who is supporting the two.

You have two options:

  1. To ManagementActivity will be the Listener of DateTimePickerFragment. What will involve a re-factoring in communication between the Activity and their Fragments.

  2. Change the way you assign Listener in the DateTimePickerFragment, doing it manually (using a setter). Then it would be:

    public class NewEventFragment extends Fragment implements DateTimeSetListener {
        // Código atual
        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            date.setOnTouchListener(new OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    DateTimePickerFragment dtp = new DateTimePickerFragment();
                    dtp.setDateTimeSetListener(NewEventFragment.this);
                    dtp.show(getFragmentManager(), "date_time_picker");
    
                    return false;
                }
            });
    
            super.onActivityCreated(savedInstanceState);
        }
    
        // Codigo atual
    }
    
    
    public class DateTimePickerFragment extends DialogFragment {
        // Código Atual
        @Override
        public void onAttach(Activity activity) {
            super.onAttach(activity);
            // Remove todo o codigo que tinha aqui
        }
    
        public void setDateTimeSetListener(DateTimeSetListener listener) {
            mListener = listener;
        }
        // Código atual
    }
    
  • Thank you very much, I preferred to use a Setter, I found it simpler.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.