Injectview (Roboguice) не работает с несколькими макетами - PullRequest
8 голосов
/ 02 ноября 2011

Итак, у меня есть разные макеты для этого занятия.

И у меня есть разные классы, которые каждый открывает и делает свое дело с макетом.

Я внедряю эти классы в Activity через @Inject. Все это без проблем.

Но когда я пытаюсь использовать @InjectView на одном из элементов управления, которые находятся в неактивном макете, я получаю сообщение об ошибке.

11-02 19: 17: 31.086: ОШИБКА / AndroidRuntime (1326): вызвано: java.lang.NullPointerException: невозможно вставить нулевое значение в класс be.baes.notes.View.EditNoteImpl.saveButton, когда поле не является @ Nullable

Тогда это будет код.

public class EditNoteImpl implements EditNote {
    @Inject CancelEditNoteClickListener cancelEditNoteClickListener;
    @Inject SaveNoteClickListener saveNoteClickListener;
    @Inject Provider<Activity> activity;
    @InjectView(R.id.saveButton) Button saveButton;

    /* (non-Javadoc)
     * @see be.baes.notes.EditNote#activateEditNote()
     */
    @Override
    public void activateEditNote()
    {
        activity.get().setContentView(R.layout.editnote);

        this.saveButton.setOnClickListener(saveNoteClickListener);
    }
}

Однако я могу это сделать.

public class EditNoteImpl implements EditNote {
    @Inject CancelEditNoteClickListener cancelEditNoteClickListener;
    @Inject SaveNoteClickListener saveNoteClickListener;
    @Inject Provider<Activity> activity;
    private Button saveButton;

    /* (non-Javadoc)
     * @see be.baes.notes.EditNote#activateEditNote()
     */
    @Override
    public void activateEditNote()
    {
        activity.get().setContentView(R.layout.editnote);
        saveButton = (Button)activity.get().findViewById(R.id.saveButton);

        this.saveButton.setOnClickListener(saveNoteClickListener);
    }
}

Есть ли лучший способ сделать это?

1 Ответ

4 голосов
/ 09 ноября 2011

Я только начал использовать roboguice, чтобы кто-то еще с большим опытом мог дать лучший ответ, но это то, что я нашел до сих пор:

  • В roboguice-1.1.2 (текущий стабильный выпуск), элементы @InjectView внедряются только тогда, когда setContentView() вызывается впервые в действии.Поскольку ваш код вызывает setContentView() динамически из вспомогательных классов, введенные элементы не будут корректно введены.

  • В roboguice-2.0b2 (текущая бета-версия) есть поддержкадля нескольких вызовов setContentView() и ваш код должен работать.Однако внедренные представления по-прежнему привязаны к контексту Activity (а не к объявленному классу), поэтому каждый @InjectView потенциально также должен быть @Nullable во всех вспомогательных классах, совместно использующих одну и ту же активность.

Поскольку проблема здесь, похоже, коренится в множественном макете (и, следовательно, в нескольких вызовах setContentView()) в одном действии, один альтернативный способ сделать то, что вы хотите, - это избежать его следующим образом:

  • Вместо нескольких макетов используйте один макет с тегом <include/>, чтобы загрузить все макеты в родительский FrameLayout:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <include layout="@layout/layout1" />

    <include layout="@layout/layout2" />

    <!-- other layouts... -->

</FrameLayout>
  • затем вместо вызова setContentView() используйте метод, который будет переключать видимый макет в Activity, что-то вроде этого:
// instead of: activity.setContentView(R.layout.layout1);
// use: activity.showLayout(R.id.layoutview1);
public void showLayout(int layoutViewId) {
    final View view = findViewById(layoutViewId);
    final ViewGroup root = (ViewGroup) view.getParent();
    for (int i = 0; i < root.getChildCount(); i++) {
        final View v = root.getChildAt(i);
        v.setVisibility(v == view ? View.VISIBLE : View.GONE);
    }
}

Приведенная выше альтернатива должна работать длякак стабильный, так и бета-релизы roboguice.Компромисс здесь заключается в том, что мы загружаем несколько макетов одновременно, вместо того, чтобы загружать каждый макет несколько раз.Кажется, он работает достаточно хорошо для меня (хотя он может отличаться для ваших нужд).

Одна вещь, на которую я должен обратить внимание, это то, что на текущей "Обновление с RoboGuice 1.1 до 2.0" страницаупоминается следующее:

Возможность использовать @InjectView в представлениях (хотя вам нужно будет вызывать RoboGuice.injectMembers () самостоятельно, поскольку базового класса RoboView нет и, вероятно, никогда не будет).

Похоже, это должно позволить вам реализовать ваши вспомогательные классы, производные от View, и заставить @InjectView в них работать лучше (надеюсь, нет необходимости, чтобы они были @Nullable, поскольку онименее привязан к деятельности).Однако, глядя на текущий код, эта функция, кажется, еще не реализована (хотя я мог бы искать не в том месте).

...