TimePicker onTimeSet not being called

好久不见. 提交于 2019-12-18 03:47:48

问题


I'm using a time picker to let the user enter his desired time to do a specific task, I'm using the DialogFragment class that's available in the support library for backward compatibility with older Android versions.

Here is my code to create the TimePickerFragment class, created in a seperate file, taken from: http://developer.android.com/guide/topics/ui/controls/pickers.html :

package com.calls.only;
import java.util.Calendar;
import android.app.Dialog;
import android.app.TimePickerDialog;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.widget.TimePicker;


public class TimePickerFragment extends DialogFragment
                            implements TimePickerDialog.OnTimeSetListener {

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        // Use the current time as the default values for the picker
        final Calendar c = Calendar.getInstance();
        int hour = c.get(Calendar.HOUR_OF_DAY);
        int minute = c.get(Calendar.MINUTE);

        // Create a new instance of TimePickerDialog and return it
        return new TimePickerDialog(getActivity(), this, hour, minute, false);
    }

    public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
        // Do something with the time chosen by the user
    }
}

Main Activity:

package com.calls.only;


import java.util.Calendar;
import java.util.TimeZone;
import android.os.Bundle;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.DialogFragment;
import android.view.Menu;
import android.view.View;
import android.widget.RadioButton;
import android.widget.TextView;

public class MainActivity extends FragmentActivity {

public void InputStartTime(View v) {
    DialogFragment newFragment = new TimePickerFragment();
    newFragment.show(getSupportFragmentManager(), "timePicker");

}

private TimePickerDialog.OnTimeSetListener mTimeSetListener =
        new TimePickerDialog.OnTimeSetListener() {
                    //Overriding onTimeSet causes an error, see below
            public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
               Log.i("TimePicker", "Time picker set!");
            }
        };

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.activity_main, menu);
    return true;
}
}

the onTimeset method is not being called as I can see from the log, if I try to override this method, I get the error: "The method onTimeSet(TimePicker, int, int) of type new TimePickerDialog.OnTimeSetListener(){} must override a superclass method"

can anyone tell me what the problem is? I've been trying to figure it out and it left me with too much frustration!


回答1:


the onTimeset method is not being called as I can see from the log

Well, that's because when you create the TimePickerDialog, you supply the fragment as OnTimeSetListener:

return new TimePickerDialog(getActivity(), this, hour, minute, false);
                                             ^

In other words: you're not seeing the log statement because the mTimeSetListener variable in your activity never gets set as listener to the dialog you create in the fragment.

You can easily fix this by either casting the activity the fragment is attached to to your MainActivity, or, if you prefer something more reusable, have it callback through an interface. In this case you could reuse the OnTimeSetListener interface, but you could also set up your own that, for instance, passes on a Calendar object back to the activity rather than the raw hour/minute values.

In it's most basic form, it would look somewhat like this:

public class TimePickerFragment extends DialogFragment {

    @Override public Dialog onCreateDialog(Bundle savedInstanceState) {
        // ... omitted

        if (!(getActivity() instanceof OnTimeSetListener)) throw new IllegalStateException("Activity should implement OnTimeSetListener!");
        OnTimeSetListener timeSetListener =  (OnTimeSetListener) getActivity();

        // Create a new instance of TimePickerDialog and return it
        return new TimePickerDialog(getActivity(), timeSetListener, hour, minute, false);
    }
}

And then have your MainActivity implement that same interface, in stead of using an anonymous innerclass:

public class MainActivity extends FragmentActivity implements TimePickerDialog.OnTimeSetListener { 

    @Override public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
        Log.i("TimePicker", "Time picker set!");
    }
}

Update: As mentioned in the comments, to enabled support for multiple pickers, you have several options. One is to keep track of what dialog is displayed in the hosting activity; a boolean would do fine if you only need to differentiate between two pickers, otherwise an enum would be an appropriate way to implement more than two states. You'll want to make sure that this piece of information is retained during configuration changes though...

However, what I'd prefer is to do, is to be able to identify the source of the result returned in onTimeSet(...) by supplying an id to every picker. That id is then included in the result so that we can tell where it came from. I'll outline the general idea below:

public class TimePickerFragment extends DialogFragment implements OnTimeSetListener {

    private int mId;
    private TimePickerDialogListener mListener;

    private static TimePickerFragment newInstance(int id) {
        Bundle args = new Bundle();
        args.putInt("picker_id", id);
        TimePickerFragment fragment = new TimePickerFragment();
        fragment.setArguments(args);
        return fragment;
    }

    @Override public Dialog onCreateDialog(Bundle savedInstanceState) {
        // ... omitted

        mId = getArguments().getInt("picker_id");
        mListener = getActivity() instanceof TimePickerDialogListener ? (TimePickerDialogListener) getActivity() : null;

        // Create a new instance of TimePickerDialog and return it
        return new TimePickerDialog(getActivity(), this, hour, minute, false);
    }

    @Override public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
        if (mListener != null) mListener.onTimeSet(mId, view, hourOfDay, minute);
    }

    public static interface TimePickerDialogListener {
        public void onTimeSet(int id, TimePicker view, int hourOfDay, int minute);
    }

}

What we've changed above is to have the dialog itself be registered as OnTimeSetListener, for which it will then pass on data through the TimePickerDialogListener, provided the hosting activity implements that interface. So that's what we need to do in the next step. Also, note that I've added a static convenience method to create a new TimePickerFragment that takes an id. This value will be set as argument to the fragment, ensuring that it becomes part of the fragment's state, so you don't have to worry about configuration changes yourself - the framework will do that for you.

So let's change MainActivity to implement our custom interface, and have it use the newInstance method:

public class MainActivity extends FragmentActivity implements TimePickerFragment.TimePickerDialogListener { 

    private static final int START_TIME_PICKER_ID = 1;
    private static final int END_TIME_PICKER_ID = 2;

    public void InputStartTime(View v) {
        // supply the appropriate id - I'm assuming you'll be adding an InputEndTime method somewhere that will then supply END_TIME_PICKER_ID 
        DialogFragment newFragment = TimePickerFragment.newInstance(START_TIME_PICKER_ID);
        newFragment.show(getSupportFragmentManager(), "timePicker");
    }

    @Override public void onTimeSet(int id, TimePicker view, int hourOfDay, int minute) {
        Log.i("TimePicker", "Time picker set from id " + id + "!");

        // here you can compare the id value to figure out what picker this data came from
    }
}

Just one final note: I typed this directly into my browser, so be aware of any obvious typos.




回答2:


I made the code use it.

public class TimePickerFragment extends DialogFragment{
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        // Use the current time as the default values for the picker
        final Calendar c = Calendar.getInstance();
        int hour = c.get(Calendar.HOUR_OF_DAY);
        int minute = c.get(Calendar.MINUTE);

        // Create a new instance of TimePickerDialog and return it
        return new TimePickerDialog(getActivity(), (MainActivity)getActivity(), hour, minute, false);
    }
}


public class MainActivity extends FragmentActivity  implements TimePickerDialog.OnTimeSetListener{

    public void InputStartTime(View v) {
        DialogFragment newFragment = new TimePickerFragment();
        newFragment.show(getSupportFragmentManager(), "timePicker");

    }

    @Override
    public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
        // TODO Auto-generated method stub
        Log.i("TimePicker", "Time picker set!");
    }

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }
}


来源:https://stackoverflow.com/questions/15915318/timepicker-ontimeset-not-being-called

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!