zoukankan      html  css  js  c++  java
  • RoboGuice 3.0 (三)总结篇

    经过前两篇的介绍,我们了解了如何使用RoboGuice方便的为我们注入需要的对象,这篇将着重说明原理。

    一.Guice与RoboGuice

    Guise是Google开发的一个轻量级的依赖注入框架,主要针对Java使用的。

    RoboGuice是基于Guice库开发,目的为Android提供一套简单易用的依赖注入框架。

    上两篇中所提到的POJO注入,说白了就是对象注入,大部分方法都是Guice框架中的。RoboGuice主要在视图注入及Android个性化的注入上下功夫。

    二.RoboGuice注入对象

    就算没用过RoboGuice,但是大家也都听过,RoboGuice是通过反射来实现注入的。

    为了了解实现的原理,我们先看下RoboActivity的代码。
    其中eventManager初始化方式使用的就是之前提过的RoboGuice.getInjector(),其内部提供了各种事件的注册,反注册,分发等等功能。

    public class RoboActivity extends Activity implements RoboContext {
        protected EventManager eventManager;
        protected HashMap<Key<?>,Object> scopedObjects = new HashMap<Key<?>, Object>();
    
        @Inject ContentViewListener ignored; // BUG find a better place to put this
        private Stopwatch stopwatch;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            stopwatch = new Stopwatch();
            final RoboInjector injector = RoboGuice.getInjector(this);
            stopwatch.resetAndLog("RoboActivity creation of injector");
            eventManager = injector.getInstance(EventManager.class);
            stopwatch.resetAndLog("RoboActivity creation of eventmanager");
            injector.injectMembersWithoutViews(this);
            stopwatch.resetAndLog("RoboActivity inject members without views");
            super.onCreate(savedInstanceState);
            stopwatch.resetAndLog("RoboActivity super onCreate");
            eventManager.fire(new OnCreateEvent<Activity>(this,savedInstanceState));
            stopwatch.resetAndLog("RoboActivity fire event");
        }
    }
    

    其次注意到被注入的ContentViewListener,这就是为了实现在Activity上的ContentView的注解,这里的方法是

    @ContextSingleton
    public class ContentViewListener {
        @Inject protected Activity activity;
    
        public void optionallySetContentView( @Observes OnCreateEvent<?> ignored ) {
            Class<?> c = activity.getClass();
            while( c != Context.class ) {
                final ContentView annotation = c.getAnnotation(ContentView.class);
                if( annotation!=null ) {
                    activity.setContentView(annotation.value());
                    return;
                }
                c = c.getSuperclass();
            }
        }
    }
    

    这里观察的是OnCreate的事件,事件的分发代码在OnCreate方法中,实现了setContentView的方法。

    onCreate方法简化后如下。可以发现inject对象的时机是在super的onCreate之前的,

    @Override
        protected void onCreate(Bundle savedInstanceState) {
            final RoboInjector injector = RoboGuice.getInjector(this);
            eventManager = injector.getInstance(EventManager.class);
            injector.injectMembersWithoutViews(this);
            super.onCreate(savedInstanceState);
            eventManager.fire(new OnCreateEvent<Activity>(this,savedInstanceState));
        }
    

    RoboInjector其实是RoboGuice内部的一个Guice Injector,大部分注入工作交给了Guice。

    反射注入这一块就不深入讨论了,下面贴出了Guice的部分代码。

    private static void computeInjectableMembers(TypeLiteral<?> type, boolean statics, Errors errors, InjectionPoint.InjectableMembers injectableMembers, InjectionPoint.OverrideIndex overrideIndex, HierarchyTraversalFilter filter) {
        Class rawType = type.getRawType();
        if(isWorthScanning(filter, rawType)) {
            Class parentRawType = rawType.getSuperclass();
            if(isWorthScanning(filter, parentRawType)) {
                computeInjectableMembers(type.getSupertype(parentRawType), statics, errors, injectableMembers, overrideIndex, filter);
                overrideIndex.position = InjectionPoint.Position.MIDDLE;
            } else {
                overrideIndex.position = InjectionPoint.Position.TOP;
            }
    
            Set allFields = filter.getAllFields(Inject.class.getName(), rawType);
            if(allFields != null) {
                Iterator allMethods = allFields.iterator();
    
                while(allMethods.hasNext()) {
                    Field i$ = (Field)allMethods.next();
                    if(Modifier.isStatic(i$.getModifiers()) == statics) {
                        Annotation method = getAtInject(i$);
                        if(method != null) {
                            InjectionPoint.InjectableField atInject = new InjectionPoint.InjectableField(type, i$, method);
                            if(atInject.jsr330 && Modifier.isFinal(i$.getModifiers())) {
                                errors.cannotInjectFinalField(i$);
                            }
    
                            injectableMembers.add(atInject);
                        }
                    }
                }
            }
    
            Set allMethods1 = filter.getAllMethods(Inject.class.getName(), rawType);
            if(allMethods1 != null) {
                Iterator i$1 = allMethods1.iterator();
    
                while(true) {
                    while(true) {
                        while(true) {
                            Method method1;
                            do {
                                if(!i$1.hasNext()) {
                                    return;
                                }
    
                                method1 = (Method)i$1.next();
                            } while(!isEligibleForInjection(method1, statics));
    
                            Annotation atInject1 = getAtInject(method1);
                            if(atInject1 != null) {
                                InjectionPoint.InjectableMethod removed2 = new InjectionPoint.InjectableMethod(type, method1, atInject1);
                                if(!checkForMisplacedBindingAnnotations(method1, errors) && isValidMethod(removed2, errors)) {
                                    if(statics) {
                                        injectableMembers.add(removed2);
                                    } else {
                                        overrideIndex.removeIfOverriddenBy(method1, true, removed2);
                                        overrideIndex.add(removed2);
                                    }
                                } else {
                                    boolean removed1 = overrideIndex.removeIfOverriddenBy(method1, false, removed2);
                                    if(removed1) {
                                        logger.log(Level.WARNING, "Method: {0} is not a valid injectable method (because it either has misplaced binding annotations or specifies type parameters) but is overriding a method that is valid. Because it is not valid, the method will not be injected. To fix this, make the method a valid injectable method.", method1);
                                    }
                                }
                            } else {
                                boolean removed = overrideIndex.removeIfOverriddenBy(method1, false, (InjectionPoint.InjectableMethod)null);
                                if(removed) {
                                    logger.log(Level.WARNING, "Method: {0} is not annotated with @Inject but is overriding a method that is annotated with @javax.inject.Inject.  Because it is not annotated with @Inject, the method will not be injected. To fix this, annotate the method with @Inject.", method1);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    

    三.总结

    这三篇过来,依赖注入给我们带来了什么?

    解耦。

    当我们在一个对象中,不需要关心它所依赖的成员如何初始化,只关心用来使用或获取属性,依赖注入为我们实现了解耦。

    再就是RoboGuice的贴心,将Android基本组件考虑在内,为我们实现了很多注入,减少了我们调用系统服务或组件的代码,再就是RoboGuice考虑到了Android生命周期的特殊问题,将注入的成员对象生命周期保持与Context生命周期一致。

    再说说反射,尽管RoboGuice强调,使用roboblender会优化很大一部分注解性能,但是反射对于移动端设备参差不齐的配置,还是让人有一点点担心,如果项目足够大,且使用了大量的注解及注入,那么性能一定是有影响的。

    最后,RoboGuice确实是一个值得使用的框架,使用简单、上手较快、能实现模块解耦。光凭这几点优点便足以打动人心。

  • 相关阅读:
    应急响应中find命令总结
    应急响应排查思路
    硬链接与软链接的区别
    Linux开机启动项总结
    android 開發常用網站
    epoll
    Qualcomm platform, the commonly used parameters of charger and battery in device tree file
    why not ovp protection ?
    Performance tuning
    Using adb over wifi
  • 原文地址:https://www.cnblogs.com/pedro-neer/p/5257037.html
Copyright © 2011-2022 走看看