如何向嵌套的Android片段注入依赖项?

6

对于普通的(非嵌套片段),我使用以下方法:

1)创建“dependencies(...)”方法来设置片段的依赖项

class MyFragment extends MyFragment {
      void dependencies(Deps deps);
}

2) 在MyFragment的父Activity的onAttachFragment()方法中,我只是为fragment提供依赖项。

class MyActivity{
    void onAttachFragment(Fragment f){
        ((MyFragment)f).dependencies(deps);
    }
}

对于嵌套片段,不再调用 onAttachFragment 片段。 仅为提供依赖项而为 嵌套片段 提供依赖项似乎非常麻烦。那么我该如何为它提供依赖项呢?

使用Dagger2吗?它被设计用来管理这种事情。 - Mimmo Grottoli
Mimmo Grottoli,我知道dagger2。但它只是一个用于消除依赖注入样板代码的库。始终应该有通过构造函数或特殊方法注入依赖项的方式。 - wilddev
一个为Fragments或Activities注入某些依赖项的构造函数?当然你可以尝试,但最终你会发现dagger或dagger2是你可以自己开发的最好的东西(至少对我来说是这样)。 - Mimmo Grottoli
无法通过构造函数向片段注入依赖项,因为Android通过反射重新创建片段。因此,我只使用dependencies()方法。不好的是,在Android中没有地方可以调用此方法以注入嵌套片段的依赖项。相反,我必须在NestedFragment.onCreate方法中提取依赖项-这是一种反模式。 - wilddev
4个回答

5

只需要在一个活动之外执行它。为您的活动创建依赖项的getter方法。无论是嵌套还是非嵌套片段都可以访问父活动。强制转换上下文,然后调用getter方法以获取嵌套活动中的依赖项。


为了额外的学分,创建一个接口ComponentProvider并让您的活动实现它,该接口公开一个方法getComponent。getContext应该被转换为接口而不是特定的活动,以允许在活动之间重用片段。 - FriendlyMikhail

2

您尝试在片段附加时设置依赖项。相反,尝试在需要时从片段获取依赖项。这是一个示例:

public class MyActivity extends Activity {

    public Deps getDepsForFragment(Fragment fragment) {
        if (fragment instanceof MyFragment) {
            return depsForMyFragment;
        } else if (fragment instanceof MyNestedFragment) {
            return depsForMyNestedFragment;
        } else {
            return null;
        }
    }
}

public class MyFragment extends Fragment {

    private Deps deps;

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        try {
            MyActivtiy myActivity = (MyActivtiy) context;
            deps = myActivity.getDepsForFragment(this);
        } catch (ClassCastException e) {
            throw new ClassCastException("This fragment attached to an activity which can't provide the required dependencies.");
        }
    }
}

// this is the same as the MyFragment
public class MyNestedFragment extends Fragment {

    private Deps deps;

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        try {
            MyActivtiy myActivity = (MyActivtiy) context;
            deps = myActivity.getDepsForFragment(this);
        } catch (ClassCastException e) {
            throw new ClassCastException("This fragment attached to an activity which can't provide the required dependencies.");
        }
    }
}

当然,您可以为活动创建一个独立的方法来获取依赖项(例如 getDepsForMyFragmentgetDepsForMyNestedFragment)。

2
如果MyFragment依赖于MyNestedFragment,而MyNestedFragment又依赖于Deps,那么可以得出MyFragment也依赖于Deps。当然,在调用Activity.onAttachFragment()时,并不存在MyNestedFragment的实例,因此你必须等到在MyFragment.onCreateView()中填充布局后才能为MyNestedFragment提供其依赖项。
public class MyActivity {

    ...

    void onAttachFragment(Fragment f){
        ((MyFragment)f).dependencies(deps);
    }

    public static class MyFragment extends Fragment {

        private Deps deps;

        void dependencies(Deps deps) {
            this.deps = deps;
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
            View rootView = inflater.inflate(R.layout.fragment_main, container, false);

            // <fragment> element in fragment_main layout has
            //  android:tag set to nested_fragment
            ((MyNestedFragment)getChildFragmentManager()
                .findFragmentByTag("nested_fragment"))
                .dependencies(this.deps);

            return rootView;
        }
    }

    public static class MyNestedFragment extends Fragment {

        void dependencies(Deps deps) {
            ...
        }
    }

    ...
}

如果这一切看起来有点混乱,那是因为Fragments不是你可以随意连接的普通Java对象(POJOs)。它们的生命周期必须由嵌套的FragmentManager进行管理。如果你是通过程序编写Fragment而不是使用元素,则可以更加控制它们的生命周期,但代价是更复杂。
如果你想把Android当作一个IoC容器来使用,那么RoboGuice可能就是你要找的:
public class MyActivity extends roboguice.activity.RoboFragmentActivity {

    ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        // This only needs to be called once for the whole app, so it could
        // be in the onCreate() method of a custom Application subclass 
        RoboGuice.setUseAnnotationDatabases(false);

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
    }

    public static class MyNestedFragment extends Fragment {

        @Inject
        private Deps deps;

        @Override
        public void onAttach(Activity activity) {
            super.onAttach(activity);
            // this isn't necessary if you extend RoboFragment
            roboguice.RoboGuice.getInjector(activity).injectMembers(this);
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

            //This would not even be possible in the previous example
            // because onCreateView() is called before dependencies()
            // can be called.
            deps.method();

            View rootView = inflater.inflate(R.layout.fragment_nested, container, false);
            return rootView;
        }
    }
}

@Singleton
public class Deps {
    public void method() {
        System.out.println("Deps.method()");
    }
}

1

只需保持层次逻辑,应该是这样的:

class MyActivity{
    void onAttachFragment(Fragment f){
        ((MyFragment)f).dependencies(deps);
    }
}

class MyFragment extends MyFragment {
      void dependencies(Deps deps) {
          //TODO: do dependencies of my fragment before
          ((MyNestedFragment)childF).nestedDependencies(deps);
          //TODO: do dependencies of my fragment after
      }
}

class MyNestedFragment extends MyNestedFragment {
      void nestedDependencies(Deps deps);
}

将依赖项注入到MyFragment非常奇怪,因为它不需要它们。 MyFragment不依赖于deps。 - wilddev
Iliiaz Akhmedov,MyFragment 不依赖于 deps,但 MyNestedFragment 依赖于它!因此将 deps 传递给 MyFragment 是反模式。 - wilddev
你的嵌套片段是你的片段的依赖项,因此,在这个层次结构中注入它是合理的。 - Iliiaz Akhmedov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接