MinimalBible.github.io/_posts/2014-05-06-questioning-the-framework.md
2014-05-07 23:00:21 -04:00

5.8 KiB

layout title modified tags image comments share
post Questioning the Framework 2014-05-07 22:52:43 -0400
framework
dependency injection
di
ioc
inversion of control
jsr330
android annotations
butterknife
dagger
feature credit creditlink

(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 class, but the BookListFragment 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 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, as it doesn't force me to use Class_ naming, and is JSR-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. 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. The interesting bits that use ButterKnife are here. 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, 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 as well, and I'm going to write another blog post comparing everything soon!