【问题标题】:How to inject dependency to nested android fragment?如何将依赖项注入嵌套的android片段?
【发布时间】:2015-10-10 21:05:34
【问题描述】:

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

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

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

2) 在 MyFragment 父活动的 onAttachFragment() 方法中,我只是为片段提供依赖项

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

对于嵌套片段,不再调用 onAttachFragment 片段。 为fragment提供依赖只是为了给嵌套的fragment提供依赖似乎很麻烦。那么我怎样才能为它提供依赖呢?

【问题讨论】:

  • 使用 dagger2?它旨在管理此类事情
  • Mimmo Grottoli,我知道 dagger2。但它只是一个消除依赖注入样板代码的库。总是应该有通过构造函数或特殊方法注入依赖项的方法。
  • 注入一些依赖的片段或活动的构造函数?当然你可以尝试,但最后你会发现dagger或dagger2是你可以自己开发的最好的东西(至少对我来说是这样)
  • 由于Android通过反射重新创建片段,因此无法通过构造函数将依赖项注入片段。所以我只使用 dependencies() 方法。不好的是在 android 中没有地方可以调用嵌套片段的这个方法来注入依赖项。相反,我必须在 NestedFragment.onCreate 方法中提取依赖项——这是一种反模式。

标签: android android-fragments dependency-injection android-nested-fragment


【解决方案1】:

只需脱离将成为活动的上下文即可。为您的活动的依赖项创建一个吸气剂。无论是否嵌套,片段都可以访问父活动。转换上下文,然后调用 getter 来获取嵌套活动中的依赖关系。

【讨论】:

  • 为了额外的功劳,创建一个接口 ComponentProvider 并让您的活动实现它,它公开了一个方法 getComponent。 getContext 应该被强制转换为接口而不是特定的活动,从而允许跨活动重用片段。
【解决方案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) {
            ...
        }
    }

    ...
}

如果所有这些看起来有点混乱,那是因为 Fragment 不是 POJO,您可以以任意方式连接起来。它们的生命周期必须由嵌套的 FragmentManager 管理。如果您以编程方式而不是使用 元素来创建片段,您将对它们的生命周期进行更多控制,但代价是更复杂。

如果您想将 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()");
    }
}

【讨论】:

    【解决方案3】:

    当附加片段时,您尝试设置依赖项。取而代之的是,在需要时尝试从片段中获取依赖项。有一个例子:

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

    当然,你可以在activity中为get deps做单独的方法(比如getDepsForMyFragmentgetDepsForMyNestedFragment)。

    【讨论】:

      【解决方案4】:

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

      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。
      • Iliiaz Akhmedov,MyFragment 不依赖于 deps,但 MyNestedFragment 依赖!所以将 deps 传递给 MyFragment 是反模式。
      • 你的嵌套片段是你的片段的依赖,所以,在这个层次结构中注入它是合理的
      猜你喜欢
      • 2014-06-16
      • 2021-11-23
      • 1970-01-01
      • 2017-12-05
      • 1970-01-01
      • 1970-01-01
      • 2015-05-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多