I have create a custom time picker dialog in my android app, and android studio keeps showing me this warning on the code that "inflater.inflate may produce null exception".
Here are the xml files for the custom timepicker:
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);
}
}
=============================
It is this line in CustomTimePickerDialog.Java which android studio keeps saying "may producc java.lang.null exception..." and the app also crashes if I try to access the view object in anyway, as it is returning null. Strangely, occasionally this piece of code runs fine and i can see the timepicker and app works fine, but 90% of time, the view inflate code returns null and app crashes.
Can somebody point out what it is I can do to fix this (fix the warning and eventually make sure the view inflation works).
Thanks
NOTE TO MODERATORS: Please do not mark this as duplicate, this is not a generic "null exception" error problem. I have searched for days before asking this question as I cannot find any answer that might solve my problem.
You are probably getting that error because you are getting LayoutInflator
using System services, which are not available to Activities before onCreate(). Try getting layout inflator in the following way:
LayoutInflater inflater = getLayoutInflater();