Исключение нулевого указателя с массивом кнопок при установке OnClickListener с добавлением putExtra в Intents

1

Я пытаюсь написать игру-головоломку для Android с выбором уровня в первой активности и реальной головоломке во второй активности. Первое действие должно содержать информацию о номере головоломки, выбранном для второго действия, чтобы второе действие могло загрузить соответствующую информацию. Это отлично работало, пока я не попытался очистить код и поместил свои кнопки в массивы:

Например,

Я ранее имел:

    puzzle0 =  (Button) findViewById(R.id.puzzle0);
    puzzle1 =  (Button) findViewById(R.id.puzzle1);
    puzzle2 =  (Button) findViewById(R.id.puzzle2);


    puzzle0.setOnClickListener(new View.OnClickListener() {
        public void onClick(View view) {
            Intent intent = new Intent(view.getContext(), Puzzle.class);
            intent.putExtra("LevelNumber", "0");
            startActivityForResult(intent, 0);
        }
    });


    puzzle1.setOnClickListener(new View.OnClickListener() {
        public void onClick(View view) {
            Intent intent = new Intent(view.getContext(), Puzzle.class);
            intent.putExtra("LevelNumber", "1");
            startActivityForResult(intent, 1);
        }
    });

    puzzle2.setOnClickListener(new View.OnClickListener() {
        public void onClick(View view) {
            Intent intent = new Intent(view.getContext(), Puzzle.class);
            intent.putExtra("LevelNumber", "2");
            startActivityForResult(intent, 2);
        }
    });

Вышеприведенный код отлично поработал и позволил мне получить правильную информацию во второй игре "Головоломка" и загрузить соответствующую загадку.

Поскольку у меня появилось еще много головоломок, кажется, что нужно использовать цикл for и автоматизировать это немного:

private void initializePuzzleButtons() {
    for(int i = 0; i < numberOfPuzzles; i++)
    {
        Log.i("Trial","A" + i);
        int puzzleButtonID = getResources().getIdentifier("puzzle" + i, "button", this.getPackageName());
        Log.i("Trial","B" + i);
        puzzleButtons[i] = (Button) findViewById(puzzleButtonID);
        Log.i("Trial","C" + i);
        final int j = i;
        Log.i("Trial","D" + i);
    }
    for(int i = 0; i < numberOfPuzzles; i++)
    {   
        final int j = i;
        puzzleButtons[i].setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                Intent intent = new Intent(view.getContext(), Puzzle.class);
                Log.i("Trial","E" + j);
                intent.putExtra("LevelNumber", j + "");
                Log.i("Trial","F" + j);
                startActivityForResult(intent, j);
            }
        });
    }

}

Команды Log в LogCat показывают, что исключение NullPointerException выбрано во втором цикле. То есть, LogCat показывает A1, B1, C1..., A2, B2, C3,... вплоть до D6 (ПРИМЕЧАНИЕ: numberOfPuzzles = 7), а затем генерируется исключение.

Мое обоснование использования переменной j состоит в том, что требуется конечная переменная (нельзя использовать только i), поскольку, как показывает Eclipse: "Нельзя ссылаться на не конечную переменную j внутри внутреннего класса, определенного другим методом", если j не окончательный.

Я думал, что переменная j вызывает проблему, но я заменил каждый j буквой 0 и все еще получил исключение NullPointerException

То есть,

for(int i = 0; i < numberOfPuzzles; i++)
    {   
        final int j = i;
        puzzleButtons[i].setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                Intent intent = new Intent(view.getContext(), Puzzle.class);
                Log.i("Trial","E" + 0);
                intent.putExtra("LevelNumber", 0 + "");
                Log.i("Trial","F" + 0);
                startActivityForResult(intent, 0);
            }
        });
    }

}

все еще вызывает исключение NullPointerException. Возможно, мне здесь что-то не хватает, но я много часов ломаю голову. Я смотрел на других в подобных дилеммах, но все ответы, которые я нашел, не используют "New View.OnClickListener" в качестве аргумента для setOnClickListener (они используют "это"), поскольку им не нужно отправлять дополнительные данные в под-активность и может разрешать Действия для реализации OnClickListener. Это не сработало бы в моем случае, так как Activity могла только в целом реализовать OnClickListener, и мне нужна конкретная строка, которая должна быть связана с каждой кнопкой (с помощью команды putExtra).

Любая помощь приветствуется!

  • 0
    Если вы публикуете ошибку Logcat, то легко найти, какое именно исключение?
Теги:
arrays
button
nullpointerexception
onclicklistener

3 ответа

1
Лучший ответ

замещать

int puzzleButtonID = getResources().getIdentifier("puzzle" + i, "button", this.getPackageName());

От

int puzzleButtonID = getResources().getIdentifier("puzzle" + i, "id", this.getPackageName());
  • 0
    Это сработало, спасибо. Я был настолько поглощен деталями, что пропустил злоупотребление «кнопка» против «идентификатор». Я бы приветствовал ваш ответ, но у меня пока нет репутации.
  • 0
    Вы можете принять ответ, если он решил вашу проблему!
Показать ещё 2 комментария
1

Если у вас несколько кнопок со схожими функциями. Я предлагаю вам внедрить OnClickListener в Activity, а не создавать анонимный прослушиватель для каждой кнопки.

Чтобы различить, какая кнопка нажата, есть два способа сделать это. 1. Когда вы инициализируете кнопки, вы можете установить кнопку с помощью тега, используя View.setTag().

  1. Использование RESID.

В вашем случае я предлагаю вам использовать метод 1, потому что вам нужно передать уровень в намерение при нажатии кнопки. Когда вы инициализируете кнопки, вы можете просто установить тег кнопки с уровнем.

Тогда ваш код должен выглядеть так:

public class YourActivity extends Activity implements OnClickListener  {

    private void initializePuzzleButtons() {
        ...
        puzzleButtons[i].setOnClickListener(this);
        puzzleButtons[i].setTag(i);
        ...
    }

    @Override
    public void onClick(View view) {
        int level = (int)view.getTag(); 
        ...
    }
}
  • 0
    Спасибо за ваш ответ. Я сделаю это, потому что это намного чище, чем мое нынешнее использование анонимного слушателя. Есть ли у вас какие-либо мысли об эффективности одного метода над другим?
0

Я думаю, следует использовать по ссылке

int id = getResources(). getIdentifier ("name_of_resource", "id", getPackageName());

  • 1
    Спасибо. Это сработало. Я пропустил это полностью, такое простое исправление! Очень признателен.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню