Как разрешить исключение раздувания в пользовательском таймере? - PullRequest
0 голосов
/ 02 июля 2018

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

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

attrs.xml

<?xml version="1.0" encoding="utf-8"?>

<resources>
    <attr name="timePickerStyle" format="reference" />
    <declare-styleable name="CustomTimePicker">
       <attr name="internalLayout" format="reference"  />
    </declare-styleable>
 </resources>

time_picker_dialog.xml

<?xml version="1.0" encoding="utf-8"?>
<app.customview.CustomTimePicker xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/timePicker"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>

time_picker.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_gravity="center_horizontal"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layoutDirection="ltr">
        <!-- hour -->
        <NumberPicker
            android:id="@+id/hour"
            android:layout_width="70dip"
            android:layout_height="wrap_content"
            android:focusable="true"
            android:focusableInTouchMode="true"
            />

        <!-- minute -->
        <NumberPicker
            android:id="@+id/minute"
            android:layout_width="70dip"
            android:layout_height="wrap_content"
            android:layout_marginStart="5dip"
            android:focusable="true"
            android:focusableInTouchMode="true"
            />

        <!-- minute -->
        <NumberPicker
            android:id="@+id/amPm"
            android:layout_width="70dip"
            android:layout_height="wrap_content"
            android:layout_marginStart="5dip"
            android:focusable="true"
            android:focusableInTouchMode="true"
            />

</LinearLayout>

CustomTimePickerDialog.Java

package app.customview;


import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TimePicker;

import app.customview.CustomTimePicker.OnTimeChangedListener;

/**
 * A dialog that prompts the user for the time of day using a {@link TimePicker}.
 * <p/>
 * <p>See the <a href="{@docRoot}guide/topics/ui/controls/pickers.html">Pickers</a>
 * guide.</p>
 */
public class CustomTimePickerDialog extends AlertDialog
        implements OnClickListener, OnTimeChangedListener {

    private static final String HOUR = "hour";
    private static final String MINUTE = "minute";
    private static final String IS_24_HOUR = "is24hour";
    private final CustomTimePicker mTimePicker;
    private final OnTimeSetListener mCallback;
    int mInitialHourOfDay;
    int mInitialMinute;
    boolean mIs24HourView;
    private View view;
    /**
     * @param context      Parent.
     * @param callBack     How parent is notified.
     * @param hourOfDay    The initial hour.
     * @param minute       The initial minute.
     * @param is24HourView Whether this is a 24 hour view, or AM/PM.
     */
    public CustomTimePickerDialog(Context context,
                                  OnTimeSetListener callBack,
                                  int hourOfDay, int minute, boolean is24HourView) {
        this(context, 0, callBack, hourOfDay, minute, is24HourView);
    }

    /**
     * @param context      Parent.
     * @param theme        the theme to apply to this dialog
     * @param callBack     How parent is notified.
     * @param hourOfDay    The initial hour.
     * @param minute       The initial minute.
     * @param is24HourView Whether this is a 24 hour view, or AM/PM.
     */
    public CustomTimePickerDialog(Context context,
                                  int theme,
                                  OnTimeSetListener callBack,
                                  int hourOfDay, int minute, boolean is24HourView) {
        super(context, theme);
        mCallback = callBack;
        mInitialHourOfDay = hourOfDay;
        mInitialMinute = minute;
        mIs24HourView = is24HourView;

        setIcon(0);
        // buggy
        setTitle("Set Time");

        //Context themeContext = getContext();
        setButton(BUTTON_POSITIVE, "Done", this);

        LayoutInflater inflater = getLayoutInflater();

        try {
            view = inflater.inflate(R.layout.time_picker_dialog, null);
        } catch(android.view.InflateException e) {
            view = inflater.inflate(R.layout.time_picker_dialog, null);
            // do nothing
        }
        setView(view);
        mTimePicker = (CustomTimePicker) view.findViewById(R.id.timePicker);

        // initialize state
        mTimePicker.setIs24HourView(mIs24HourView);
        mTimePicker.setCurrentHour(mInitialHourOfDay);
        mTimePicker.setCurrentMinute(mInitialMinute);
        mTimePicker.setOnTimeChangedListener(this);

    }

    public void onClick(DialogInterface dialog, int which) {
        tryNotifyTimeSet();
    }

    public void updateTime(int hourOfDay, int minutOfHour) {
        mTimePicker.setCurrentHour(hourOfDay);
        mTimePicker.setCurrentMinute(minutOfHour);
    }

    private void tryNotifyTimeSet() {
        if (mCallback != null) {
            mTimePicker.clearFocus();
            mCallback.onTimeSet(mTimePicker, mTimePicker.getCurrentHour(),
                    mTimePicker.getCurrentMinute());
        }
    }

    @Override
    protected void onStop() {
        tryNotifyTimeSet();
        super.onStop();
    }

    @Override
    public Bundle onSaveInstanceState() {
        Bundle state = super.onSaveInstanceState();
        state.putInt(HOUR, mTimePicker.getCurrentHour());
        state.putInt(MINUTE, mTimePicker.getCurrentMinute());
        state.putBoolean(IS_24_HOUR, mTimePicker.is24HourView());
        return state;
    }

    @Override
    public void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        int hour = savedInstanceState.getInt(HOUR);
        int minute = savedInstanceState.getInt(MINUTE);
        mTimePicker.setIs24HourView(savedInstanceState.getBoolean(IS_24_HOUR));
        mTimePicker.setCurrentHour(hour);
        mTimePicker.setCurrentMinute(minute);
    }

    @Override
    public void onTimeChanged(CustomTimePicker view, int hourOfDay, int minute) {
        // TODO Auto-generated method stub

    }


    /**
     * The callback interface used to indicate the user is done filling in
     * the time (they clicked on the 'Set' button).
     */
    public interface OnTimeSetListener {

        /**
         * @param view      The view associated with this listener.
         * @param hourOfDay The hour that was set.
         * @param minute    The minute that was set.
         */
        void onTimeSet(CustomTimePicker view, int hourOfDay, int minute);
    }

}

