Android RoboGuice2 使用指南(4): 综合示例Astroboy

jerry Android 2015年08月24日 收藏

前面介紹了RogoGuice2.0的基本用法,其它使用可以參見RoboGuice1.1開發指南,2.0中提供了對Fragment,View(自定義View中使用注入)的支持,本博客不再一一介紹。

本例使用的是RoboGuice 開發包中的簡單示例Astroboy(阿童木)。涉及的使用RoboGuice2.0 的一些常用方法。

本例下載(Eclipse項目)。

下面對項目中RoboGuice2的使用進行解釋。因為本例沒使用自定義綁定,所以無需使用res/values/roboguice.xml 定義Module. 如有自定義模塊,可以參見Android RoboGuice2 使用指南(2): 第一個例子Hello World。

1. 類Astroboy

  1. // There's only one Astroboy, so make it a @Singleton.
  2. // This means that there will be only one instance of Astroboy in the entire
  3. // app.
  4. // Any class that requires an instance of Astroboy will get the same instance.
  5. // This also means this class needs to be thread safe, of course
  6. @Singleton
  7. public class Astroboy {
  8.  
  9. // Because Astroboy is a Singleton, we can't directly inject the current
  10. // Context since the current context may change depending on what activity
  11. // is using Astroboy
  12. // at the time. Instead we use the application context.
  13. // Vibrator is bound to context.getSystemService(VIBRATOR_SERVICE) in
  14. // DefaultRoboModule.
  15. // Random has no special bindings, so Guice will create a new instance for
  16. // us.
  17. @Inject Application application;
  18. @Inject Vibrator vibrator;
  19. @Inject Random random;
  20.  
  21. public void say(String something) {
  22. // Make a Toast, using the current context as returned by the Context
  23. // Provider
  24. Toast.makeText(application, "Astroboy says, \"" + something + "\"",
  25. Toast.LENGTH_LONG).show();
  26. }
  27.  
  28. public void brushTeeth() {
  29. vibrator.vibrate(
  30. new long[] { 0, 200, 50, 200, 50, 200, 50, 200, 50, 200, 50,
  31. 200, 50, 200, 50, 200, 50, 200, 50, 200, 50, 200, 50, },
  32. -1);
  33. }
  34.  
  35. public String punch() {
  36. final String expletives[] = new String[] { "POW!", "BANG!", "KERPOW!",
  37. "OOF!" };
  38. return expletives[random.nextInt(expletives.length)];
  39. }
  40. }
  41.  

程序中只希望使用一個Astroboy實例,因此可以使用@Singleton標註,此後任何使用

@Inject Astroboy astroboy;

注入的Astroboy都會指向同一個實例,這也是符合Singleton設計模式的。

@Inject Application application; 注入Application實例。參見Android RoboGuice 使用指南(15):Inject Context

@Inject Vibrator vibrator; 注入Android Vibrator實例,參見Android RoboGuice 使用指南(16):Standard Injection

@Inject Random random; 對於普通的Java 類型(POJO),如果該類具有預設構造函數(不帶參數的等),也可以使用RoboGuice自動注入實例。

因此當Astroboy創建時,RoboGuice 自動為application, vibrator, random 創建實例,無需使用new 或參數傳入來構造它們。

