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的视图、资源、系统服务、对象等注入,为开发带来便捷,同时也减少了模块的耦合性。

posted @ 2016-03-07 19:32  pedro_neer  阅读(2464)  评论(2编辑  收藏  举报