【问题标题】:MainActivity cannot be cast to android.app.TimePickerDialog$OnTimeSetListener Cannot be resolvedMainActivity 无法强制转换为 android.app.TimePickerDialog$OnTimeSetListener 无法解决
【发布时间】:2020-10-12 02:21:09
【问题描述】:

我不知道为什么我要更改一个活动以分段它没有按预期工作。

020-06-22 14:18:38.973 13510-13510/com.vikaskonaparthi.time E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.vikaskonaparthi.time, PID: 13510
java.lang.ClassCastException: com.vikaskonaparthi.time.MainActivity cannot be cast to android.app.TimePickerDialog$OnTimeSetListener
    at com.vikaskonaparthi.time.dialogs.TimePickerDialogFragment.onAttach(TimePickerDialogFragment.java:29)
    at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1247)
    at android.app.FragmentManagerImpl.addAddedFragments(FragmentManager.java:2431)
    at android.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2210)
    at android.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2166)
    at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2067)
    at android.app.FragmentManagerImpl$1.run(FragmentManager.java:742)
    at android.os.Handler.handleCallback(Handler.java:883)
    at android.os.Handler.dispatchMessage(Handler.java:100)
    at android.os.Looper.loop(Looper.java:214)
    at android.app.ActivityThread.main(ActivityThread.java:7397)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:935)

这是 Timepicker 对话框片段

public class TimePickerDialogFragment extends DialogFragment  {
private int hour;
private int minute;
private TimePickerDialog.OnTimeSetListener listener;

public static final String FRAGMENT_TAG = "time_picker";
public static final String BUNDLE_KEY_ALARM_HOUR = "alarm_hour";
public static final String BUNDLE_KEY_ALARM_MINUTE = "alarm_minute";


@Override
public void onAttach(Context context) {
    super.onAttach(context);
    listener = (TimePickerDialog.OnTimeSetListener) context;
}

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    Bundle bundle = getArguments();
    hour = bundle.getInt(BUNDLE_KEY_ALARM_HOUR);
    minute = bundle.getInt(BUNDLE_KEY_ALARM_MINUTE);

    final AlarmTimePickerDialog timePickerDialog = new AlarmTimePickerDialog(getActivity(), listener, hour, minute, true);

    LayoutInflater inflater = LayoutInflater.from(getActivity());
    View customTitleView = inflater.inflate(R.layout.partial_timepicker_dialog_title, null);

    timePickerDialog.setCustomTitle(customTitleView);

    timePickerDialog.setOnShowListener(new DialogInterface.OnShowListener() {
        @Override
        public void onShow(DialogInterface dialog) {
            timePickerDialog.showTimeLeft(hour, minute);
        }
    });

    return timePickerDialog;
}
}

这里是警告对话框

public class AlarmTimePickerDialog extends TimePickerDialog {

public AlarmTimePickerDialog(Context context, OnTimeSetListener listener, int hourOfDay, int minute,
                             boolean is24HourView) {
    super(context, listener, hourOfDay, minute, is24HourView);
}

@Override
public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
    super.onTimeChanged(view, hourOfDay, minute);
    showTimeLeft(hourOfDay, minute);
}

@Override
public void setCustomTitle(View customTitleView) {
    if (getContext().getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { //title is displayed in portrait orientation only
        super.setCustomTitle(customTitleView);
    }
}

public void showTimeLeft(int hour, int minute) {
    if (getContext().getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
        TextView textView = (TextView) this.findViewById(R.id.textview_timepickerdialog_timeleft);
        AlarmTime time = new AlarmTime(hour, minute);
        textView.setText(getContext().getString(R.string.all_time_left, time.getHoursLeft(), time.getMinutesLeft()));
    }
}
}

我见过很多这样的东西并尝试过,但没有任何效果。实际上,这段代码在活动中运行良好,但是当我将活动更改为碎片时,错误正在抛出。

提前谢谢你。

