【问题标题】:Android, Dagger 2 inject recyclerview inside fragmentAndroid,Dagger 2在片段内注入recyclerview
【发布时间】:2016-10-28 05:30:33
【问题描述】:

正如我之前读到的,dagger 会发出所有构造函数并自己提供它们,所以我们的业务中几乎不应该有任何构造函数,现在想象在 FragmentActivity 中有一个 RecyclerView正在注入片段,我如何为片段注入LayoutManagerAdapter 以及Presenter(不将它们注入到活动中并通过参数传递给片段)

我正在处理的示例是here,但他根据MVP 模式将Activity 本身用作View,但我试图改用Fragment

This 是他的Activity(这里注入了recycler view 和presenter)。

我的代码:

UserComponent 是 AppComponent 的子组件

@UserScope
@Subcomponent(modules = UserModule.class)
public interface UserComponent {
     RepoListComponent plus(RepoListModule repoListModule);

     UserEntity getUserEntity();
}

RepoListModule:

@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);
  }
}

RepoListComponent:

@Subcomponent(modules = RepoListModule.class)
public interface RepoListComponent {
    void inject(RepoListContract.View view);
}

RepoListActivity:

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);
  }
}

RepoListFragment:

public class RepoListFragment extends Fragment implements RepoListContract.View {
@BindView(R.id.rv_repo) RecyclerView rvRepo;

@Inject RepoListContract.Presenter presenter;
@Inject LinearLayoutManager layoutManager;
@Inject RepoListAdapter adapter;

public static RepoListFragment newInstance() {
    return new RepoListFragment();
}

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
                         @Nullable Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragment_repo_list, container, false);
    ButterKnife.bind(this, v);
    initRvRepo();
    return v;
}
private void initRvRepo() {
    rvRepo.setLayoutManager(layoutManager); // null
    rvRepo.setAdapter(adapter); //null
}

@Override
public void onResume() {
    super.onResume();
    presenter.subscribe(); //NullPointerException
  }
}

【问题讨论】:

    标签: android dagger-2


    【解决方案1】:

    我不确定我是否完全理解这些词:“...所以我们的业务中几乎不应该有任何构造函数...”。通常我会通过 - 作为经验法则,每次您看到 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,您正在访问onResumeonCreateView 中的注入变量。这些是片段生命周期的一部分,一旦添加到活动中就会运行(假设ActivityUtils.addFragmentToActivity 实际上在布局中添加/替换片段)。

    如您所见,这意味着在您有机会注入成员之前,您已经在访问它们。所以你应该在添加之前注入片段。

    【讨论】:

    • 你是说我可以访问适配器吗?我做到了,但没有工作
    • 你可以访问适配器是什么意思?您自己创建适配器...
    • 感谢您的完整回答,但由于RepositoriesListComponent 是作为 AppComponent 的子组件的 UserComponent 的子组件,它可能会发生,现在我的适配器和 layoutManager 为空! -> Activity: => 'GApplication.get(getApplicationContext()) .getUserComponent().plus(new RepoListModule(fragment)) .inject(fragment);'
    • 就像我说的,这只是一种方法。听起来你有另一个问题。我看不出当时这些为空的原因,所以也许你可以用你已经尝试过的一些代码来更新你的问题,我可以改变答案来帮助你。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多