Web后端开发者应该对依赖注入都比较熟悉,至于Android又是如何进行依赖注入的呢?在这篇文章中,让我们一起通过一个例子了解一下在Android中进行依赖注入的好处。
AndroidAnnotations
AndroidAnnotations是一个致力于加快应用开发速度的Android端开源框架,它关注纵向开发,让开发者把注意义集中在真正重要的事情上。AndroidAnnotations让你的代码变得简单,便于维护。
我们始终应该相信,一个极客应该选择更简单的解决方式,Robert C. Martin说过
读代码和写代码的时间比例是10:1,所以让代码更易读,也会使代码更易编写。
当我们享受沉溺于移动开发的过程时,我们总会问自己,为什么要不断地重复写一些相同的代码?为什么我们的应用越来越难于维护?大量的Context和Activity对象,复杂的线程切换,难于理解的API和各种没必要的广播,我们能不能改善它们呢?
使用
直接使用Java注解就可以让开发者很明确的表现自己的意图,并让AndroidAnnotation在编译时生成中间代码。
特性
- Dependency injection: 可以注入视图、系统服务、资源等内容……
- Simplified threading model: 直接通过注解来决定是在UI线程还是后台执行一个方法。
- Event binding: 通过在方法上添加注解来将事件绑定到视图中,不需要一堆丑陋的匿名监听类。
- REST client: 创建一个客户端接口,AndroidAnnotations就会帮你实现。
- No magic: AndroidAnnotations在编译时会生成子类,你可以查看实现代码。
- AndroidAnnotations提供这些很酷的功能,而且它还不到50kb,而且对性能没有任何的影响
对比
我们可以通过一个简单的例子从代码的角度直观地看一下进行依赖注入前后的区别。
使用前
- public class BookmarksToClipboardActivity extends Activity {
-
- BookmarkAdapter adapter;
- ListView bookmarkList;
- EditText search;
- BookmarkApplication application;
- Animation fadeIn;
- ClipboardManager clipboardManager;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- getWindow().setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN);
- setContentView(R.layout.bookmarks);
- bookmarkList = (ListView) findViewById(R.id.bookmarkList);
- search = (EditText) findViewById(R.id.search);
- application = (BookmarkApplication) getApplication();
- fadeIn = AnimationUtils.loadAnimation(this, anim.fade_in);
- clipboardManager = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
-
- View updateBookmarksButton1 = findViewById(R.id.updateBookmarksButton1);
- updateBookmarksButton1.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- updateBookmarksClicked();
- }
- });
-
- View updateBookmarksButton2 = findViewById(R.id.updateBookmarksButton2);
- updateBookmarksButton2.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- updateBookmarksClicked();
- }
- });
-
- bookmarkList.setOnItemClickListener(new OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> p, View v, int pos, long id) {
- Bookmark selectedBookmark = (Bookmark) p.getAdapter().getItem(pos);
- bookmarkListItemClicked(selectedBookmark);
- }
- });
- initBookmarkList();
- }
- void initBookmarkList() {
- adapter = new BookmarkAdapter(this);
- bookmarkList.setAdapter(adapter);
- }
-
- void updateBookmarksClicked() {
- UpdateBookmarksTask task = new UpdateBookmarksTask();
- task.execute(search.getText().toString(), application.getUserId());
- }
-
- private static final String BOOKMARK_URL = //
- "http://www.bookmarks.com/bookmarks/{userId}?search={search}";
- class UpdateBookmarksTask extends AsyncTask<String, Void, Bookmarks> {
- @Override
- protected Bookmarks doInBackground(String... params) {
- String searchString = params[0];
- String userId = params[1];
- RestTemplate client = new RestTemplate();
- HashMap<String, Object> args = new HashMap<String, Object>();
- args.put("search", searchString);
- args.put("userId", userId);
- HttpHeaders httpHeaders = new HttpHeaders();
- HttpEntity<Bookmarks> request = new HttpEntity<Bookmarks>(httpHeaders);
- ResponseEntity<Bookmarks> response = client.exchange( //
- BOOKMARK_URL, HttpMethod.GET, request, Bookmarks.class, args);
- Bookmarks bookmarks = response.getBody();
- return bookmarks;
- }
- @Override
- protected void onPostExecute(Bookmarks result) {
- adapter.updateBookmarks(result);
- bookmarkList.startAnimation(fadeIn);
- }
- }
- void bookmarkListItemClicked(Bookmark selectedBookmark) {
- clipboardManager.setText(selectedBookmark.getUrl());
- }
- }
使用后
- @NoTitle
- @Fullscreen
- @EActivity(R.layout.bookmarks)
- public class BookmarksToClipboardActivity extends Activity {
-
- BookmarkAdapter adapter;
-
- @ViewById
- ListView bookmarkList;
- @ViewById
- EditText search;
- @App
- BookmarkApplication application;
- @RestService
- BookmarkClient restClient;
- @AnimationRes
- Animation fadeIn;
- @SystemService
- ClipboardManager clipboardManager;
- @AfterViews
- void initBookmarkList() {
- adapter = new BookmarkAdapter(this);
- bookmarkList.setAdapter(adapter);
- }
- @Click({R.id.updateBookmarksButton1, R.id.updateBookmarksButton2})
- void updateBookmarksClicked() {
- searchAsync(search.getText().toString(), application.getUserId());
- }
- @Background
- void searchAsync(String searchString, String userId) {
- Bookmarks bookmarks = restClient.getBookmarks(searchString, userId);
- updateBookmarks(bookmarks);
- }
- @UiThread
- void updateBookmarks(Bookmarks bookmarks) {
- adapter.updateBookmarks(bookmarks);
- bookmarkList.startAnimation(fadeIn);
- }
- @ItemClick
- void bookmarkListItemClicked(Bookmark selectedBookmark) {
- clipboardManager.setText(selectedBookmark.getUrl());
- }
- }
- @Rest("http://www.bookmarks.com")
- public interface BookmarkClient {
- @Get("/bookmarks/{userId}?search={search}")
- Bookmarks getBookmarks(String search, String userId);
- }
实践
AndroidAnnotations是如何实现住注入的?我们以@EActivityannotated为例:
- @EActivity
- public class MyActivity extends Activity {
- // ...
- }
它会在同一个包下的另一个文件夹中为MyActivity生成了一个子类:
- public final class MyActivity_ extends MyActivity {
- // ...
- }
在子类中通过重写为Activity添加实现,比如onCreate()方法,然后在父类中委托,这就是为什么我们使用AndroidAnnotations的时候需要在AndroidManifest.xml中多加一个下划线:
- <activity android:name=".MyListActivity_" />
在开发中,你经常这样启动一个Activity:
- startActivity(this, MyListActivity.class);
然而通过AndroidAnnotations,你必须启动MyListActivity_.class:
- startActivity(this, MyListActivity_.class);
Service也是如此:
- startService(this, MyService.class);
- startService(this,MyService_.class);
这样干对性能有影响吗?
简单的回答是“不会!”,更多的原因可以看看FAQ。
https://github.com/excilys/androidannotations/wiki/FAQ#perf-impact
0 0