2. 類AstroboyRemoteControl

  1. /**
  2. * A class to control Astroboy remotely.
  3. *
  4. * This class uses the current context, so we must make it @ContextSingleton.
  5. * This means that there will be one AstroboyRemoteControl for every activity or
  6. * service that requires one. Note that we actually ask for the Activity, rather
  7. * than the Context (which is the same thing), because we need access to some
  8. * activity-related methods and this saves us from having to downcast to an
  9. * Activity manually.
  10. *
  11. * It also asks RoboGuice to inject the Astroboy instance so we can control him.
  12. *
  13. * What you'll learn in this class - What @ContextScope means and when to use it
  14. * - How to inject an Activity instead of a Context (which is really the same
  15. * thing) - How to use RoboGuice's convenient and flexible logging facility, Ln.
  16. */
  17. @ContextSingleton
  18. public class AstroboyRemoteControl {
  19.  
  20. // The Astroboy class has been decorated with @Singleton, so this instance
  21. // of Astroboy will be the same instance used elsewhere in our app.
  22. // Injecting an Activity is basically equivalent to "@Inject Context context",
  23. // and thus also requires @ContextScope. If you wanted, you could also
  24. // @Inject Application, Service, etc. wherever appropriate.
  25. @Inject Astroboy astroboy;
  26. @Inject Activity activity;
  27.  
  28. public void brushTeeth() {
  29. // More info about logging available here:
  30. // http://code.google.com/p/roboguice/wiki/Logging
  31. Ln.d("Sent brushTeeth command to Astroboy");
  32. astroboy.brushTeeth();
  33. }
  34.  
  35. public void say(String something) {
  36. Ln.d("Sent say(%s) command to Astroboy", something);
  37. astroboy.say(something);
  38. }
  39.  
  40. public void selfDestruct() {
  41. Toast.makeText(
  42. activity,
  43. "Your evil remote control has exploded! Now Astroboy is FREEEEEEEEEE!",
  44. Toast.LENGTH_LONG).show();
  45. activity.finish();
  46. }
  47. }
  48.  

與Singleton類似的一個Scope標註為@ContextSingleton ,它表示對於每個Activity實例有一個實例,不同的activity對應不同的實例。

@Inject Astroboy astroboy; 注入同一個Astroboy實例(Singleton)。

@Inject Astroboy astroboy; 注入對應的Activity實例。

3. 類AstroboyMasterConsole

  1. /**
  2. * This activity uses an AstroboyRemoteControl to control Astroboy remotely!
  3. *
  4. * What you'll learn in this class: - How to use @InjectView as a typesafe
  5. * version of findViewById() - How to inject plain old java objects as well
  6. * (POJOs) - When injection happens - Some basics about injection, including
  7. * when injection results in a call to an object's default constructor, versus
  8. * when it does something "special" like call getSystemService()
  9. */
  10. @ContentView(R.layout.main)
  11. public class AstroboyMasterConsole extends RoboActivity {
  12.  
  13. // Various views that we inject into the activity.
  14. // Equivalent to calling findViewById() in your onCreate(), except more
  15. // succinct
  16. @InjectView(R.id.self_destruct) Button selfDestructButton;
  17. @InjectView(R.id.say_text) EditText sayText;
  18. @InjectView(R.id.brush_teeth) Button brushTeethButton;
  19. @InjectView(tag = "fightevil") Button fightEvilButton; // we can also use tags if we want
  20.  
  21. // Standard Guice injection of Plain Old Java Objects (POJOs)
  22. // Guice will find or create the appropriate instance of AstroboyRemoteControl for us
  23. // Since we haven't specified a special binding for AstroboyRemoteControl,
  24. // Guice will create a new instance for us using AstroboyRemoteControl's default constructor.
  25. // Contrast this with Vibrator, which is an Android service that is
  26. // pre-bound by RoboGuice.
  27. // Injecting a Vibrator will return a new instance of a Vibrator obtained by
  28. // calling
  29. // context.getSystemService(VIBRATOR_SERVICE). This is configured in
  30. // DefaultRoboModule, which is
  31. // used by default to configure every RoboGuice injector.
  32. @Inject AstroboyRemoteControl remoteControl;
  33. @Inject Vibrator vibrator;
  34.  
  35. @Override
  36. public void onCreate(Bundle savedInstanceState) {
  37. super.onCreate(savedInstanceState); // @Inject, @InjectResource, and
  38. // @InjectExtra injection happens
  39. // during super.onCreate()
  40.  
  41. sayText.setOnEditorActionListener(new OnEditorActionListener() {
  42. public boolean onEditorAction(TextView textView, int i,
  43. KeyEvent keyEvent) {
  44.  
  45. // Have the remoteControl tell Astroboy to say something
  46. remoteControl.say(textView.getText().toString());
  47. textView.setText(null);
  48. return true;
  49. }
  50. });
  51.  
  52. brushTeethButton.setOnClickListener(new OnClickListener() {
  53. public void onClick(View view) {
  54. remoteControl.brushTeeth();
  55. }
  56. });
  57.  
  58. selfDestructButton.setOnClickListener(new OnClickListener() {
  59. public void onClick(View view) {
  60.  
  61. // Self destruct the remoteControl
  62. vibrator.vibrate(2000);
  63. remoteControl.selfDestruct();
  64. }
  65. });
  66.  
  67. // Fighting the forces of evil deserves its own activity
  68. fightEvilButton.setOnClickListener(new OnClickListener() {
  69. public void onClick(View view) {
  70. startActivity(new Intent(AstroboyMasterConsole.this,
  71. FightForcesOfEvilActivity.class));
  72. }
  73. });
  74.  
  75. }
  76.  
  77. }
  78.  

