For those interested, I’d like to share an example of how difficult it can be to get something done that seems to be simple.
The goal: include a number of images in the app, store the location of the images in the database.
I’ve created a picture book app, where users can create and edit picture books based on their own images. I store the images in a folder inside the app, and keep track of these files in a database. Now I want to provide one picture book with the app, so the bookshelf isn’t empty.
To break it down I want to:
- Add images to my project, probably somewhere in the resources folder
- When the app starts for the first time, I want to create records in the database that refer to these images. So a book can be created, just like a book that the user can create.
To lighten up this somewhat depressing post, here’s one of the images in the book.
So this gives me two main questions:
- In what folder do I need to store the images?
- How do I store the paths of these images in the database?
Starting point: Android documentation
First let me try to find an answer to my first question; where to store the images.
It seems I have (at least) three options:
- The assets folder
- The drawable folder inside res
- The raw folder inside res
Too bad it is not explained in the documentation when to use what folder. The documentation seems to assume that I want to access the files, but don’t care about the path. Here’s the most informative part for my quest, at the section explaining the ‘raw’ folder.
What I’m missing is the high level concept. Why does Android have these layers between files and code? Why not just have a folder and a way to refer to them.
Conclusion question 1) I don’t know where to put the images.. so I’ll just put it in the drawables folder.
Now let’s try to investigate how to access the resources later on:
It explains that for all the files included in resources, such as the drawable files, have a unique ID referring to it. It then goes on about how you can access those files in code (r.string.hello) or via XML (/@string/hello).
I have used this way to access files many times before. But now I become aware how much of this is a black box. For instance, what is the path to the launch icon file of my app? I have no idea where it is actually stored.
Since the official documentation didn’t seem to help me, I tried googling for answers. I ended up with stack overflow pages like these:
“..But it sounds like you don’t really need a path to asset files. You should look into these functions.. ..These functions allow you to get input stream or file descriptor for any of your assets. Here is an example:”
And this is where I get stranded on all these stack overflow pages. Every time I find someone who seems to ask exactly the same question as I do, the answer ends up saying that it’s smarter not to use the path but some other way to access these files. And since this is not my goal, I’m stuck again.
Conclusion question 2) I don’t know how to access these files. My mental model of how Android works is probably flawed in some ways.
Now what to do?
- Copy all images to a folder inside the app
One way to go about this, is that I use the access of the files to make a copy to a folder and use that path to store in the database. But that would make the app quite slow when it first starts and has to do all the copying. I feels like it should be much easier to do this. I know I can include images and even show them, so it shouldn’t be difficult to store a reference to the file.
- Keep Googling, hoping to find an answer
I’ve tried this for a couple of hours, and it hasn’t brought me as much as I hoped..
- Launch the app without an example book.
This is not an option, since I believe it is needed for a good experience. Also I’ve spent 40 hours drawing the book, so not using it would make me sad.
- First learn more about the inner workings of Android
- Hard code my example book
Just don’t use the database, and store it inside variables. While this sounds nice, it breaks the ‘edit’ mode of the book. Also I am stubborn enough that I now want to know how to do it properly and not circumvent it.
So I ended up with going for #1 making a copy of all files. Creating a bitmap for every image using BitmapFactory.decodeResource, and then storing it in the correct folder using Bitmap.Compress. This takes at least 10 seconds, so I have to put it in an async task.
Now I need to figure out a way to let the user know it needs to wait about 10 seconds and just do nothing so I can create a book for them.. Quite a horrible way to experience your first 10 seconds of the app. So for now I’ll just go to sleep and see if I can think of something better later this week.