2015-10-15 24 views
2

我有一個應用程序設置使用迫擊炮/流量和匕首2.它似乎工作,除了當我在同一類的兩個視圖之間切換。新視圖以前一個視圖的主持人結束。如何防止砂漿作用域在屏幕上持續存在?

例如,我有一個ConversationScreen,它將conversationId作爲構造函數參數。第一次創建ConversationScreen並將其添加到Flow中時,它會創建ConversationView,它將自身注入一個Presenter,該Presenter是使用傳遞給屏幕的conversationId創建的。如果我使用不同的conversationId創建一個新的ConversationScreen,當ConversationView請求一個Presenter時,Dagger返回舊的Presenter,因爲範圍在前一個ConversationScreen中尚未關閉。

在我設置新的屏幕之前,有沒有辦法讓我手動關閉前一個屏幕的範圍?或者我剛剛設置了錯誤的範圍?

ConversationView

public class ConversationView extends RelativeLayout { 
    @Inject 
    ConversationScreen.Presenter presenter; 

    public ConversationView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     DaggerService.<ConversationScreen.Component>getDaggerComponent(context).inject(this); 
    } 

    @Override 
    protected void onAttachedToWindow() { 
     super.onAttachedToWindow(); 
     presenter.takeView(this); 
    } 

    @Override 
    protected void onDetachedFromWindow() { 
     presenter.dropView(this); 
     super.onDetachedFromWindow(); 
    } 
} 

ConversationScreen

@Layout(R.layout.screen_conversation) 
public class ConversationScreen extends Paths.ConversationPath implements ScreenComponentFactory<SomeComponent> { 
    public ConversationScreen(String conversationId) { 
     super(conversationId); 
    } 

    @Override 
    public String getTitle() { 
     title = Conversation.get(conversationId).getTitle(); 
    } 

    @Override 
    public Object createComponent(SomeComponent parent) { 
     return DaggerConversationScreen_Component.builder() 
       .someComponent(parent) 
       .conversationModule(new ConversationModule()) 
       .build(); 
    } 

    @dagger.Component(
      dependencies = SomeComponent.class, 
      modules = ConversationModule.class 
    ) 

    @DaggerScope(Component.class) 
    public interface Component { 
     void inject(ConversationView conversationView); 
    } 

    @DaggerScope(Component.class) 
    @dagger.Module 
    public class ConversationModule { 
     @Provides 
     @DaggerScope(Component.class) 
     Presenter providePresenter() { 
      return new Presenter(conversationId); 
     } 
    } 

    @DaggerScope(Component.class) 
    static public class Presenter extends BasePresenter<ConversationView> { 
     private String conversationId; 

     @Inject 
     Presenter(String conversationId) { 
      this.conversationId = conversationId; 
     } 

     @Override 
     protected void onLoad(Bundle savedInstanceState) { 
      super.onLoad(savedInstanceState); 
      bindData(); 
     } 

     void bindData() { 
      // Show the messages in the conversation 
     } 
    } 
} 

回答

2

如果使用默認的從迫擊炮/流程示例項目ScreenScoperPathContextFactory類,你會看到新的範圍,以創建的名稱是屏幕類的名稱。

因爲您想從ConversationScreen的一個實例導航到另一個ConversationScreen實例,所以新範圍的名稱將等於先前範圍的名稱。因此,您不會創建新的Mortar作用域,而只是重用前一個作用域,這意味着重複使用同一個演示者。

您需要的是更改新範圍的命名策略。而不是隻使用新屏幕類的名稱,添加其他內容。
最簡單的修復方法是使用實​​例標識:myScreen.toString()

另一個更好的解決方法是跟蹤屏幕/範圍名稱。 下面的例子https://github.com/lukaspili/Mortar-architect

class EntryCounter { 

    private final SimpleArrayMap<Class, Integer> ids = new SimpleArrayMap<>(); 

    int get(History.Entry entry) { 
     Class cls = entry.path.getClass(); 
     return ids.containsKey(cls) ? ids.get(cls) : 0; 
    } 

    void increment(History.Entry entry) { 
     update(entry, true); 
    } 

    void decrement(History.Entry entry) { 
     update(entry, false); 
    } 

    private void update(History.Entry entry, boolean increment) { 
     Class cls = entry.path.getClass(); 
     int id = ids.containsKey(cls) ? ids.get(cls) : 0; 
     ids.put(cls, id + (increment ? 1 : -1)); 
    } 
} 

提取,然後創建新的範圍時,使用此計數器:

private ScopedEntry buildScopedEntry(History.Entry entry) { 
    String scopeName = String.format("ARCHITECT_SCOPE_%s_%d", entry.path.getClass().getName(), entryCounter.get(entry)); 
    return new ScopedEntry(entry, MortarFactory.createScope(navigator.getScope(), entry.path, scopeName)); 
} 

而在其他一些地方,我遞增/遞減計數器,如果新的範圍或推範圍被破壞。

+0

404在您的鏈接上(請考慮將代碼添加到您的答案) – pjco

+1

感謝您的通知,修正。 – lukas

2

ScreenScoper中的作用域基於一個字符串,如果您創建了相同的路徑,它將使用相同的名稱,因爲它將它作爲路徑的類名。

我解決了這個問題,通過從ScreenScoper中刪除一些噪音,考慮到我在Dagger2驅動的項目中並沒有使用@ModuleFactory

public abstract class BasePath 
     extends Path { 
    public abstract int getLayout(); 

    public abstract Object createComponent(); 

    public abstract String getScopeName(); 
} 

public class ScreenScoper { 
    public MortarScope getScreenScope(Context context, String name, Object screen) { 
     MortarScope parentScope = MortarScope.getScope(context); 
     return getScreenScope(parentScope, name, screen); 
    } 

    /** 
    * Finds or creates the scope for the given screen. 
    */ 
    public MortarScope getScreenScope(MortarScope parentScope, final String name, final Object screen) { 
     MortarScope childScope = parentScope.findChild(name); 
     if (childScope == null) { 
      BasePath basePath = (BasePath) screen; 
      childScope = parentScope.buildChild() 
        .withService(DaggerService.TAG, basePath.createComponent()) 
        .build(name); 
     } 
     return childScope; 
    } 
}