public class Fragment1 extends Fragment implements
    IntervalDialogFragment.IntervalDialogListener,
    NumberOfAlarmsDialogFragment.NumberOfAlarmsDialogListener,
    TimePickerDialog.OnTimeSetListener{

SwitchCompat onOffSwitch;
ListView alarmsListView;
TextView intervalBetweenAlarmsTextView;
TextView numberOfAlarmsTextView;
TextView firstAlarmTextView;
TextView timeLeftTextView;
LinearLayout firstAlarmLayout;
LinearLayout intervalLayout;
LinearLayout numberOfAlarmsLayout;
AlarmsListHelper alarmsListHelper;
SharedPreferencesHelper sharPrefHelper;
TimerManager timerManager;
AlarmParams alarmParams;
BroadcastReceiver timeLeftReceiver;
private final String LOG_TAG = Fragment1.class.getSimpleName();

final int ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE = 45;
final float DISPLAYED_NUMBERS_SIZE_RELATIVE_TO_TEXT_PROPORTION = 2f;  // number of alarms, first alarm, interval values text size is larger than text around them

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

    View root = inflater.inflate(R.layout.fragment1,container,false);
    alarmsListView = (ListView) root.findViewById(R.id.listview_main_alarmslist);
    onOffSwitch = (SwitchCompat) root.findViewById(R.id.switch_main);
    intervalBetweenAlarmsTextView = (TextView) root.findViewById(R.id.textview_main_interval);
    numberOfAlarmsTextView = (TextView) root.findViewById(R.id.textview_main_numberofalarms);
    firstAlarmLayout = (LinearLayout) root.findViewById(R.id.layout_main_firstalarm);
    firstAlarmTextView = (TextView) root.findViewById(R.id.textview_main_firstalarm_time);
    timeLeftTextView = (TextView) root.findViewById(R.id.textview_main_timeleft);
    intervalLayout = (LinearLayout) root.findViewById(R.id.layout_main_interval);
    numberOfAlarmsLayout = (LinearLayout) root.findViewById(R.id.layout_main_numberofalarms);

    sharPrefHelper = new SharedPreferencesHelper(getActivity());
    sharPrefHelper.printAll();

    alarmParams = sharPrefHelper.getParams();
    timerManager = new TimerManager(getActivity());
    alarmsListHelper = new AlarmsListHelper(getActivity(), alarmsListView);

    showFirstAlarmTime(alarmParams.firstAlarmTime.toString());
    showTimeLeft(alarmParams);

    showInterval(sharPrefHelper.getIntervalStr());
    showNumberOfAlarms(sharPrefHelper.getNumberOfAlarmsStr());
    onOffSwitch.setChecked(sharPrefHelper.isAlarmTurnedOn());

    alarmsListHelper.showList(alarmParams);

    onOffSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            alarmParams.turnedOn = isChecked;
            if (isChecked) {
                checkNotificationPolicy();
                checkOverlayPermission();
                timerManager.startSingleAlarmTimer(alarmParams.firstAlarmTime.toMillis());
                showToast(getString(R.string.main_alarm_turned_on_toast));
                sharPrefHelper.setNumberOfAlreadyRangAlarms(0);
            } else {
                timerManager.cancelTimer();
                showToast(getString(R.string.main_alarm_turned_off_toast));
            }
            alarmsListHelper.showList(alarmParams);
            showTimeLeft(alarmParams);
            sharPrefHelper.setAlarmState(isChecked);
        }
    });

    intervalLayout.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            IntervalDialogFragment dialog = new IntervalDialogFragment();
            Bundle intervalBundle = new Bundle();
            intervalBundle.putString(IntervalDialogFragment.BUNDLE_KEY_INTERVAL, sharPrefHelper.getIntervalStr());
            dialog.setArguments(intervalBundle);
            dialog.show(getActivity().getFragmentManager(), IntervalDialogFragment.FRAGMENT_TAG);
        }
    });

    numberOfAlarmsLayout.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            NumberOfAlarmsDialogFragment dialog = new NumberOfAlarmsDialogFragment();
            Bundle numberOfAlarmsBundle = new Bundle();
            numberOfAlarmsBundle.putString(NumberOfAlarmsDialogFragment.BUNDLE_KEY_NUMBER_OF_ALARMS, sharPrefHelper.getNumberOfAlarmsStr());
            dialog.setArguments(numberOfAlarmsBundle);
            dialog.show(getActivity().getFragmentManager(), NumberOfAlarmsDialogFragment.FRAGMENT_TAG);
        }
    });

    firstAlarmLayout.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Bundle timePickerBundle = new Bundle();
            timePickerBundle.putInt(TimePickerDialogFragment.BUNDLE_KEY_ALARM_HOUR, sharPrefHelper.getHour());
            timePickerBundle.putInt(TimePickerDialogFragment.BUNDLE_KEY_ALARM_MINUTE, sharPrefHelper.getMinute());

            TimePickerDialogFragment timePicker = new TimePickerDialogFragment();

            timePicker.setArguments(timePickerBundle);
            timePicker.show(getActivity().getFragmentManager(), TimePickerDialogFragment.FRAGMENT_TAG);
        }
    });

    return root;


}

