正如我之前读过的那样,dagger会发出所有构造函数并自己提供它们,因此我们的业务中几乎不应该有任何构造函数,现在想象RecyclerView
内部有一个Fragment
并且Activity
正在注入片段,如何为片段注入LayoutManager
和Adapter
以及Presenter
(不将其注入活动内并将参数传递给片段)
我正在处理的示例是here,但他根据Activity
模式将View
本身用作MVP
,但我正在尝试使用{{1}相反。
This是他的Fragment
(此处注册了回收者视图和演示者)。
我的代码:
UserComponent,它是AppComponent
的子组件Activity
RepoListModule:
@UserScope
@Subcomponent(modules = UserModule.class)
public interface UserComponent {
RepoListComponent plus(RepoListModule repoListModule);
UserEntity getUserEntity();
}
RepoListComponent:
@Module
public class RepoListModule {
private RepoListContract.View view;
public RepoListModule(RepoListContract.View view) {
this.view = view;
}
@Provides
RepoListContract.View provideRepoListContractView(){
return view;
}
@Provides
LinearLayoutManager provideLayoutManager(Context context) {
return new LinearLayoutManager(context);
}
@Provides
RepoListAdapter provideAdapter(RepoListContract.View view) {
return new RepoListAdapter(view);
}
}
RepoListActivity:
@Subcomponent(modules = RepoListModule.class)
public interface RepoListComponent {
void inject(RepoListContract.View view);
}
RepoListFragment:
public class RepoListActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_repo_list);
RepoListFragment fragment = (RepoListFragment) getSupportFragmentManager()
.findFragmentById(R.id.fragment_container);
if (fragment == null) {
fragment = new RepoListFragment();
ActivityUtils.addFragmentToActivity(getSupportFragmentManager(),
fragment, R.id.fragment_container);
}
GApplication.get(getApplicationContext())
.getUserComponent().plus(new RepoListModule(fragment))
.inject(fragment);
}
}
答案 0 :(得分:2)
我不确定我是否完全理解这些词:" ...所以我们的业务中几乎不应该有任何构造函数......" 。通常我会经过 - 每次看到new
运算符时,根据经验表明你对实例化的类有严格的依赖关系,你应该尝试删除它。也就是说,这就是我如何处理你的任务(肯定有更多解决方案,这只是一种方法)。
让我们从最简单的事情开始吧。让我们创建你的片段:
public RepositoriesListFragment extends Fragment implements RepositoriesListView {
@Inject RecyclerView.LayoutManager layoutManager;
@Inject RecyclerView.Adapter adapter;
@Inject RepositoriesListPresenter presenter;
public static RepositoriesListFragment newInstance() {
return new RepositoriesListFragment();
}
// ...
}
现在这可能是依赖项的模块:
@Module
public class RepositoriesListModule {
private final RepositoriesListView view;
public RepositoriesListModule(RepositoriesListView view) {
this.view = view;
}
@Provides
public RepositoriesListView providesView() {
return view;
}
@Provides
public RecyclerView.LayoutManager providesLayoutManager(Context context) {
return new LinearLayoutManager(context);
}
@Provides
public RecyclerView.Adapter providesAdapter(SomeAdapterImpl adapter) {
return adapter;
}
@Provides
public RepositoriesListPresenter providesPresenter(SomePresenterImpl presenter) {
return presenter;
}
}
首先要注意的是它需要构造函数中的视图。这是因为通常演示者也需要视图。因此SomePresenterImpl
会在其构造函数中看到此视图。
第二件事,该模块假定某处还提供了Context
。最有可能通过组件所依赖的另一个模块。
这是组件:
@Component(modules = { RepositoriesListModule.class, ... })
public interface RepositoriesListComponent {
void inject(RepositoriesListFragment fragment);
}
(如前所述,此组件可能需要其他模块,甚至依赖于其他组件)。
您需要做的最后一件事就是注入片段。正如你所说,有一个创建和注入片段的活动。所以这可能看起来像:
public class MainActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
// ...
RepositoriesListFragment fragment = RepositoriesListFragment.newInstance();
DaggerRepositoriesListComponent.builder()
.repositoriesListModule(new RepositoriesListModule(fragment))
.inject(fragment);
// ...
}
就像我说的,这不是唯一的方法。这有一个问题,您可以多次创建组件。如果您对组件的范围超出了正确处理组件所需的范围。您不能每次都创建它,否则您将使范围无用。每当您要注入视图时,模块都需要正确的视图,您需要确保模块引用该视图。
希望这有帮助。
修改强>:
看了你的代码后,我认为这个问题与你在注入之前添加片段的事实有关,所以基本上这样做可能会解决问题:
public class RepoListActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_repo_list);
RepoListFragment fragment = (RepoListFragment) getSupportFragmentManager()
.findFragmentById(R.id.fragment_container);
if (fragment == null) {
fragment = new RepoListFragment();
GApplication.get(getApplicationContext())
.getUserComponent().plus(new RepoListModule(fragment))
.inject(fragment);
ActivityUtils.addFragmentToActivity(
getSupportFragmentManager(),
fragment, R.id.fragment_container);
}
}
}
为什么会这样?查看RepoListFragment
您访问onResume
和onCreateView
中注入的变量的ActivityUtils.addFragmentToActivity
。这些是片段生命周期的一部分,它将在活动中添加(假设enum model_class
{
...
};
struct SModelData
{
string m_strName;
model_class m_class;
vector<int> m_parts;
int m_iSeats;
SModelData(...) : ... {}
};
const multimap<int, SModelData*> models_data =
{
{ 400, new SModelData("Landstalker", STUFF, ***, 4) },
...
};
实际添加/替换布局中的片段)。
如您所见,这意味着在您有机会注入成员之前,您已经在访问它们了。所以你应该在添加之前注入片段。