AstroboyMasterConsole 為主Activity,要使用RoboGuice,則Activity需從RoboActivity派生,其它如Service,Fragment等可以參見Android RoboGuice 使用指南(13):RoboGuice 功能描述。

@InjectView(R.id.self_destruct) Button selfDestructButton;  注入View實例,功能同findViewById。 它的另外一種方法是使用Tag,如

@InjectView(tag = “fightevil”) Button fightEvilButton ,功能一樣。

這個類使用@ContentView(R.layout.main) 為Activity指明ContentView,無需再調用setContentView.

4. 類FightForcesOfEvilActivity

  1. /**
  2. * Things you'll learn in this class: - How to inject Resources - How to use
  3. * RoboAsyncTask to do background tasks with injection - What it means to be a @Singleton
  4. */
  5. public class FightForcesOfEvilActivity extends RoboActivity {
  6.  
  7. @InjectView(R.id.expletive) TextView expletiveText;
  8.  
  9. // You can also inject resources such as Strings, Drawables, and Animations
  10. @InjectResource(R.anim.expletive_animation) Animation expletiveAnimation;
  11.  
  12. // AstroboyRemoteControl is annotated as @ContextSingleton, so the instance
  13. // we get in FightForcesOfEvilActivity will be a different instance than
  14. // the one we got in AstroboyMasterConsole
  15. // @Inject AstroboyRemoteControl remoteControl;
  16.  
  17. @Override
  18. protected void onCreate(Bundle savedInstanceState) {
  19. super.onCreate(savedInstanceState);
  20. setContentView(R.layout.fight_evil);
  21.  
  22. expletiveText.setAnimation(expletiveAnimation);
  23. expletiveAnimation.start();
  24.  
  25. // Throw some punches
  26. for (int i = 0; i < 10; ++i)
  27. new AsyncPunch(this) {
  28. @Override
  29. protected void onSuccess(String expletive) throws Exception {
  30. expletiveText.setText(expletive);
  31. }
  32.  
  33. // We could also override onException() and onFinally() if we
  34. // wanted
  35.  
  36. }.execute();
  37.  
  38. }
  39.  
  40. // This class will call Astroboy.punch() in the background
  41. public static class AsyncPunch extends RoboAsyncTask<String> {
  42.  
  43. // Because Astroboy is a @Singleton, this will be the same
  44. // instance that we inject elsewhere in our app.
  45. // Random of course will be a new instance of java.util.Random, since
  46. // we haven't specified any special binding instructions anywhere
  47. @Inject Astroboy astroboy;
  48. @Inject Random random;
  49.  
  50. public AsyncPunch(Context context) {
  51. super(context);
  52. }
  53.  
  54. public String call() throws Exception {
  55. Thread.sleep(random.nextInt(5 * 1000));
  56. return astroboy.punch();
  57. }
  58. }
  59. }
  60.  

@InjectResource(R.anim.expletive_animation) Animation expletiveAnimation; 注入資源,可以參見Android RoboGuice 使用指南(18):Inject Resources。

從代碼中可以看出使用RoboGuice 注入可以簡化程序,運行結果如下圖: