• RoboGuice 3.0 (一)入坑篇


    RoboGuice是什么?

    一个Android上的依赖注入框架。

    依赖注入是什么?

    从字面理解,这个框架做了两件事情,第一是去除依赖,第二是注入依赖。简单理解就是,将对象的初始化委托给一个容器控制器,即去除依赖,再从容器控制器中构建依赖,注入回原本的对象中,即注入依赖。

    依赖注入的好处是对象不需要在乎其依赖的初始化,使代码变得无比简洁。

    一.接入

    在build.grade中添加依赖

    dependencies {
        provided 'org.roboguice:roboblender:3.0.1'
        compile 'org.roboguice:roboguice:3.0.1'
    }
    

    二.视图注入

    接触依赖注入后,最方便的可能就是视图的注入了,将之前成片的findViewById的代码省去,Activity中的代码量完成了史上第一次大扫除。

    视图注入分三个步骤:

    • 继承自RoboGuice的RoboActivity 当然RoboFragmentActivity也可以
    • 为Activity加入content view(setContentView也可以使用注解来实现)
    • 使用@InjectView来注入视图
    @ContentView(R.layout.activity_main)
    public class MainActivity extends RoboFragmentActivity {
    
        @InjectView(R.id.text_test)
        TextView textView;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            textView.setText("hello there!");
        }
    }
    

    由此可见,视图注入大大简化了Activity中的代码量。

    同理 ,Fragment也是一样的。需要注意的是,视图注入需要在onViewCreated后使用。

    public class AFragment extends RoboFragment {
    
        @InjectView(R.id.fragment_text)
        TextView textView;
    
        public static AFragment newInstance() {
            return new AFragment();
        }
    
        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            return inflater.inflate(R.layout.a_fragment, container, false);
        }
    
        @Override
        public void onViewCreated(View view, Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
            textView.setText("Hi there!");
        }
    }
    

    三.资源注入

    RoboGuice除了提供了视图注入,还提供了资源的注入。

    比如String资源、color资源、Animation资源等。

    
    @ContentView(R.layout.activity_main)
    public class MainActivity extends RoboFragmentActivity {
    
        @InjectView(R.id.text_test)
        TextView textView;
    
        @InjectResource(R.string.app_name)
        String appName;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            textView.setText(appName);
        }
    }
    
    

    四.系统服务注入

    在Activity中可以注入各种系统服务,比如震动、通知管理。

    完整的列表在这:https://github.com/roboguice/roboguice/wiki/Provided-Injections

    这样我们不用再去写烦人的getSystemService这种代码。

    @ContentView(R.layout.activity_main)
    public class MainActivity extends RoboFragmentActivity {
    
        @Inject
        Vibrator vibrator;
    
        @Inject
        NotificationManager notificationManager;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            vibrator.vibrate(500L);
            notificationManager.cancelAll();
        }
    }
    

    五.对象注入

    对象的注入最大程度的完成了代码的解耦工作。也是类似框架中上手最慢的。

    想象一个场景,比如在Activity中用户判断登录状态,我们不需要在乎UserInfo是如何初始化的,只在乎得到用户是否登陆的状态。

    结合实际情况,举个例子。这是一个用来储存用户信息的model。

    public class UserInfo {
        private String userId;
        private String token;
    
        public String getUserId() {
            return userId;
        }
    
        public void setUserId(String userId) {
            this.userId = userId;
        }
    
        public String getToken() {
            return token;
        }
    
        public void setToken(String token) {
            this.token = token;
        }
    
        public boolean isLogin(){
            return !TextUtils.isEmpty(token);
        }
    }
    

    使用注解注入UserInfo,RoboGuice会帮我们完成初始化工作,初始化时调用UserInfo的默认构造方法。

    这样在没有写userInfo = new UserInfo()我们便操作了对象。

    @ContentView(R.layout.activity_main)
    public class MainActivity extends RoboFragmentActivity {
    
        @Inject
        UserInfo userInfo;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
            userId = sharedPreferences.getString("userId", "");
            token = sharedPreferences.getString("token", "");
            String userId = sharedPreferences.getString("userId", "");
            String token = sharedPreferences.getString("token", "");
    	    userInfo.setUserId(userId);
            userInfo.setToken(token);
        }
    }
    

    再然而onCreate内部的取用户信息的代码确实很丑陋,我们需要在Activity中完成与页面不相关的初始化工作,核心原因是我们依赖了Activity中的Context。这就相当于,如果对象中的成员初始化时需要对象的一些属性,我们很难巧妙的将属性交给容器管理着负责初始化成员。

    那么又该如何处理这么丑陋的代码呢。

    RoboGuice提供了更让人欣喜的功能,将对象中的成员初始化需要的属性封装起来,提交给容器管理者,这样当依赖对象属性的成员初始化过程就可以完全脱离对象,在成功后注入回对象即可。

    Talk is cheap! Show me the code.

    在RoboGuice的Activity中,容器管理者已经默认提供了的属性比如页面中的Context,这样当成员初始化时,可以使用@Inject来标记构造方法以用来告诉RoboGuice不使用默认构造方法进行初始化,当构造方法中的参数属性已经由Activity对象提交给容器管理者时,即容器管理者会使用该构造方法进行初始化。

    我们经过改装,UserInfo和Activity是这样的。其中@ContextSingleton注解标示UserInfo随Context的生命周期销毁而销毁,如果这里改为@Singleton,那么UserInfo的生命周期将是整个应用的生命周期,如果两个Activity都使用了该注解,那么产生的对象将是同一个。

    这里需要注意的是,如果@ContextSingleton使用不当,将造成内存泄露,这个以后会有例子说明。

    @ContextSingleton
    public class UserInfo {
        private static final String TAG = "UserInfo";
        private Context context;
        private String userId;
        private String token;
    
        @Inject
        public UserInfo(Context context) {
            this.context = context;
            init();
        }
    
        private void init() {
            SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
            userId = sharedPreferences.getString("userId", "");
            token = sharedPreferences.getString("token", "");
        }
    
        public String getUserId() {
            return userId;
        }
    
        public void setUserId(String userId) {
            this.userId = userId;
        }
    
        public String getToken() {
            return token;
        }
    
        public void setToken(String token) {
            this.token = token;
        }
    
        public boolean isLogin(){
            return !TextUtils.isEmpty(token);
        }
    
        public void saveUserInfo(String userId) {
            SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
            editor.putString("userId", userId);
            editor.apply();
        }
    }
    
    @ContentView(R.layout.activity_main)
    public class MainActivity extends RoboFragmentActivity {
    
        @InjectView(R.id.text_test)
        TextView textView;
    
        @Inject
        UserInfo userInfo;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            if(userInfo.isLogin()){
                textView.setText(userInfo.getUserId());
            } else {
                textView.setText("未登录");
            }
        }
    }
    

    至此,入坑篇告一段落,这篇主要说明了RoboGuice的视图、资源、系统服务、对象等注入,为开发带来便捷,同时也减少了模块的耦合性。

  • 相关阅读:
    C++中的queue类、Qt中的QQueue类
    FeignClient传输实体类(包括GET、POST)
    Spring @Order注解的使用
    springboot整合fastdfs实现上传和下载
    Illegal group reference解决方法
    Java io下载并替换文件内容
    Java根据模板下载TXT文件
    SpringBoot--logger日志配置,使用@Slf4j注解
    SpringBoot--poi导出Excel文件
    JRebel for IntelliJ 热部署破解方法
  • 原文地址:https://www.cnblogs.com/pedro-neer/p/5251610.html
Copyright © 2020-2023  润新知