CustomTimePicker.java

public CustomTimePicker(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        // initialization based on locale
        setCurrentLocale(Locale.getDefault());

        // process style attributes
         TypedArray attributesArray = context.obtainStyledAttributes(
                attrs, R.styleable.CustomTimePicker, defStyle, 0);
        int layoutResourceId = attributesArray.getResourceId(
           R.styleable.CustomTimePicker_internalLayout, R.layout.time_picker);
         attributesArray.recycle();

        LayoutInflater inflater = (LayoutInflater) context.getSystemService(
                Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(layoutResourceId, this, true);

        // hour
        mHourSpinner = (NumberPicker) findViewById(R.id.hour);
        mHourSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
            public void onValueChange(NumberPicker spinner, int oldVal, int newVal) {
                if (!is24HourView()) {
                    if ((oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY)
                            || (oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1)) {
                        mIsAm = !mIsAm;
                        updateAmPmControl();
                    }
                }
                onTimeChanged();
            }
        });


        // minute
        mMinuteSpinner = (NumberPicker) findViewById(R.id.minute);
        mMinuteSpinner.setMinValue(0);
        mMinuteSpinner.setMaxValue(3);
        mMinuteSpinner.setDisplayedValues(new String[]{"0", "15", "30", "45"});
        mMinuteSpinner.setFormatter(new TwoDigitFormatter());
        mMinuteSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
            public void onValueChange(NumberPicker spinner, int oldVal, int newVal) {
                onTimeChanged();
            }
        });

        /* Get the localized am/pm strings and use them in the spinner */
        mAmPmStrings = new DateFormatSymbols().getAmPmStrings();

        // am/pm
        View amPmView = findViewById(R.id.amPm);
        if (amPmView instanceof Button) {
            mAmPmSpinner = null;
            mAmPmButton = (Button) amPmView;
            mAmPmButton.setOnClickListener(new OnClickListener() {
                public void onClick(View button) {
                    button.requestFocus();
                    mIsAm = !mIsAm;
                    updateAmPmControl();
                    onTimeChanged();
                }
            });
        } else {
            mAmPmButton = null;
            mAmPmSpinner = (NumberPicker) amPmView;
            mAmPmSpinner.setMinValue(0);
            mAmPmSpinner.setMaxValue(1);
            mAmPmSpinner.setDisplayedValues(mAmPmStrings);
            mAmPmSpinner.setOnValueChangedListener(new OnValueChangeListener() {
                public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
                    picker.requestFocus();
                    mIsAm = !mIsAm;
                    updateAmPmControl();
                    onTimeChanged();
                }
            });
        }

        // update controls to initial state
        updateHourControl();
        updateAmPmControl();

        setOnTimeChangedListener(NO_OP_CHANGE_LISTENER);

        // set to current time
        setCurrentHour(mTempCalendar.get(Calendar.HOUR_OF_DAY));
        setCurrentMinute(mTempCalendar.get(Calendar.MINUTE));

        if (!isEnabled()) {
            setEnabled(false);
        }

    }

=============================

Именно эта строка в CustomTimePickerDialog.Java, которую андроид-студия продолжает говорить «может произойти исключение java.lang.null ...», и приложение также аварийно завершает работу, если я в любом случае пытаюсь получить доступ к объекту представления, так как оно возвращает нуль , Странно, но иногда этот фрагмент кода работает нормально, и я вижу, что средство выбора времени и приложение работают нормально, но в 90% случаев код с раздуванием представления возвращает ноль, и приложение вылетает.

Может ли кто-нибудь указать, что я могу сделать, чтобы исправить это (исправить предупреждение и в конечном итоге убедиться, что инфляция представления работает).

Спасибо

ПРИМЕЧАНИЕ ДЛЯ МОДЕРАТОРОВ: Пожалуйста, не отмечайте это как дубликат, это не является общей ошибкой «нулевого исключения». Я искал несколько дней, прежде чем задавать этот вопрос, так как не могу найти ответ, который мог бы решить мою проблему.

1 Ответ

0 голосов
/ 02 июля 2018

Вероятно, вы получаете эту ошибку, потому что вы получаете LayoutInflator с использованием системных служб, которые недоступны для Activity до onCreate (). Попробуйте получить компоновщик следующим образом:

LayoutInflater inflater = getLayoutInflater();
...