Как @Provide Activity для MortarActivityScope, не пропуская Activity при изменении ориентации?

У меня есть приложение Mortar с MortarActivityScope в качестве первого дочернего элемента в корневой области. MortarActivityScope имеет ActivityScope, который @обеспечивает действие для введенных классов:

@Module(addsTo = ApplicationModule.class, injects = {Foo.class, SomePresenter.class, AnotherPresenter.class})
public class ActivityModule {

    private final Activity activity;

    public ActivityModule(Activity activity) {
        this.activity = activity;
    }

    @Provides Activity provideActivity() {
        return activity;
    }
}

public class Foo {
    private final Activity activity;
    @Inject(Activity activity) {
        this.activity = activity;
    }
    public void doSomethingWithActivity() {
       // do stuff with activity: findViewById(), getWindow(), mess with action bar etc.
    }
}

Это нормально, пока не произойдет изменение ориентации. В примере проекта Mortar область действия не уничтожается при изменении ориентации. Предположительно, это позволяет презентаторам @Singleton, экранам и т. д. сохраняться при изменении ориентации. Вы можете увидеть это в методе onDestroy() в основной активности примера проекта:

@Override protected void onDestroy() {
    super.onDestroy();

    actionBarOwner.dropView(this);

    // activityScope may be null in case isWrongInstance() returned true in onCreate()
    if (isFinishing() && activityScope != null) {
      MortarScope parentScope = Mortar.getScope(getApplication());
      parentScope.destroyChild(activityScope);
      activityScope = null;
    }
  }
}

Однако такой способ означает, что старый ObjectGraph сохраняется при изменении ориентации. Я заметил, что Mortar.requireActivityScope не заменяет модуль из старой области действия новым модулем, предоставленным новым Blueprint. Вместо этого граф объектов сохраняет ссылку на предыдущий модуль, включая уничтоженную Activity.

public class MyActivity extends Activity implements Blueprint {

    @Inject foo;

    @Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        MortarScope parentScope = Mortar.getScope(getApplication());
        activityScope = Mortar.requireActivityScope(parentScope, this);
        Mortar.inject(this, this);

        foo.doSomethingWithActivity(); //fails, because activity injected by object graph is destroyed
    }

    @Override
    public String getMortarScopeName() {
        return getClass().getName();
    }

    @Override
    public Object getDaggerModule() {
        return new ActivityModule(this);
    }
}

Пример активности Mortar, кажется, обходит это, не включая метод @Provides Activity в основной модуль. Но разве MortarActivityScope не может внедрить активность? Каков предпочтительный способ сделать это, не теряя все ваши одноэлементные объекты (объекты Presenter и т. д.) при изменении ориентации?


person weefbellington    schedule 23.10.2014    source источник


Ответы (1)


Не позволяйте никому вводить действие, которое невозможно сделать безопасным. Вместо этого введите презентатор, привязанный к Activity.

Как обрабатывать onActivityResult() с помощью Mortar включает пример действия, владеющего ведущим. Другие части вашего приложения, в том числе другие докладчики, могут затем внедрить это и попросить его сделать все, что им нужно, что требует обработки действия.

И нет необходимости связывать всю работу, связанную с конкретным действием, с одним презентатором. В нашей деятельности есть несколько презентаторов, которые предоставляют свои услуги остальной части приложения.

person rjrjr    schedule 23.10.2014
comment
Очень элегантно. Использование внедренного Presenter — это путь, который я никогда не рассматривал, и это намного меньше бухгалтерского учета, чем ручное обновление каждого объекта, содержащего ссылку на Activity. - person weefbellington; 24.10.2014