Исключение Android NullPointer?

Привет, когда я пытаюсь установить текущий прогресс seekbar, который является предпочтением, на основе текущего уровня громкости звонка в onResume я получаю следующее:

12-31 22:02:12.559: E/AndroidRuntime(266): java.lang.RuntimeException: Unable to resume activity {com.camelCaseD.nsettings/com.camelCaseD.nsettings.Toggles}: java.lang.NullPointerException
12-31 22:02:12.559: E/AndroidRuntime(266):  at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2120)
12-31 22:02:12.559: E/AndroidRuntime(266):  at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2135)
12-31 22:02:12.559: E/AndroidRuntime(266):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1668)
12-31 22:02:12.559: E/AndroidRuntime(266):  at android.app.ActivityThread.access$1500(ActivityThread.java:117)
12-31 22:02:12.559: E/AndroidRuntime(266):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)
12-31 22:02:12.559: E/AndroidRuntime(266):  at android.os.Handler.dispatchMessage(Handler.java:99)
12-31 22:02:12.559: E/AndroidRuntime(266):  at android.os.Looper.loop(Looper.java:123)
12-31 22:02:12.559: E/AndroidRuntime(266):  at android.app.ActivityThread.main(ActivityThread.java:3683)
12-31 22:02:12.559: E/AndroidRuntime(266):  at java.lang.reflect.Method.invokeNative(Native Method)
12-31 22:02:12.559: E/AndroidRuntime(266):  at java.lang.reflect.Method.invoke(Method.java:507)
12-31 22:02:12.559: E/AndroidRuntime(266):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
12-31 22:02:12.559: E/AndroidRuntime(266):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
12-31 22:02:12.559: E/AndroidRuntime(266):  at dalvik.system.NativeStart.main(Native Method)
12-31 22:02:12.559: E/AndroidRuntime(266): Caused by: java.lang.NullPointerException
12-31 22:02:12.559: E/AndroidRuntime(266):  at com.camelCaseD.nsettings.SeekBarPreference.setProgressC(SeekBarPreference.java:215)
12-31 22:02:12.559: E/AndroidRuntime(266):  at com.camelCaseD.nsettings.Toggles.onResume(Toggles.java:112)
12-31 22:02:12.559: E/AndroidRuntime(266):  at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1150)
12-31 22:02:12.559: E/AndroidRuntime(266):  at android.app.Activity.performResume(Activity.java:3832)
12-31 22:02:12.559: E/AndroidRuntime(266):  at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2110)
12-31 22:02:12.559: E/AndroidRuntime(266):  ... 12 more

Вот класс SeekBarPreference:

import com.camelCaseD.nsettings.R;

import android.content.Context;
import android.content.res.TypedArray;
import android.preference.Preference;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.SeekBar;
import android.widget.TableLayout;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.media.AudioManager;

public class SeekBarPreference extends Preference implements OnSeekBarChangeListener {

    private final String TAG = getClass().getName();

    private static final int DEFAULT_VALUE = 50;

    private int mMinValue      = 0;
    private int mCurrentValue;
    private SeekBar mSeekBar;

    private AudioManager mgr=null;

    private View mView;

    private int mStream;

    public SeekBarPreference(Context context, AttributeSet attrs, int stream) {
        super(context, attrs);

        mStream = stream;
    }

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

        mStream = stream;
    }

    @Override
    protected View onCreateView(ViewGroup parent){

        TableLayout layout =  null;

        try {
            LayoutInflater mInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);

            layout = (TableLayout)mInflater.inflate(R.layout.seek_bar_preference, parent, false);
        }
        catch(Exception e)
        {
            Log.e(TAG, "Error creating seek bar preference", e);
        }

        return layout;

    }

    private void initBar(SeekBar bar, final int stream, View view) {
        mgr=(AudioManager)getContext().getSystemService(Context.AUDIO_SERVICE);

        bar.setMax(mgr.getStreamMaxVolume(stream));
        bar.setProgress(mgr.getStreamVolume(stream));

        TextView mTitle = (TextView) view.findViewById(android.R.id.title);
        TextView mSummary = (TextView) view.findViewById(android.R.id.summary);

        switch(stream) {
        case AudioManager.STREAM_RING:
            mTitle.setText("Ringer Volume");
            mSummary.setText("Slide to adjust ringer volume.");
            break;

        case AudioManager.STREAM_MUSIC:
            mTitle.setText("Media Volume");
            mSummary.setText("Slide to adjust media volume.");
            break;
        }

        bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
          public void onProgressChanged(SeekBar bar, int progress,
                                        boolean fromUser) {
            mgr.setStreamVolume(stream, progress,
                                AudioManager.FLAG_PLAY_SOUND);
          }

          public void onStartTrackingTouch(SeekBar bar) {
            // no-op
          }

          public void onStopTrackingTouch(SeekBar bar) {
            // no-op
          }
        });
      }

    @Override
    public void onBindView(View view) {
        super.onBindView(view);
        try
        {
            mView = view;
            mSeekBar = (SeekBar) view.findViewById(R.id.seek_bar);
            initBar(mSeekBar, mStream, view);
        }
        catch(Exception ex) {
            Log.e(TAG, "Error binding view: " + ex.toString());
        }

        updateView(view);
    }

    /**
     * Update a SeekBarPreference view with our current state
     * @param view
     */
    protected void updateView(View view) {

        try {
            TableLayout layout = (TableLayout)view;

            mSeekBar.setProgress(mCurrentValue - mMinValue);
        }
        catch(Exception e) {
            Log.e(TAG, "Error updating seek bar preference", e);
        }

    }

    @Override 
    protected Object onGetDefaultValue(TypedArray ta, int index){

        int defaultValue = ta.getInt(index, DEFAULT_VALUE);
        return defaultValue;

    }

    @Override
    protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {

    }

    public void setProgressC(int stream) {
        mgr=(AudioManager)getContext().getSystemService(Context.AUDIO_SERVICE);
        switch(stream) {
        case AudioManager.STREAM_RING:
            SeekBar bar = (SeekBar)mView.findViewById(R.id.seek_bar);
            bar.setProgress(mgr.getStreamVolume(AudioManager.STREAM_RING));
            break;
        }
    }

}