@Override
public void onResume() {
    super.onResume();
    showTimeLeft(alarmParams);
    timeLeftReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context ctx, Intent intent) {
            if (intent.getAction().compareTo(Intent.ACTION_TIME_TICK) == 0) {  //i.e. every minute
                showTimeLeft(alarmParams);
            }
        }
    };
    getActivity().registerReceiver(timeLeftReceiver, new IntentFilter(Intent.ACTION_TIME_TICK));
}



@Override
public void onPause() {
    super.onPause();
    if (timeLeftReceiver != null) {
        getActivity().unregisterReceiver(timeLeftReceiver);
    }
}


@Override
public boolean onOptionsItemSelected(MenuItem item) {
    int id = item.getItemId();
    switch (id) {
        case R.id.action_settings: {
            Intent intent = new Intent(getActivity(), PrefActivity.class);
            startActivity(intent);
            break;
        }
    }
    return super.onOptionsItemSelected(item);
}


@Override
public void onIntervalChanged(String intervalStr) {
    showInterval(intervalStr);
    alarmParams.interval = Integer.parseInt(intervalStr);
    alarmsListHelper.showList(alarmParams);
    resetTimerIfTurnedOn();
    sharPrefHelper.setInterval(intervalStr);
}

@Override
public void onNumberOfAlarmsChanged(String numberOfAlarmsStr) {
    showNumberOfAlarms(numberOfAlarmsStr);
    alarmParams.numberOfAlarms = Integer.parseInt(numberOfAlarmsStr);
    alarmsListHelper.showList(alarmParams);
    resetTimerIfTurnedOn();
    sharPrefHelper.setNumberOfAlarms(numberOfAlarmsStr);
}

@Override
public void onTimeSet(TimePicker view, int hour, int minute) {
    AlarmTime alarmTime = new AlarmTime(hour, minute);
    alarmParams.firstAlarmTime = alarmTime;
    showFirstAlarmTime(alarmTime.toString());
    alarmsListHelper.showList(alarmParams);
    showTimeLeft(alarmParams);
    sharPrefHelper.setNumberOfAlreadyRangAlarms(0);
    resetTimerIfTurnedOn();
    sharPrefHelper.setTime(alarmTime);
}

private void showToast(String message) {
    Toast.makeText(getActivity(), message, Toast.LENGTH_SHORT).show();
}

private void resetTimerIfTurnedOn() {
    if (onOffSwitch.isChecked()) {
        timerManager.resetSingleAlarmTimer(alarmParams.firstAlarmTime.toMillis());
        showToast(getString(R.string.main_alarm_reset_toast));
    }
}

private void showInterval(String interval) {
    String wholeTitle = getString(R.string.main_interval, interval);
    SpannableString wholeTitleSpan = new SpannableString(wholeTitle);
    wholeTitleSpan.setSpan(new RelativeSizeSpan(DISPLAYED_NUMBERS_SIZE_RELATIVE_TO_TEXT_PROPORTION), wholeTitle.indexOf(interval), interval.length() + 1, 0);
    intervalBetweenAlarmsTextView.setText(wholeTitleSpan);
}

private void showNumberOfAlarms(String numberOfAlarms) {
    int numberOfAlarmsInt = Integer.parseInt(numberOfAlarms);
    String wholeTitle = this.getResources().getQuantityString(R.plurals.main_number_of_alarms, numberOfAlarmsInt, numberOfAlarmsInt);
    SpannableString wholeTitleSpan = new SpannableString(wholeTitle);
    wholeTitleSpan.setSpan(new RelativeSizeSpan(DISPLAYED_NUMBERS_SIZE_RELATIVE_TO_TEXT_PROPORTION),
            wholeTitle.indexOf(numberOfAlarms),
            numberOfAlarms.length() + 1, 0);
    numberOfAlarmsTextView.setText(wholeTitleSpan);
}

private void showFirstAlarmTime(String firstAlarmTime) {
    String wholeTitle = getString(R.string.main_firstalarm_time, firstAlarmTime);
    SpannableString wholeTitleSpan = new SpannableString(wholeTitle);
    wholeTitleSpan.setSpan(new RelativeSizeSpan(DISPLAYED_NUMBERS_SIZE_RELATIVE_TO_TEXT_PROPORTION),
            wholeTitle.indexOf(firstAlarmTime) - 1,
            wholeTitle.indexOf(firstAlarmTime) + firstAlarmTime.length(), 0);
    firstAlarmTextView.setText(wholeTitleSpan);
}

