TimePicker onTimeSet не вызывается

Я использую средство выбора времени, чтобы пользователь мог ввести желаемое время для выполнения определенной задачи, я использую класс DialogFragment, который доступен в библиотеке поддержки для обратной совместимости со старыми версиями Android.

Вот мой код для создания класса TimePickerFragment, созданного в отдельном файле, взятый из: 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
    }
}

Основная деятельность:

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

метод onTimeset не вызывается, как я вижу из журнала, если я пытаюсь переопределить этот метод, я получаю ошибку: "Метод onTimeSet(TimePicker, int, int) типа new TimePickerDialog.OnTimeSetListener(){} должен переопределить метод суперкласса

Может кто-нибудь сказать мне, в чем проблема? Я пытался понять это, и это оставило меня слишком много разочарований!

2 ответа

Решение

метод onTimeset не вызывается, как я вижу из журнала

Ну, это потому, что когда вы создаете TimePickerDialogВы предоставляете фрагмент как OnTimeSetListener:

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

Другими словами: вы не видите оператора журнала, потому что mTimeSetListener переменная в вашей деятельности никогда не будет установлена ​​как слушатель диалога, который вы создаете во фрагменте.

Вы можете легко исправить это, применив действие, к которому прикреплен фрагмент. MainActivityили, если вы предпочитаете что-то более повторно используемое, используйте обратный вызов через интерфейс. В этом случае вы можете использовать OnTimeSetListener интерфейс, но вы также можете настроить свой собственный, который, например, передает Calendar Возвратитесь к действию, а не к необработанным значениям часа / минуты.

В своей основной форме это будет выглядеть примерно так:

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

И тогда у вас есть MainActivity реализовать тот же интерфейс вместо использования анонимного внутреннего класса:

public class MainActivity extends FragmentActivity implements TimePickerDialog.OnTimeSetListener { 

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

Обновление: как уже упоминалось в комментариях, чтобы включить поддержку нескольких сборщиков, у вас есть несколько вариантов. Один из них - отслеживать, какой диалог отображается в хостинге; логическое будет хорошо, если вам нужно различать только два средства выбора, в противном случае перечисление будет подходящим способом для реализации более двух состояний. Вы хотите убедиться, что эта часть информации сохраняется во время изменений конфигурации...

Тем не менее, я бы предпочел сделать так, чтобы можно было определить источник результата, возвращенного в onTimeSet(...) предоставляя идентификатор каждому сборщику. Этот идентификатор затем включается в результат, чтобы мы могли сказать, откуда он пришел. Я изложу общую идею ниже:

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

}

Что мы изменили выше, так это чтобы сам диалог был зарегистрирован как OnTimeSetListener, для которого он будет затем передавать данные через TimePickerDialogListenerпри условии, что хостинг реализует этот интерфейс. Вот что нам нужно сделать на следующем шаге. Также обратите внимание, что я добавил статический удобный метод для создания нового TimePickerFragment это берет идентификатор. Это значение будет установлено в качестве аргумента для фрагмента, гарантируя, что оно станет частью состояния фрагмента, поэтому вам не нужно беспокоиться об изменениях конфигурации самостоятельно - инфраструктура сделает это за вас.

Итак, давайте изменим MainActivity реализовать наш пользовательский интерфейс и использовать его newInstance метод:

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

Последнее замечание: я набрал это прямо в своем браузере, так что будьте в курсе любых очевидных опечаток.

Я сделал код использовать его.

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;
    }
}
Другие вопросы по тегам