Класс представления расширяет Preference, и макет представления показан ниже:

<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res/com.commonsware.android.syssvc.volume"
  android:stretchColumns="1"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:paddingLeft="20px"
  android:paddingRight="10px"
>
  <TableRow android:paddingTop="10px" 
            android:paddingBottom="2px" >
            <TextView android:id="@android:id/title" android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:textSize="22dp"
            android:typeface="sans"
            android:textStyle="normal"
            android:textColor="#ffffff" />
  </TableRow>
  <TableRow android:paddingTop="2px" 
            android:paddingBottom="2px" >
  <TextView android:id="@android:id/summary" 
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" />
  </TableRow>
  <TableRow
    android:paddingBottom="20px">
    <SeekBar
      android:id="@+id/seek_bar"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
    />
   </TableRow>  
</TableLayout>

Затем внутри моего класса PreferenceActivity:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    PreferenceCategory mAudCat = (PreferenceCategory) findPreference("audCat");

    SeekBarPreference mRingerVol = new SeekBarPreference(this, null, AudioManager.STREAM_RING);
    mRingerVol.setKey("ringerVol");

    mAudCat.addPreference(mRingerVol);
}

@Override
public void onResume() {
    super.onResume();

    SeekBarPreference mRingerVol = (SeekBarPreference) findPreference("ringerVol");
    mRingerVol.setProgressC(AudioManager.STREAM_RING);
}

Любая помощь будет оценена.


person camelCaseD    schedule 31.12.2011    source источник
comment
Какая строка 215 в setProgressC?   -  person Alex Paino    schedule 01.01.2012
comment
Какая строка кода в setProgressC() вызывает исключение? А как выглядит остальная часть SeekBarPreference?   -  person tomtheguvnor    schedule 01.01.2012
comment
(Алекс имеет в виду единственную действительно полезную строку в трассировке: at com.camelCaseD.nsettings.SeekBarPreference.setProgressC(SeekBarPreference.java:215) ‹-- это ВАШ код :-)   -  person    schedule 01.01.2012
comment
Я предполагаю, что это строка 215? bar.setProgress(mgr.getStreamVolume(AudioManager.STREAM_RING)); Если это так, попробуйте Project -> Clean пересобрать проект. Часто Eclipse допускает ошибку, связанную с макетом XML, и для ее исправления достаточно очистки проекта.   -  person theisenp    schedule 01.01.2012
comment
Я действительно не понимаю, почему многие из этих NPE не закрываются немедленно из-за того, что они слишком локализованы. Если нет возможности создать отдельный заголовок, то... вероятно, проблема лучше всего решается с помощью использования отладчика, чтобы увидеть, какое выражение оценивается как null.   -  person    schedule 01.01.2012
comment
stackoverflow .com/questions/8103296/ — см. ответ Алекса   -  person    schedule 01.01.2012
comment
@pst что вы имеете в виду под использованием отладчика, чтобы увидеть, какое выражение оценивается как нуль, поэтому я предполагаю использовать отладчик в eclipse?   -  person camelCaseD    schedule 01.01.2012
comment
ДА Не угадывайте! Перехватите исключение, а затем покопайтесь. Хотя часто случается так, что NPE можно легко увидеть, ведение журнала (и SO :-) не заменяет просмотр состояния во время исключения. Вид был найден? (Например, это может вернуть null. И, если не было причиной, что было null, хотя этого быть не должно было?)   -  person    schedule 01.01.2012
comment
бу ху. Я понял проблему, за исключением того, что не могу опубликовать ответ еще 8 часов. Мне нужно еще всего семь повторений, чтобы сделать это прямо сейчас.   -  person camelCaseD    schedule 01.01.2012
comment
Разве вы не должны вызывать addPreferencesFromResource или каким-то образом загружать xml перед попыткой вызвать findViewById?   -  person kingston    schedule 01.01.2012
comment
@herschel нет, мне не нужно этого делать, потому что файл xml представляет собой TableLayout, и при создании пользовательского представления внутри класса вы используете findViewById   -  person camelCaseD    schedule 01.01.2012


Ответы (1)


Как я понял источник ошибки.

В setProgressC переменная mView имеет значение null после того, как я вывел значение этой переменной в onBindView, а сам setProgressC в LogCat.

person camelCaseD    schedule 01.01.2012