mirror of
https://github.com/MinimalBible/MinimalBible.github.io
synced 2024-11-14 03:58:29 -05:00
78 lines
5.8 KiB
Markdown
78 lines
5.8 KiB
Markdown
---
|
|
layout: post
|
|
title: "Questioning the Framework"
|
|
modified: 2014-05-07 22:52:43 -0400
|
|
tags: [framework, dependency injection, di, ioc, inversion of control, jsr330, android annotations, butterknife, dagger]
|
|
image:
|
|
feature:
|
|
credit:
|
|
creditlink:
|
|
comments:
|
|
share:
|
|
---
|
|
*(insert joke about thinking outside the box here)*
|
|
------------------------------------------------
|
|
|
|
So, I've been trying to refactor some of the code design recently. Most of this is centered around the [DownloadManager](https://github.com/MinimalBible/MinimalBible/blob/adc3bbf69cb9326b561d8b22a20fd58162970683/MinimalBible/src/org/bspeice/minimalbible/activities/downloader/DownloadManager.java) class, but the [BookListFragment](https://github.com/MinimalBible/MinimalBible/blob/adc3bbf69cb9326b561d8b22a20fd58162970683/MinimalBible/src/org/bspeice/minimalbible/activities/downloader/BookListFragment.java) is involved as well. Before we get too much farther though, let's explain the use case.
|
|
|
|
The `BookListFragment` is responsible for displaying a `ListView` of books available for download, whether Bibles, Dictionaries, Commentaries, etc. There is one fragment per category of books. However, trying to refresh the list of available books is a very expensive operation. So, there is a `DownloadManager` to make downloading easy, and provide a caching mechanism. This class should be a Singleton to ensure that we re-use the list of books.
|
|
|
|
And that's the basic use case. Time for some code.
|
|
|
|
**BookListAdapter.java**
|
|
{% highlight java %}
|
|
@Override
|
|
public View getView(int position, View convertView, ViewGroup parent) {
|
|
BookItemView itemView;
|
|
if (convertView == null) {
|
|
itemView = BookItemView_.build(this.ctx);
|
|
} else {
|
|
itemView = (BookItemView) convertView;
|
|
}
|
|
itemView.bind(getItem(position));
|
|
return itemView;
|
|
}
|
|
{% endhighlight %}
|
|
|
|
**BookItemView.java**
|
|
{% highlight java %}
|
|
@EViewGroup(R.layout.list_download_items)
|
|
public class BookItemView extends RelativeLayout {
|
|
@ViewById (R.id.img_download_icon) ImageView downloadIcon;
|
|
@ViewById(R.id.txt_download_item_name) TextView itemName;
|
|
@ViewById(R.id.img_download_index_downloaded) ImageView isIndexedDownloaded;
|
|
@ViewById(R.id.img_download_item_downloaded) ImageView isDownloaded;
|
|
public BookItemView (Context ctx) { super(ctx); }
|
|
public void bind(Book b) {
|
|
itemName.setText(b.getName());
|
|
}
|
|
}
|
|
{% endhighlight %}
|
|
|
|
Here's what's going on: The `BookItemView` is responsible for displaying an individual element in the list. [AndroidAnnotations](http://androidannotations.org/) is responsible for injecting the `LayoutInflater`, and individual views (the `@ViewById`). From there, the `BookListAdapter` can then build individual elements of the list using `BookItemView_.build()`.
|
|
|
|
This works mostly fine, but here's my issue - the `BookItemView` is small enough, I feel it should be an inner class. I can't do that with AndroidAnnotations. Also, the astute reader will notice that I'm building a `BookView_`, not a `BookView`. That's AndroidAnnotations generating the class for me. Which is exactly what it should be doing, but in my limited experience I've been having to learn the semantics of when/not to use the generated class. Plus when you have a lot of generated classes all over the place, I think it will get complicated.
|
|
|
|
Onward to the `DownloadManager`. I haven't committed code for this yet, but I'm hoping to illustrate my point. The class needs to be a singleton, and will eventually need an EventBus inject. I imagine it would look something like this:
|
|
|
|
**DownloadManager.java**
|
|
{% highlight java %}
|
|
@Singleton
|
|
public class DownloadManager {
|
|
@Inject EventBus downloadBus;
|
|
// Extra methods to actually do stuff here
|
|
}
|
|
{% endhighlight %}
|
|
|
|
Now, the first question is, where do I get `@Inject` from? I'm wanting to use [Dagger](http://square.github.io/dagger/), as it doesn't force me to use `Class_` naming, and is [JSR-330](https://jcp.org/en/jsr/detail?id=330) compliant (which mostly means I think the `@Bean` naming used by AndroidAnnotations looks weird).
|
|
|
|
The second question is: where does `@Singleton` come from? That's a little bit ambiguous. Both Dagger and AndroidAnnotations provide an annotation, but one forces me to use the `Class_` naming *(AndroidAnnotations)*, one doesn't. One forces me to build an `ObjectGraph` at runtime *(Dagger)*, one doesn't. This can get very confusing.
|
|
|
|
Realizing I was about to run into this confusion, I ported the existing AndroidAnnotations code to use [ButterKnife](http://jakewharton.github.io/butterknife/). ButterKnife is a library used to support view injection (but does a bit more). It's not as feature-filled as AndroidAnnotations, but doesn't require that I use `Class_`.
|
|
|
|
You can check out the code over [here](https://github.com/MinimalBible/MinimalBible/tree/b49facb2fee9b0cbced5ee9d0c75dbf9afdb0cc2). The interesting bits that use ButterKnife are [here](https://github.com/MinimalBible/MinimalBible/blob/b49facb2fee9b0cbced5ee9d0c75dbf9afdb0cc2/MinimalBible/src/org/bspeice/minimalbible/activities/downloader/BookListAdapter.java). ButterKnife requires me to write a bit more boilerplate code, but doesn't force the class naming rules on me. It's a bit of a tradeoff.
|
|
|
|
So that's a quick overview of the problem. All that to say, **I'm questioning what I should use as a framework**. I like the functionality AA provides, but it comes with a readability/understandability penalty. Coming from Python, I'm a big fan of [making things explicit](http://legacy.python.org/dev/peps/pep-0020/), but AA does provide a lot. ButterKnife/Dagger are both incredibly well-designed, and very focused. Which means they leave me to do some of the legwork myself.
|
|
|
|
I've also been investigating [RoboGuice](https://github.com/roboguice/roboguice) as well, and I'm going to write another blog post comparing everything soon!
|