private void showTimeLeft(AlarmParams alarmParams) {
    AlarmTime alarmTime = alarmParams.firstAlarmTime;
    timeLeftTextView.setText(getString(R.string.all_time_left, alarmTime.getHoursLeft(), alarmTime.getMinutesLeft()));
    if (alarmParams.turnedOn) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            timeLeftTextView.setTextColor(getActivity().getColor(R.color.primary));
        }
    } else {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            timeLeftTextView.setTextColor(getActivity().getColor(R.color.main_disabled_textcolor));
        }
    }
    Log.d(LOG_TAG, "Time left: "+alarmTime.getHoursLeft() + ":" + alarmTime.getMinutesLeft());
}

private void checkNotificationPolicy() {
    NotificationManager notificationManager =
            (NotificationManager) getActivity().getSystemService(Context.NOTIFICATION_SERVICE);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
            && !notificationManager.isNotificationPolicyAccessGranted()) {
        Intent intent = new Intent(
                android.provider.Settings
                        .ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS);
        startActivity(intent);
    }
}

/**
 * needed for Android Q: on some devices activity doesn't show from fullScreenNotification without
 * permission SYSTEM_ALERT_WINDOW
 */
private void checkOverlayPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        if ((Build.VERSION.SDK_INT > Build.VERSION_CODES.P) && (!Settings.canDrawOverlays(getActivity()))) {
            Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                    Uri.parse("package:" + getActivity().getPackageName()));
            startActivityForResult(intent, ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE);
        }
    }
}
}

【问题讨论】:

  • 既然你在做listener = (TimePickerDialog.OnTimeSetListener) context;,那么底层的活动上下文是否实现了TimePickerDialog.OnTimeSetListener
  • 基础是它没有实现的主要活动
  • 那么你需要,context 里面的onAttach 表示活动而不是调用时间选择器对话框的片段。您还可以检查getParentFragment 并相应地更改实现。
  • 我没明白

标签: java android android-studio android-fragments android-activity


【解决方案1】:

使用子片段管理器展示您的时间选择对话:

timePicker.show(getChildFragmentManager(), TimePickerDialogFragment.FRAGMENT_TAG);

子片段管理器有什么用? Java 文档将帮助我们:

    /**
     * Return a private FragmentManager for placing and managing Fragments
     * inside of this Fragment.
     */
    @NonNull
    final public FragmentManager getChildFragmentManager() {
        if (mHost == null) {
            throw new IllegalStateException("Fragment " + this + " has not been attached yet.");
        }
        return mChildFragmentManager;
    }

因此,您的时间选择器对话将由Fragment1“管理”(当然不是直接由片段管理)。

更改片段管理器后,您现在可以将TimePickerDialogFragment 的父片段(不是管理器)转换为TimePickerDialog.OnTimeSetListener

public class TimePickerDialogFragment extends DialogFragment  {
    ...
    private TimePickerDialog.OnTimeSetListener listener;
    ...

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        listener = (TimePickerDialog.OnTimeSetListener) getParentFragment();
    }

...

您可以通过调用getParentFragment()获取父片段:

    /**
     * Returns the parent Fragment containing this Fragment.  If this Fragment
     * is attached directly to an Activity, returns null.
     */
    @Nullable
    final public Fragment getParentFragment() {
        return mParentFragment;
    }

注意:注意可能的内存泄漏。

评论相关更新

DialogFragment 扩展TimePickerDialogFragment androidx 包:

【讨论】:

  • 无法解析符号'show(androidx.fragment.app.FragmentManager)
  • @VikasKonaparthi,答案已更新。使用androidx.fragment.app.DialogFragment
  • 非常感谢您
【解决方案2】:

尝试为您的片段实现 TimePickerDialog.OnTimeSetListener:

public class TimePickerDialogFragment extends DialogFragment implements TimePickerDialog.OnTimeSetListener

////

@Override
    public void onAttach(Context context) {
        super.onAttach(context);
        listener = this;
    }

    @Override
    public void onTimeSet(TimePicker timePicker, int i, int i1) {
        // get selected time
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-11
    • 1970-01-01
    • 2019-03-09
    • 1970-01-01
    • 2018-02-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多