The requested URL was not found on this server. That's all we know.
7 |
8 |
13 |
--------------------------------------------------------------------------------
/CNAME:
--------------------------------------------------------------------------------
1 | www.androiddesignpatterns.com
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | ruby '2.4.0'
4 |
5 | group :jekyll_plugins do
6 | gem 'github-pages', '>=105'
7 | gem 'jekyll-paginate'
8 | end
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | activesupport (4.2.9)
5 | i18n (~> 0.7)
6 | minitest (~> 5.1)
7 | thread_safe (~> 0.3, >= 0.3.4)
8 | tzinfo (~> 1.1)
9 | addressable (2.5.2)
10 | public_suffix (>= 2.0.2, < 4.0)
11 | coffee-script (2.4.1)
12 | coffee-script-source
13 | execjs
14 | coffee-script-source (1.11.1)
15 | colorator (1.1.0)
16 | commonmarker (0.17.7.1)
17 | ruby-enum (~> 0.5)
18 | concurrent-ruby (1.0.5)
19 | ethon (0.11.0)
20 | ffi (>= 1.3.0)
21 | execjs (2.7.0)
22 | faraday (0.13.1)
23 | multipart-post (>= 1.2, < 3)
24 | ffi (1.9.18)
25 | forwardable-extended (2.6.0)
26 | gemoji (3.0.0)
27 | github-pages (172)
28 | activesupport (= 4.2.9)
29 | github-pages-health-check (= 1.3.5)
30 | jekyll (= 3.6.2)
31 | jekyll-avatar (= 0.5.0)
32 | jekyll-coffeescript (= 1.0.2)
33 | jekyll-commonmark-ghpages (= 0.1.3)
34 | jekyll-default-layout (= 0.1.4)
35 | jekyll-feed (= 0.9.2)
36 | jekyll-gist (= 1.4.1)
37 | jekyll-github-metadata (= 2.9.3)
38 | jekyll-mentions (= 1.2.0)
39 | jekyll-optional-front-matter (= 0.3.0)
40 | jekyll-paginate (= 1.1.0)
41 | jekyll-readme-index (= 0.2.0)
42 | jekyll-redirect-from (= 0.12.1)
43 | jekyll-relative-links (= 0.5.2)
44 | jekyll-remote-theme (= 0.2.3)
45 | jekyll-sass-converter (= 1.5.0)
46 | jekyll-seo-tag (= 2.3.0)
47 | jekyll-sitemap (= 1.1.1)
48 | jekyll-swiss (= 0.4.0)
49 | jekyll-theme-architect (= 0.1.0)
50 | jekyll-theme-cayman (= 0.1.0)
51 | jekyll-theme-dinky (= 0.1.0)
52 | jekyll-theme-hacker (= 0.1.0)
53 | jekyll-theme-leap-day (= 0.1.0)
54 | jekyll-theme-merlot (= 0.1.0)
55 | jekyll-theme-midnight (= 0.1.0)
56 | jekyll-theme-minimal (= 0.1.0)
57 | jekyll-theme-modernist (= 0.1.0)
58 | jekyll-theme-primer (= 0.5.2)
59 | jekyll-theme-slate (= 0.1.0)
60 | jekyll-theme-tactile (= 0.1.0)
61 | jekyll-theme-time-machine (= 0.1.0)
62 | jekyll-titles-from-headings (= 0.5.0)
63 | jemoji (= 0.8.1)
64 | kramdown (= 1.14.0)
65 | liquid (= 4.0.0)
66 | listen (= 3.0.6)
67 | mercenary (~> 0.3)
68 | minima (= 2.1.1)
69 | rouge (= 2.2.1)
70 | terminal-table (~> 1.4)
71 | github-pages-health-check (1.3.5)
72 | addressable (~> 2.3)
73 | net-dns (~> 0.8)
74 | octokit (~> 4.0)
75 | public_suffix (~> 2.0)
76 | typhoeus (~> 0.7)
77 | html-pipeline (2.7.1)
78 | activesupport (>= 2)
79 | nokogiri (>= 1.4)
80 | i18n (0.9.1)
81 | concurrent-ruby (~> 1.0)
82 | jekyll (3.6.2)
83 | addressable (~> 2.4)
84 | colorator (~> 1.0)
85 | jekyll-sass-converter (~> 1.0)
86 | jekyll-watch (~> 1.1)
87 | kramdown (~> 1.14)
88 | liquid (~> 4.0)
89 | mercenary (~> 0.3.3)
90 | pathutil (~> 0.9)
91 | rouge (>= 1.7, < 3)
92 | safe_yaml (~> 1.0)
93 | jekyll-avatar (0.5.0)
94 | jekyll (~> 3.0)
95 | jekyll-coffeescript (1.0.2)
96 | coffee-script (~> 2.2)
97 | coffee-script-source (~> 1.11.1)
98 | jekyll-commonmark (1.1.0)
99 | commonmarker (~> 0.14)
100 | jekyll (>= 3.0, < 4.0)
101 | jekyll-commonmark-ghpages (0.1.3)
102 | commonmarker (~> 0.17.6)
103 | jekyll-commonmark (~> 1)
104 | rouge (~> 2)
105 | jekyll-default-layout (0.1.4)
106 | jekyll (~> 3.0)
107 | jekyll-feed (0.9.2)
108 | jekyll (~> 3.3)
109 | jekyll-gist (1.4.1)
110 | octokit (~> 4.2)
111 | jekyll-github-metadata (2.9.3)
112 | jekyll (~> 3.1)
113 | octokit (~> 4.0, != 4.4.0)
114 | jekyll-mentions (1.2.0)
115 | activesupport (~> 4.0)
116 | html-pipeline (~> 2.3)
117 | jekyll (~> 3.0)
118 | jekyll-optional-front-matter (0.3.0)
119 | jekyll (~> 3.0)
120 | jekyll-paginate (1.1.0)
121 | jekyll-readme-index (0.2.0)
122 | jekyll (~> 3.0)
123 | jekyll-redirect-from (0.12.1)
124 | jekyll (~> 3.3)
125 | jekyll-relative-links (0.5.2)
126 | jekyll (~> 3.3)
127 | jekyll-remote-theme (0.2.3)
128 | jekyll (~> 3.5)
129 | rubyzip (>= 1.2.1, < 3.0)
130 | typhoeus (>= 0.7, < 2.0)
131 | jekyll-sass-converter (1.5.0)
132 | sass (~> 3.4)
133 | jekyll-seo-tag (2.3.0)
134 | jekyll (~> 3.3)
135 | jekyll-sitemap (1.1.1)
136 | jekyll (~> 3.3)
137 | jekyll-swiss (0.4.0)
138 | jekyll-theme-architect (0.1.0)
139 | jekyll (~> 3.5)
140 | jekyll-seo-tag (~> 2.0)
141 | jekyll-theme-cayman (0.1.0)
142 | jekyll (~> 3.5)
143 | jekyll-seo-tag (~> 2.0)
144 | jekyll-theme-dinky (0.1.0)
145 | jekyll (~> 3.5)
146 | jekyll-seo-tag (~> 2.0)
147 | jekyll-theme-hacker (0.1.0)
148 | jekyll (~> 3.5)
149 | jekyll-seo-tag (~> 2.0)
150 | jekyll-theme-leap-day (0.1.0)
151 | jekyll (~> 3.5)
152 | jekyll-seo-tag (~> 2.0)
153 | jekyll-theme-merlot (0.1.0)
154 | jekyll (~> 3.5)
155 | jekyll-seo-tag (~> 2.0)
156 | jekyll-theme-midnight (0.1.0)
157 | jekyll (~> 3.5)
158 | jekyll-seo-tag (~> 2.0)
159 | jekyll-theme-minimal (0.1.0)
160 | jekyll (~> 3.5)
161 | jekyll-seo-tag (~> 2.0)
162 | jekyll-theme-modernist (0.1.0)
163 | jekyll (~> 3.5)
164 | jekyll-seo-tag (~> 2.0)
165 | jekyll-theme-primer (0.5.2)
166 | jekyll (~> 3.5)
167 | jekyll-github-metadata (~> 2.9)
168 | jekyll-seo-tag (~> 2.2)
169 | jekyll-theme-slate (0.1.0)
170 | jekyll (~> 3.5)
171 | jekyll-seo-tag (~> 2.0)
172 | jekyll-theme-tactile (0.1.0)
173 | jekyll (~> 3.5)
174 | jekyll-seo-tag (~> 2.0)
175 | jekyll-theme-time-machine (0.1.0)
176 | jekyll (~> 3.5)
177 | jekyll-seo-tag (~> 2.0)
178 | jekyll-titles-from-headings (0.5.0)
179 | jekyll (~> 3.3)
180 | jekyll-watch (1.5.1)
181 | listen (~> 3.0)
182 | jemoji (0.8.1)
183 | activesupport (~> 4.0, >= 4.2.9)
184 | gemoji (~> 3.0)
185 | html-pipeline (~> 2.2)
186 | jekyll (>= 3.0)
187 | kramdown (1.14.0)
188 | liquid (4.0.0)
189 | listen (3.0.6)
190 | rb-fsevent (>= 0.9.3)
191 | rb-inotify (>= 0.9.7)
192 | mercenary (0.3.6)
193 | mini_portile2 (2.3.0)
194 | minima (2.1.1)
195 | jekyll (~> 3.3)
196 | minitest (5.10.3)
197 | multipart-post (2.0.0)
198 | net-dns (0.8.0)
199 | nokogiri (1.8.1)
200 | mini_portile2 (~> 2.3.0)
201 | octokit (4.8.0)
202 | sawyer (~> 0.8.0, >= 0.5.3)
203 | pathutil (0.16.1)
204 | forwardable-extended (~> 2.6)
205 | public_suffix (2.0.5)
206 | rb-fsevent (0.10.2)
207 | rb-inotify (0.9.10)
208 | ffi (>= 0.5.0, < 2)
209 | rouge (2.2.1)
210 | ruby-enum (0.7.1)
211 | i18n
212 | rubyzip (1.2.1)
213 | safe_yaml (1.0.4)
214 | sass (3.5.4)
215 | sass-listen (~> 4.0.0)
216 | sass-listen (4.0.0)
217 | rb-fsevent (~> 0.9, >= 0.9.4)
218 | rb-inotify (~> 0.9, >= 0.9.7)
219 | sawyer (0.8.1)
220 | addressable (>= 2.3.5, < 2.6)
221 | faraday (~> 0.8, < 1.0)
222 | terminal-table (1.8.0)
223 | unicode-display_width (~> 1.1, >= 1.1.1)
224 | thread_safe (0.3.6)
225 | typhoeus (0.8.0)
226 | ethon (>= 0.8.0)
227 | tzinfo (1.2.4)
228 | thread_safe (~> 0.1)
229 | unicode-display_width (1.3.0)
230 |
231 | PLATFORMS
232 | ruby
233 |
234 | DEPENDENCIES
235 | github-pages (>= 105)
236 | jekyll-paginate
237 |
238 | RUBY VERSION
239 | ruby 2.4.0p0
240 |
241 | BUNDLED WITH
242 | 1.16.0
243 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Alex Lockwood
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Android Design Patterns
2 | =======================
3 |
4 | This is the source code for www.androiddesignpatterns.com. Android Design Patterns is powered by [Jekyll](http://jekyllrb.com/) and is hosted by [GitHub Pages](http://pages.github.com/).
5 |
6 | If you wish to fork this repository to use as the basis of your own blogging template, please make sure you review the [license and copyright](#license-and-copyright) information below.
7 |
8 | ## Building locally
9 |
10 | Make sure you have at least Ruby 2.0.0 installed on your machine. From the this project's root directory, execute:
11 |
12 | ```
13 | gem install bundler
14 | bundler install
15 | ```
16 |
17 | Then,
18 |
19 | ```
20 | npm install
21 | npm start
22 | ```
23 |
24 | Then navigate to `http://localhost:4000` to view the locally built site.
25 |
26 | ## Find a typo?
27 |
28 | If you find a typo, please feel free to suggest a correction yourself by submitting a pull request! All published posts are written in standard markdown format and can be found in the [`_posts/`](/_posts) directory. If you are unfamiliar with GitHub, the easiest way to suggest a fix is to:
29 |
30 | 1. Navigate to the [`_posts/`](/_posts) directory and click on the post that contains the error.
31 | 2. Click **Edit** and update the post with your proposed correction.
32 | 3. Write a _detailed_ commit summary and description (if necessary) and click **Propose File Change**.
33 | 4. Click **Send pull request** on the following page. I'll review the correction as soon as I can!
34 |
35 | Thanks in advance!
36 |
37 | ## License and copyright
38 |
39 | All posts and images (i.e. all files in the [`_posts/`](/_posts) and [`assets/images/`](/assets/images) directories) are copyright Alex Lockwood. You may not copy, distribute, or trasmit these files or their contents without explicit permission from the author.
40 |
41 | All other files are licensed under the [MIT license](/LICENSE.txt).
42 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | name: Android Design Patterns
2 | author:
3 | name: Alex Lockwood
4 | googleplus: https://google.com/+AlexLockwood
5 | twitter: https://twitter.com/alexjlockwood
6 | stackoverflow: https://stackoverflow.com/users/844882
7 | flickr: https://www.flickr.com/photos/tailorransom
8 | github: https://github.com/alexjlockwood
9 | feedburner: https://feeds.feedburner.com/androiddesignpatterns
10 |
11 | baseurl: https://www.androiddesignpatterns.com
12 | description: 'Android Design Patterns is a website for developers who wish to better understand the Android application framework. The tutorials here emphasize proper code design and project maintainability.'
13 |
14 | paginate: 5
15 |
16 | permalink: /:year/:month/:title.html
17 |
18 | exclude: [
19 | 'README.md',
20 | 'LICENSE.txt',
21 | 'gulpfile.js',
22 | 'node_modules',
23 | 'package.json',
24 | 'Gemfile',
25 | 'Gemfile.lock'
26 | ]
27 | plugins: [jekyll-paginate]
28 |
29 | markdown: kramdown
30 | kramdown:
31 | input: GFM
32 | syntax_highlighter: rouge
33 | hard_wrap: false
34 |
35 | host: 0.0.0.0
36 | future: true
37 |
--------------------------------------------------------------------------------
/_drafts/2015-04-01-shared-element-callbacks.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: 'Shared Element Callbacks (part 3c)'
4 | date: 2015-04-01
5 | permalink: /2015/04/shared-element-callbacks-part3c.html
6 | related: ['/2012/08/implementing-loaders.html',
7 | '/2013/08/fragment-transaction-commit-state-loss.html',
8 | '/2012/06/app-force-close-honeycomb-ics.html']
9 | published: false
10 | ---
11 |
12 |
13 | ### Creating Advanced Transitions Using `SharedElementCallback`s
14 |
15 | You can further customize your shared element transitions by setting a [`SharedElementCallback`][SharedElementCallback]. Understanding the SharedElementCallback class will be important if you want to implement custom Transitions that are more complicated than simply moving an image from one location to another. In particular, the following three callback methods are very important to understand when writing more complex shared element transitions:
16 |
17 | * `onMapSharedElements()` lets you adjust the mapping of shared element names to Views. **TODO: more detail.**
18 | * `onSharedElementStart()` and `onSharedElementEnd()` let you adjust view properties in your layout immediately before the transitions capture their start and end values respectively. **TODO: more detail.**
19 |
--------------------------------------------------------------------------------
/_includes/fonts.css:
--------------------------------------------------------------------------------
1 | @font-face{font-family:'Asap';font-style:normal;font-weight:400;src:local('Asap'),local('Asap-Regular'),url(https://themes.googleusercontent.com/static/fonts/asap/v1/nvGvEwsMAvkIa6w2U-PXffesZW2xOQ-xsNqO47m55DA.woff) format('woff')}@font-face{font-family:'Asap';font-style:normal;font-weight:700;src:local('Asap Bold'),local('Asap-Bold'),url(https://themes.googleusercontent.com/static/fonts/asap/v1/QGN0GG0540fyG6NL_PpOpgLUuEpTyoUstqEm5AMlJo4.woff) format('woff')}@font-face{font-family:'Asap';font-style:italic;font-weight:400;src:local('Asap Italic'),local('Asap-Italic'),url(https://themes.googleusercontent.com/static/fonts/asap/v1/QnZU7dKCBgkkMBlac2djsOvvDin1pK8aKteLpeZ5c0A.woff) format('woff')}@font-face{font-family:'Asap';font-style:italic;font-weight:700;src:local('Asap Bold Italic'),local('Asap-BoldItalic'),url(https://themes.googleusercontent.com/static/fonts/asap/v1/_sVKdO-TLWvaH-ptGimJBbO3LdcAZYWl9Si6vvxL-qU.woff) format('woff')}@font-face{font-family:'Roboto';font-style:normal;font-weight:400;src:local('Roboto Regular'),local('Roboto-Regular'),url(https://themes.googleusercontent.com/static/fonts/roboto/v9/CrYjSnGjrRCn0pd9VQsnFOvvDin1pK8aKteLpeZ5c0A.woff) format('woff')}@font-face{font-family:'Roboto';font-style:normal;font-weight:700;src:local('Roboto Bold'),local('Roboto-Bold'),url(https://themes.googleusercontent.com/static/fonts/roboto/v9/d-6IYplOFocCacKzxwXSOLO3LdcAZYWl9Si6vvxL-qU.woff) format('woff')}@font-face{font-family:'Roboto';font-style:normal;font-weight:900;src:local('Roboto Black'),local('Roboto-Black'),url(https://themes.googleusercontent.com/static/fonts/roboto/v9/mnpfi9pxYH-Go5UiibESIrO3LdcAZYWl9Si6vvxL-qU.woff) format('woff')}
--------------------------------------------------------------------------------
/_includes/posts/2016/11/29/includes10_downloading_animated_svgs.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
61 |
62 |
66 |
70 |
74 |
78 |
79 |
80 |
Figure 10. A downloading progress icon animation that demonstrates a combination of several techniques discussed in this blog post. Android source code is available on GitHub: (a) in-progress download and (b) download complete. Click the icon to start its animation.
133 | Figure 1. Understanding how paths are drawn using path commands. The numbers
134 | in the diagrams match the position of the path after each command is executed. In each diagram, the top left coordinate
135 | is (0,0) and the bottom right coordinate is (12,12). The source code
136 | for each icon is available on
137 | GitHub.
Figure 2. The effects of different combinations of <group> transformations on a play, pause, and record icon. The order of the checkboxes matches the order in which the transformations are applied in the sample code above. Android source code for each icon is available on GitHub.
Figure 3. Understanding how <group> transformations can be used to create icon animations. Android source code for each is available on GitHub: (a)
69 | expand to collapse, (b)
70 | alarm clock, and (c)
71 | radio button. Click each icon to start its animation.
Figure 9. Understanding how <clip-path>s can be used to create icon animations. Android source code for each is available on GitHub: (a) hourglass, (b) eye visibility, and (c) heart fill/break. Click each icon to start its animation.
77 |
78 |
79 |
--------------------------------------------------------------------------------
/_posts/2012-05-21-correctly-managing-your-sqlite-database.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: 'Correctly Managing your SQLite Database'
4 | date: 2012-05-21
5 | permalink: /2012/05/correctly-managing-your-sqlite-database.html
6 | related: ['/2012/06/content-resolvers-and-content-providers.html',
7 | '/2012/07/understanding-loadermanager.html',
8 | '/2012/10/sqlite-contentprovider-thread-safety.html']
9 | ---
10 | One thing that I've noticed other Android developers having trouble with is properly
11 | setting up their `SQLiteDatabase`. Often times, I come across questions on StackOverflow
12 | asking about error messages such as,
13 |
14 | ```
15 | E/Database(234): Leak found
16 | E/Database(234): Caused by: java.lang.IllegalStateException: SQLiteDatabase created and never closed
17 | ```
18 |
19 | As you have probably figured out, this exception is thrown when you have opened more
20 | `SQLiteDatabase` instances than you have closed. Managing the database can be complicated
21 | when first starting out with Android development, especially to those who are just beginning
22 | to understand the `Activity` lifecycle. The easiest solution is to make your database
23 | instance a singleton instance across the entire application's lifecycle. This will ensure
24 | that no leaks occur, and will make your life a lot easier since it eliminates the
25 | possibility of forgetting to close your database as you code.
26 |
27 |
28 |
29 | Here are two examples that illustrates three possible approaches in managing your
30 | singleton database. These will ensure safe access to the database throughout the application.
31 |
32 | ### Approach #1: Use a Singleton to Instantiate the `SQLiteOpenHelper`
33 |
34 | Declare your database helper as a static instance variable and use the Singleton
35 | pattern to guarantee the singleton property. The sample code below should give you a good
36 | idea on how to go about designing the `DatabaseHelper` class correctly.
37 |
38 | The static `getInstance()` method ensures that only one `DatabaseHelper`
39 | will ever exist at any given time. If the `sInstance` object has not been initialized,
40 | one will be created. If one has already been created then it will simply be returned.
41 | You should not initialize your helper object using with `new DatabaseHelper(context)`!
42 | Instead, always use `DatabaseHelper.getInstance(context)`, as it guarantees that only one
43 | database helper will exist across the entire application's lifecycle.
44 |
45 | ```java
46 | public class DatabaseHelper extends SQLiteOpenHelper {
47 |
48 | private static DatabaseHelper sInstance;
49 |
50 | private static final String DATABASE_NAME = "database_name";
51 | private static final String DATABASE_TABLE = "table_name";
52 | private static final int DATABASE_VERSION = 1;
53 |
54 | public static synchronized DatabaseHelper getInstance(Context context) {
55 |
56 | // Use the application context, which will ensure that you
57 | // don't accidentally leak an Activity's context.
58 | // See this article for more information: http://bit.ly/6LRzfx
59 | if (sInstance == null) {
60 | sInstance = new DatabaseHelper(context.getApplicationContext());
61 | }
62 | return sInstance;
63 | }
64 |
65 | /**
66 | * Constructor should be private to prevent direct instantiation.
67 | * make call to static method "getInstance()" instead.
68 | */
69 | private DatabaseHelper(Context context) {
70 | super(context, DATABASE_NAME, null, DATABASE_VERSION);
71 | }
72 | }
73 | ```
74 |
75 | ### Approach #2: Wrap the `SQLiteDatabase` in a `ContentProvider`
76 |
77 | This is also a nice approach. For one, the new `CursorLoader` class requires
78 | `ContentProvider`s, so if you want an Activity or Fragment to implement `LoaderManager.LoaderCallbacks`
79 | with a `CursorLoader` (as discussed in this post),
80 | you'll need to implement a `ContentProvider` for your application. Further, you don't need to worry
81 | about making a singleton database helper with `ContentProvider`s. Simply call `getContentResolver()`
82 | from the Activity and the system will take care of everything for you (in other words, there is no
83 | need for designing a Singleton pattern to prevent multiple instances from being created).
84 |
85 | Leave a comment if this helped or if you have any questions!
86 |
--------------------------------------------------------------------------------
/_posts/2012-05-24-using-newinstance-to-instantiate-a-fragment.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: 'Using newInstance() to Instantiate a Fragment'
4 | date: 2012-05-24
5 | permalink: /2012/05/using-newinstance-to-instantiate.html
6 | ---
7 | I recently came across an interesting question on StackOverflow regarding Fragment instantiation:
8 |
9 | > What is the difference between `new MyFragment()` and `MyFragment.newInstance()`?
10 | > Should I prefer one over the other?
11 |
12 | Good question. The answer, as the title of this blog suggests, is a matter of proper design. In this
13 | case, the `newInstance()` method is a "static factory method," allowing us to initialize and setup a
14 | new `Fragment` without having to call its constructor and additional setter methods. Providing static
15 | factory methods for your fragments is good practice because it encapsulates and abstracts the steps
16 | required to setup the object from the client. For example, consider the following code:
17 |
18 |
19 |
20 | ```java
21 | public class MyFragment extends Fragment {
22 |
23 | /**
24 | * Static factory method that takes an int parameter,
25 | * initializes the fragment's arguments, and returns the
26 | * new fragment to the client.
27 | */
28 | public static MyFragment newInstance(int index) {
29 | MyFragment f = new MyFragment();
30 | Bundle args = new Bundle();
31 | args.putInt("index", index);
32 | f.setArguments(args);
33 | return f;
34 | }
35 |
36 | }
37 | ```
38 |
39 | Rather than having the client call the default constructor and manually set the fragment's arguments
40 | themselves, we provide a static factory method that does this for them. This is preferred over the
41 | default constructor for two reasons. One, it's convenient for the client, and two, it enforces well-defined
42 | behavior. By providing a static factory method, we protect ourselves from bugs down the line—we no
43 | longer need to worry about accidentally forgetting to initialize the fragment's arguments or incorrectly doing so.
44 |
45 | Overall, while the difference between the two is mostly just a matter of design, this difference is really
46 | important because it provides another level of abstraction and makes code a lot easier to understand.
47 |
48 | Feel free to leave a comment if this blog post helped (it will motivate me to write more in the future)! :)
49 |
--------------------------------------------------------------------------------
/_posts/2012-05-26-reaping-benefits-of-the-loadermanager.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: 'Reaping the Benefits of the LoaderManager'
4 | date: 2012-05-26
5 | permalink: /2012/05/why-you-should-use-loadermanager.html
6 | ---
7 | With Android 3.0 came the introduction of the `LoaderManager` class, an abstract
8 | class associated with an `Activity` or `Fragment` for managing one or
9 | more `Loader` instances. The `LoaderManager` class is one of my favorite
10 | additions to the Android framework for a number of reasons, but mostly because it _significantly_
11 | reduces code complexity and makes your application run a lot smoother. Implementing data loaders
12 | with the `LoaderManager` is simple to implement, and takes care of everything about
13 | lifecycle management so are much less error prone.
14 |
15 |
16 |
17 | While applications are free to write their own loaders for loading various types of data, the
18 | most common (and simplest) use of the `LoaderManager` is with a `CursorLoader`.
19 | When done correctly, the `CursorLoader` class offloads the work of loading data on a thread,
20 | and keeps the data persistent during short term activity refresh events, such as an orientation change.
21 | In addition to performing the initial query, the `CursorLoader` registers a
22 | `ContentObserver` with the dataset you requested and calls `forceLoad()`
23 | on itself when the data set changes, and is thus auto-updating. This is extremely convenient for
24 | the programmer, as he doesn't have to worry about performing these queries himself. Further,
25 | for bigger screens it becomes more important that you query on a separate thread since configuration
26 | changes involve recreating the entire view layout, a complex operation that can cause disasters
27 | when blocked.
28 |
29 | As mentioned earlier, one could implement his or her class to load data on a separate
30 | thread using an `AsyncTask` or even a `Thread`.
31 | The point, however, is that the `LoaderManager` does this all for you, so
32 | it's convenient for the developer, less error prone, and simple to implement. Of course
33 | it is possible to use an `AsyncTask` to keep your application UI thread friendly,
34 | but it will involve a lot more code, and implementing your class so that it will retain the
35 | loaded `Cursor` over the twists and turns of the `Activity` lifecycle
36 | won't be simple. The bottom line is that `LoaderManager` will do this automatically
37 | for you, as well as taking care of correctly creating and closing the `Cursor`
38 | based on the `Activity` lifecycle.
39 |
40 | To use `LoaderManager` with (or without) the `CursorLoader`
41 | in an app targeting pre-Honeycomb devices, you should make use of the classes provided
42 | in the Android Support Package, including the `FragmentActivity` class. A
43 | `FragmentActivity` is just an `Activity` that has been created
44 | for Android compatibility support, and does not require the use of fragments in your
45 | application. When transitioning from an `Activity`s to `FragmentActivity`s,
46 | be extremely careful that you use the `getSupportLoaderManager()` instead of
47 | `getLoaderManager()`. `FragmentActivity` extends `Activity`,
48 | thus inheriting all of its methods, and as a result the compiler will not complain if you
49 | accidentally mix up these methods, so be very careful!
50 |
51 |
Leave a comment if you have any questions or criticisms... or just to let me know
52 | that you managed to read through this entire post without getting distracted! I'm also
53 | open to providing more explicit code samples if anyone asks.
--------------------------------------------------------------------------------
/_posts/2012-05-30-basic-android-debugging-with-logs.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: 'Basic Android Debugging with Logs'
4 | date: 2012-05-30
5 | permalink: /2012/05/intro-to-android-debug-logging.html
6 | ---
7 | As with most areas in software engineering, debugging is a crucial aspect
8 | of Android development. Properly setting up your application for debugging
9 | can save you hours of work and frustration. Unfortunately, in my experience
10 | not many beginners learn how to properly make use of the utility classes
11 | provided in the Android SDK. Unless you are an experienced developer, it
12 | is my personal belief that Android debugging should follow a _pattern_.
13 | This will prove beneficial for a couple reasons:
14 |
15 |
16 |
17 | + **It allows you to anticipate bugs down the line.** Setting up your development
18 | work space for debugging will give you a head start on bugs you might encounter
19 | in the future.
20 |
21 | + **It gives you centralized control over the debugging process.** Disorganized and
22 | sparse placement of log messages in your class can clutter your logcat output, making
23 | it difficult to interpret debugging results. The ability to toggle certain groups
24 | of log messages on/off can make your life a whole lot easier, especially if your
25 | application is complex.
26 |
27 | ### The `Log` Class
28 |
29 | For those of you who don't know, the Android SDK includes a useful logging
30 | utility class called `android.util.Log`. The class allows you to
31 | log messages categorized based severity; each type of logging message has
32 | its own message. Here is a listing of the message types, and their respective
33 | method calls, ordered from lowest to highest priority:
34 |
35 | + The `Log.v()` method is used to log verbose messages.
36 | + The `Log.d()` method is used to log debug messages.
37 | + The `Log.i()` method is used to log informational messages.
38 | + The `Log.w()` method is used to log warnings.
39 | + The `Log.e()` method is used to log errors.
40 | + The `Log.wtf()` method is used to log events that should never happen
41 | ("wtf" being an abbreviation for "What a Terrible Failure", of course).
42 | You can think of this method as the equivalent of Java's `assert` method.
43 |
44 | One should _always_ consider a message's type when assigning log messages to
45 | one of the six method calls, as this will allow you to
46 | filter your logcat output
47 | when appropriate. It is also important to understand when it is acceptable to
48 | compile log messages into your application:
49 |
50 | + **Verbose logs should never be compiled into an application except during development.**
51 | When development is complete and you are ready to release your application to the world,
52 | you should remove all verbose method calls either by commenting them out, or using
53 | ProGuard to remove any verbose log statements directly from the bytecode of your
54 | compiled JAR executable, as described in Christopher's answer in this
55 | StackOverflow post.
56 | + **Debug logs** are compiled in but are ignored at runtime.
57 | + **Error**, **warning**, and **informational** logs are always kept.
58 |
59 | ### A Simple Pattern
60 |
61 | A simple way to organize debugging is with the sample pattern implemented
62 | below. A global, static string is given to represent the specific class
63 | (an Activity in this example, but it could be a service, an adapter,
64 | anything), and a boolean variable to represent whether or not log
65 | messages should be printed to the logcat.
66 |
67 | ```java
68 | public class SampleActivity extends Activity {
69 |
70 | /**
71 | * A string constant to use in calls to the "log" methods. Its
72 | * value is often given by the name of the class, as this will
73 | * allow you to easily determine where log methods are coming
74 | * from when you analyze your logcat output.
75 | */
76 | private static final String TAG = "SampleActivity";
77 |
78 | /**
79 | * Toggle this boolean constant's value to turn on/off logging
80 | * within the class.
81 | */
82 | private static final boolean VERBOSE = true;
83 |
84 | @Override
85 | public void onCreate(Bundle savedInstanceState) {
86 | super.onCreate(savedInstanceState);
87 | if (VERBOSE) Log.v(TAG, "+++ ON CREATE +++");
88 | }
89 |
90 | @Override
91 | public void onStart() {
92 | super.onStart();
93 | if (VERBOSE) Log.v(TAG, "++ ON START ++");
94 | }
95 |
96 | @Override
97 | public void onResume() {
98 | super.onResume();
99 | if (VERBOSE) Log.v(TAG, "+ ON RESUME +");
100 | }
101 | }
102 | ```
103 |
104 | Don't be afraid to be creative in how you print your log messages to the logcat!
105 | For instance, when the sample activity above is launched, the resulting logcat
106 | is presented in an nicely formatted and human-readable way:
107 |
108 | ```
109 | V SampleActivity +++ ON CREATE +++
110 | V SampleActivity ++ ON START++
111 | V SampleActivity + ON RESUME +
112 | ```
113 |
114 | ### Conclusion
115 |
116 | In this post, I have covered the basics in which Android debugging can (and
117 | should) be performed. In a future post, I will go into a bit more depth by
118 | providing some more advanced patterns that will give you more control over
119 | how debugging is performed at runtime.
120 |
121 | Leave a comment if this helped... it'll motivate me to write more of these
122 | blog posts in the future! :)
--------------------------------------------------------------------------------
/_posts/2012-06-04-ensuring-compatibility-with-utility-class.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: 'Ensuring Compatibility with a Utility Class'
4 | date: 2012-06-14
5 | permalink: /2012/06/compatability-manager-utility-class.html
6 | ---
7 | This post introduces the concept of a **utility class** and gives a simple
8 | example of how you can use one to tidy up your code. As Android projects grow in size, it
9 | becomes increasingly important that your code remains organized and well-structured.
10 | Providing a utility class for commonly called methods can help tremendously in reducing
11 | the complexity of your project, allowing you to structure your code in a readable and
12 | easily understandable way.
13 |
14 |
15 |
16 | Here's a simple example. Let's say you are building an Android application that frequently
17 | checks the device's SDK version code, to ensure backward compatibility. You'll need to
18 | use the constants provided in the `android.os.Build.VERSION_CODES` class,
19 | but these constants are long and can quickly clutter up your code. In this case,
20 | it might be a good idea to create a `CompatabilityUtil` utility class.
21 | A sample implementation is given below:
22 |
23 | ```java
24 | public class CompatibilityUtil {
25 |
26 | /** Get the current Android API level. */
27 | public static int getSdkVersion() {
28 | return Build.VERSION.SDK_INT;
29 | }
30 |
31 | /** Determine if the device is running API level 8 or higher. */
32 | public static boolean isFroyo() {
33 | return getSdkVersion() >= Build.VERSION_CODES.FROYO;
34 | }
35 |
36 | /** Determine if the device is running API level 11 or higher. */
37 | public static boolean isHoneycomb() {
38 | return getSdkVersion() >= Build.VERSION_CODES.HONEYCOMB;
39 | }
40 |
41 | /**
42 | * Determine if the device is a tablet (i.e. it has a large screen).
43 | *
44 | * @param context The calling context.
45 | */
46 | public static boolean isTablet(Context context) {
47 | return (context.getResources().getConfiguration().screenLayout
48 | & Configuration.SCREENLAYOUT_SIZE_MASK)
49 | >= Configuration.SCREENLAYOUT_SIZE_LARGE;
50 | }
51 |
52 | /**
53 | * Determine if the device is a HoneyComb tablet.
54 | *
55 | * @param context The calling context.
56 | */
57 | public static boolean isHoneycombTablet(Context context) {
58 | return isHoneycomb() && isTablet(context);
59 | }
60 |
61 | /** This class can't be instantiated. */
62 | private CompatibilityUtil() { }
63 | }
64 | ```
65 |
66 | Developers often create a separate package called `[package name].util` for
67 | frequently used utility classes. So for example, if your package name is `com.example.myapp`,
68 | then a nice place to put your utility classes would be in a separate package called
69 | `com.example.myapp.util`. However, remember that there's no need to _over-organize_
70 | your project. Creating a separate package might be a good idea for a larger project,
71 | but is completely unnecessary if your project contains only 5-10 classes. I might
72 | write a post about package/class organization in the future. For now, check out the
73 | (very well-designed) Google I/O 2011
74 | app's source code. You will learn a lot!
75 |
--------------------------------------------------------------------------------
/_posts/2012-06-13-designing-for-backwards-compatibility.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: 'Designing for Backwards Compatibility'
4 | date: 2012-06-13
5 | permalink: /2012/06/designing-for-backwards-compatibility.html
6 | ---
7 | > Note: please read this short post
8 | > before continuing forward.
9 |
10 | A common issue in Android development is backwards compatibility. How can we add cool
11 | new features from the most recent Android API while still ensuring that it runs
12 | correctly on devices running older versions of Android? This post discusses the
13 | problem by means of a simple example, and proposes a scalable, well-designed solution.
14 |
15 |
16 |
17 | ### The Problem
18 |
19 | Let's say we are writing an application that reads and writes pictures to new albums
20 | (i.e. folders) located on external storage, and that we want our application to support
21 | all devices running Donut (Android 1.6, SDK version 4) and above. Upon consulting the
22 | documentation,
23 | we realize there is a slight problem. With the introduction of Froyo (Android 2.2,
24 | SDK version 8) came a somewhat radical change in how external storage was laid out
25 | and represented on Android devices, as well as several new API methods (see
26 | android.os.Environment)
27 | that allow us access to the public storage directories. To ensure backwards compatibility
28 | all the way back to Donut, we must provide two separate implementations: one for older,
29 | pre-Froyo devices, and another for devices running Froyo and above.
30 |
31 | ### Setting up the Manifest
32 |
33 | Before we dive into the implementation, we will first update our `uses-sdk` tag in the Android
34 | manifest. There are two attributes we must set,
35 |
36 | + `android:minSdkVersion="4"`. This attribute defines a minimum API level required for
37 | the application to run. We want our application to run on devices running Donut and above,
38 | so we set its value to `"4"`.
39 |
40 | + `android:targetSdkVersion="15"`. This attribute is a little trickier to understand
41 | (and is incorrectly defined on blogs all over the internet). This attribute specifies
42 | the API level on which the application is designed to run. Preferably we would want
43 | its value to correspond to the most recently released SDK (`"15"`, at the time of this
44 | posting). Strictly speaking, however, its value should be given by the largest SDK
45 | version number that we have tested your application against (we will assume we have
46 | done so for the remainder of this example).
47 |
48 | The resulting tag in our manifest is as follows:
49 |
50 | ```
51 |
54 |
55 | ```
56 |
57 | ### Implementation
58 |
59 | Our implementation will consist of an abstract class and two subclasses that extend
60 | it. The abstract `AlbumStorageDirFactory` class enforces a simple contract by
61 | requiring its subclasses to implement the `getAlbumStorageDir` method. The actual
62 | implementation of this method depends on the device's SDK version number. Specifically,
63 | if we are using a device running Froyo or above, its implementation will make use of
64 | new methods introduced in API level 8. Otherwise, the correct directory must be
65 | determined using pre-Froyo method calls, to ensure that our app remains backwards compatible.
66 |
67 | ```java
68 | public abstract class AlbumStorageDirFactory {
69 |
70 | /**
71 | * Returns a File object that points to the folder that will store
72 | * the album's pictures.
73 | */
74 | public abstract File getAlbumStorageDir(String albumName);
75 |
76 | /**
77 | * A static factory method that returns a new AlbumStorageDirFactory
78 | * instance based on the current device's SDK version.
79 | */
80 | public static AlbumStorageDirFactory newInstance() {
81 | // Note: the CompatibilityUtil class is implemented
82 | // and discussed in a previous post, entitled
83 | // "Ensuring Compatibility with a Utility Class".
84 | if (CompatabilityUtil.isFroyo()) {
85 | return new FroyoAlbumDirFactory();
86 | } else {
87 | return new BaseAlbumDirFactory();
88 | }
89 | }
90 | }
91 | ```
92 |
93 | The two subclasses and their implementation are given below.The class also provides
94 | a static factory `newInstance` method (note that this method makes use of the
95 | `CompatabilityUtil` utility class, which was both implemented and discussed in a
96 | previous post).
97 | We discuss this method in detail in the next section.
98 |
99 | The `BaseAlbumDirFactory` subclass handles pre-Froyo SDK versions:
100 |
101 | ```java
102 | public class BaseAlbumDirFactory extends AlbumStorageDirFactory {
103 |
104 | /**
105 | * For pre-Froyo devices, we must provide the name of the photo directory
106 | * ourselves. We choose "/dcim/" as it is the widely considered to be the
107 | * standard storage location for digital camera files.
108 | */
109 | private static final String CAMERA_DIR = "/dcim/";
110 |
111 | @Override
112 | public File getAlbumStorageDir(String albumName) {
113 | return new File(Environment.getExternalStorageDirectory()
114 | + CAMERA_DIR + albumName);
115 | }
116 | }
117 | ```
118 |
119 | The `FroyoAlbumDirFactory` subclass handles Froyo and above:
120 |
121 | ```java
122 | public class FroyoAlbumDirFactory extends AlbumStorageDirFactory {
123 |
124 | @Override
125 | public File getAlbumStorageDir(String albumName) {
126 | return new File(Environment.getExternalStoragePublicDirectory(
127 | Environment.DIRECTORY_PICTURES), albumName);
128 | }
129 | }
130 | ```
131 |
132 | ### Making Sense of the Pattern
133 |
134 | Take a second to study the structure of the code above. Our implementation ensures
135 | compatibility with pre-Froyo devices through a simple design. To ensure compatibility,
136 | we simply request a new `AlbumStorageDirFactory` and call the abstract `getAlbumStorageDir`
137 | method. The subclass is determined and instantiated at runtime depending on the Android
138 | device's SDK version number. See the sample activity below for an example on how an ordinary
139 | Activity might use this pattern to retrieve an album's directory.
140 |
141 | ```java
142 | public class SampleActivity extends Activity {
143 |
144 | private AlbumStorageDirFactory mAlbumFactory;
145 |
146 | @Override
147 | public void onCreate(Bundle savedInstanceState) {
148 | super.onCreate(savedInstanceState);
149 |
150 | // Instantiate the AlbumStorageDirFactory. Instead of
151 | // invoking the subclass' default constructors directly,
152 | // we make use of the Abstract Factory design pattern,
153 | // which encapsulates the inner details. As a result, the
154 | // Activity does not need to know `anything` about the
155 | // compatibility-specific implementation--all of this is
156 | // done behind the scenes within the "mAlbumFactory" object.
157 | mAlbumFactory = AlbumStorageDirFactory.newInstance();
158 |
159 | // get the album's directory
160 | File sampleAlbumDir = getAlbumDir("sample_album");
161 | }
162 |
163 | /**
164 | * A simple helper method that returns a File corresponding
165 | * to the album named "albumName". The helper method invokes
166 | * the abstract "getAlbumStorageDir" method, which will return
167 | * correct location of the directory depending on the subclass
168 | * that was returned in "newInstance" (which depends entirely
169 | * on the device's SDK version number).
170 | */
171 | private File getAlbumDir(String albumName) {
172 | return mAlbumFactory.getAlbumStorageDir(albumName);
173 | }
174 | }
175 | ```
176 |
177 | There are a couple benefits to organizing the code the way we have:
178 |
179 | + **It's easily extendable.** While there is certainly no need to separate our
180 | implementations into classes for simple examples (such as the one discussed above),
181 | doing so is important when working with large, complicated projects, as it will ensure
182 | changes can quickly be made down the line.
183 | + **It encapsulates the implementation-specific details.** Abstracting these details
184 | from the client makes our code less cluttered and easier to read (note: in this case,
185 | "the client" was the person who wrote the Activity class).
186 |
187 | ### Conclusion
188 |
189 | Android developers constantly write code to ensure backwards compatibility. As projects
190 | expand and applications become more complex, it becomes increasingly important to ensure
191 | your implementation is properly designed. Hopefully this post helped and will encourage
192 | you to more elegant solutions in the future!
193 |
194 | Leave a comment if you have any questions or criticisms... or just to let me know that
195 | you managed to read through this entire post!
196 |
--------------------------------------------------------------------------------
/_posts/2012-06-18-why-ice-cream-sandwich-crashes-your-app.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: 'Why Ice Cream Sandwich Crashes your App'
4 | date: 2012-06-18
5 | permalink: /2012/06/app-force-close-honeycomb-ics.html
6 | related: ['/2013/08/fragment-transaction-commit-state-loss.html',
7 | '/2012/06/compatability-manager-utility-class.html',
8 | '/2013/01/inner-class-handler-memory-leak.html']
9 | ---
10 | The following question has plagued StackOverflow ever since Ice Cream
11 | Sandwich's initial release:
12 |
13 | > My application works fine on devices running Android 2.x, but
14 | > force closes on devices running Honeycomb (3.x) and Ice Cream
15 | > Sandwich (4.x). Why does this occur?
16 |
17 | This is a great question; after all, newer versions of Android are
18 | released with the expectation that old apps will remain compatible
19 | with new devices. In my experience, there are a couple reasons why
20 | this might occur. Most of the time, however, the reason is simple:
21 | _you are performing a potentially expensive operation on the UI
22 | thread_.
23 |
24 |
25 |
26 | ### What is the UI Thread?
27 |
28 | The concept and importance of the application's **main UI thread**
29 | is something every Android developer should understand. Each time an
30 | application is launched, the system creates a thread called "main"
31 | for the application. The main thread (also known as the "UI thread")
32 | is in charge of dispatching events to the appropriate views/widgets
33 | and thus is very important. It's also the thread where your application
34 | interacts with running components of your application's UI. For instance,
35 | if you touch a button on the screen, the UI thread dispatches the touch
36 | event to the view, which then sets its pressed state and posts an invalidate
37 | request to the event queue. The UI thread dequeues this request and then
38 | tells the view to redraw itself.
39 |
40 | This single-thread model can yield poor performance unless Android
41 | applications are implemented properly. Specifically, if the UI thread
42 | was in charge of running everything in your entire application,
43 | performing long operations such as network access or database queries
44 | on the UI thread would block the entire user interface. No event would
45 | be able to be dispatched—including drawing and touchscreen
46 | events—while the long operation is underway. From the user's
47 | perspective, the application will appear to be frozen.
48 |
49 | In these situations, instant feedback is vital. Studies show that
50 | **0.1 seconds** is about the limit for having the user feel that
51 | the system is reacting instantaneously. Anything slower than this
52 | limit will probably be considered as **lag**
53 | (Miller 1968; Card et al. 1991).
54 | While a fraction of a second might not seem harmful, even a tenth
55 | of a second can be the difference between a good review and a bad
56 | review on Google Play. Even worse, if the UI thread is blocked
57 | for more than about five seconds, the user is presented with the
58 | notorious "application not responding" (ANR) dialog and the app is
59 | force closed.
60 |
61 | ### Why Android Crashes Your App
62 |
63 | The reason why your application crashes on Android versions 3.0 and above,
64 | but works fine on Android 2.x is because **Honeycomb and Ice Cream Sandwich
65 | are much stricter about abuse against the UI Thread**. For example, when
66 | an Android device running HoneyComb or above detects a network access on
67 | the UI thread, a `NetworkOnMainThreadException` will be thrown:
68 |
69 | ```
70 | E/AndroidRuntime(673): java.lang.RuntimeException: Unable to start activity
71 | ComponentInfo{com.example/com.example.ExampleActivity}: android.os.NetworkOnMainThreadException
72 | ```
73 |
74 | The explanation as to why this occurs is well documented on the Android
75 | developer's site:
76 |
77 | > A `NetworkOnMainThreadException` is thrown when an application
78 | > attempts to perform a networking operation on its main thread. This is
79 | > only thrown for applications targeting the Honeycomb SDK or higher.
80 | > Applications targeting earlier SDK versions are allowed to do networking
81 | > on their main event loop threads, but it's heavily discouraged.
82 |
83 | Some examples of other operations that ICS and Honeycomb _won't_ allow
84 | you to perform on the UI thread are:
85 |
86 | + Opening a `Socket` connection (i.e. `new Socket()`).
87 | + HTTP requests (i.e. `HTTPClient` and `HTTPUrlConnection`).
88 | + Attempting to connect to a remote MySQL database.
89 | + Downloading a file (i.e. `Downloader.downloadFile()`).
90 |
91 | If you are attempting to perform any of these operations on the UI thread, you
92 | _must_ wrap them in a worker thread. The easiest way to do this is to use
93 | of an `AsyncTask`, which allows you to perform asynchronous work on
94 | your user interface. An `AsyncTask` will perform the blocking operations
95 | in a worker thread and will publish the results on the UI thread, without
96 | requiring you to handle threads and/or handlers yourself.
97 |
98 | ### Conclusion
99 |
100 | The reason why I decided to write about this topic is because I have seen it
101 | come up on StackOverflow and other forums countless times. The majority of
102 | the time the error stems from placing expensive operations directly on the UI
103 | thread. To ensure you don't disrupt the user experience, it is very important
104 | to execute Socket connections, HTTP requests, file downloads, and other
105 | long-term operations on a separate Thread. The easiest way to do this is
106 | to wrap your operation in an AsyncTask, which launches a new thread and
107 | allows you to perform asynchronous work on your user interface.
108 |
109 | As always, let me know if this was helpful by +1-ing the post or leaving a
110 | comment below! Feel free to ask questions too... I respond to them quickly. :)
111 |
112 | ### Helpful Links
113 |
114 | Here are some helpful links that might help you get started with `AsyncTask`s:
115 |
116 | + `AsyncTask` documentation
117 | + Multithreading For Performance
118 |
--------------------------------------------------------------------------------
/_posts/2012-06-25-content-providers-and-content-resolvers.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: 'Content Providers & Content Resolvers'
4 | date: 2012-06-25
5 | permalink: /2012/06/content-resolvers-and-content-providers.html
6 | ---
7 | Content Providers and Content Resolvers are a common source of confusion for beginning
8 | Android developers. Further, online tutorials and sample code are not sufficient in
9 | describing how the two classes work together to provide access to the Android data
10 | model. This post hopes to fill in this gap by explaining their place in the
11 | `android.content` package. It concludes with a walk through the life of a
12 | simple query to the Content Resolver.
13 |
14 |
15 |
16 | ### The `android.content` Package
17 |
18 | The `android.content`
19 | package contains classes for accessing and publishing data. The Android framework
20 | enforces a **robust** and **secure** data sharing model. Applications are _not_
21 | allowed direct access to other application's internal data. Two classes in the
22 | package help enforce this requirement: the `ContentResolver` and the `ContentProvider`.
23 |
24 | ### What is the Content Resolver?
25 |
26 | The Content Resolver is the single, global instance in your application that provides
27 | access to your (and other applications') content providers. The Content Resolver
28 | behaves exactly as its name implies: it accepts requests from clients, and _resolves_
29 | these requests by directing them to the content provider with a distinct authority.
30 | To do this, the Content Resolver stores a mapping from authorities to Content Providers.
31 | This design is important, as it allows a simple and secure means of accessing other
32 | applications' Content Providers.
33 |
34 | The Content Resolver includes the CRUD (create, read, update, delete) methods corresponding
35 | to the abstract methods (insert, query, update, delete) in the Content Provider class.
36 | The Content Resolver does not know the implementation of the Content Providers it is
37 | interacting with (nor does it need to know); each method is passed an URI that specifies
38 | the Content Provider to interact with.
39 |
40 | ### What is a Content Provider?
41 |
42 | Whereas the Content Resolver provides an abstraction from the application's Content Providers,
43 | Content Providers provide an abstraction from the underlying data source
44 | (i.e. a SQLite database). They provide mechanisms for defining data security (i.e. by
45 | enforcing read/write permissions) and offer a standard interface that connects data
46 | in one process with code running in another process.
47 |
48 | Content Providers provide an interface for publishing and consuming data, based around a
49 | simple URI addressing model using the `content://` schema. They enable you to decouple
50 | your application layers from the underlying data layers, making your application
51 | data-source agnostic by abstracting the underlying data source.
52 |
53 | ### The Life of a Query
54 |
55 | So what exactly is the step-by-step process behind a simple query? As described above,
56 | when you query data from your database via the content provider, you don't communicate
57 | with the provider directly. Instead, you use the Content Resolver object to communicate
58 | with the provider. The specific sequence of events that occurs when a query is made
59 | is given below:
60 |
61 | 1. A call to `getContentResolver().query(Uri, String, String, String, String)` is made.
62 | The call invokes the Content Resolver's `query` method, _not_ the `ContentProvider`'s.
63 | 2. When the `query` method is invoked, the Content Resolver parses the `uri` argument
64 | and extracts its authority.
65 | 3. The Content Resolver directs the request to the content provider registered with the
66 | (unique) authority. This is done by calling the Content Provider's `query` method.
67 | 4. When the Content Provider's `query` method is invoked, the query is performed and
68 | a Cursor is returned (or an exception is thrown). The resulting behavior depends
69 | entirely on the Content Provider's implementation.
70 |
71 | ### Conclusion
72 |
73 | An integral part of the
74 | `android.content`
75 | package, the `ContentResolver` and `ContentProvider` classes work together to
76 | ensure secure access to other applications' data. Understanding how the underlying
77 | system works becomes second nature once you've written enough Android code, but I
78 | hope that someone finds this explanation helpful some day.
79 |
80 | Let me know if you have any questions about the process!
81 |
--------------------------------------------------------------------------------
/_posts/2012-08-07-exit-application-dialogs-are-evil.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: "'Exit Application?' Dialogs Are Evil, Don't Use Them!"
4 | date: 2012-08-07
5 | permalink: /2012/08/exit-application-dialogs-are-evil-dont.html
6 | ---
7 | Here's a question that is worth thinking about:
8 |
9 | > Should I implement an "Exit application?" dialog in my app?
10 |
11 | In my experience, the answer is almost always **no**. Consider the official Flickr app,
12 | as an example. At the main screen, the user clicks the back button and is immediately
13 | prompted with a dialog, questioning whether or not the user wishes to exit the application:
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
(a) Back button pressed.
29 |
(b) "Exit Flickr?"
30 |
31 |
32 |
33 |
34 | So what went wrong? Well, pretty much everything, at least in my opinion.
35 | Here are the three major flaws I see in Flickr's decision to include the dialog:
36 |
37 | 1. **It slows down the user experience.** An additional click is required to leave the application.
38 | Sure, it doesn't seem like much... but zero clicks is always better than one. Including the
39 | dialog will annoy the occasional meticulous power user and will make it much more likely
40 | that people like me will write-up angry rants about it online. To make matters worse, Flickr's
41 | dialog incorrectly positions the "OK" and "Cancel" buttons, which as of Android 4.0, should be
42 | positioned on the right and left respectively. This is also not a _huge_ deal, but it forces
43 | users to think more than they should need to, and the simple action of exiting the application is
44 | no longer seamless as a result.
45 |
46 | 2. **It is inconsistent.** Name one native Android application that warns the user when they are
47 | about to exit the application. If you can't, that's because there are none. Of all the familiar,
48 | Google-made Android apps (Gmail, Google Drive, etc.), exactly _none_ of them exhibit this
49 | behavior. The user expects the back button to bring him or her back to the top activity on the
50 | Activity Stack; there is no reason why it shouldn't do otherwise in this simple situation.
51 |
52 | 3. **It serves absolutely no purpose.** What baffles me the most, however, is that there is no
53 | reason to confirm exit in the first place. _Maybe_ the dialog would be OK if there was a
54 | long-running operation running in the background that is specific to the Activity (i.e. an
55 | `AsyncTask` that the user might not want canceled). A dialog _might_ also
56 | make sense if the application took a long time to load, for example, a fancy, video intensive FPS like
57 | Dead Trigger.
58 | In Flickr's case, there is no acceptable reason why the user shouldn't be allowed to "back-out" of
59 | the application immediately.
60 |
61 | In my opinion, dialogs are both slow and annoying, and should be used as little as possible.
62 | Always prefer the faster "edit in place" user model (as described
63 | here)
64 | when it comes to saving persistent state, and never prompt the user when they wish to "back-out" of the
65 | application unless you have a _very_ good reason for doing so.
66 |
67 | As always, let me know if you agree or disagree in the comments below!
68 |
69 | **EDIT:** For more discussion on this topic, I recommend reading through the content/comments
70 | of this Google+ post (made by
71 | +Cyril Mottier,
72 | a very talented Android developer recognized by Google as a
73 | Android Developer Expert).
--------------------------------------------------------------------------------
/_posts/2012-08-26-follow-this-blog-on-google-currents.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: 'Follow This Blog On Google Currents!'
4 | date: 2012-08-26
5 | permalink: /2012/08/follow-this-blog-on-google-currents_8022.html
6 | ---
7 |
8 | Hi all,
9 |
10 | I've recently made this blog available on Google Currents! Install the application and
11 | subscribe by clicking [this link](https://www.google.com/producer/editions/CAow5Ir3AQ/android_design_patterns).
12 |
13 | If you have never used Google Currents, I strongly recommend that you try it out. It's a
14 | really great way to keep up with the latest news, blogs, and your favorite Google+ streams,
15 | and it works seamlessly offline (which I've found is great for long plane rides). If you're
16 | a long time Flipboard user, I recommend you give it a try as well... in my opinion, Currents
17 | is easier to navigate and feels much more like a native Android application. That said,
18 | I do tend to be a bit biased towards the native Google apps. :P
19 |
20 |
21 |
22 | As always, don't hesitate to leave a comment if you find a bug or have any suggestions on
23 | how I can improve the edition! I'm going to try really hard to keep it up-to-date for those
24 | of you who follow this blog and can't get enough of Google Currents!
25 |
26 | Cheers,
27 | Alex
--------------------------------------------------------------------------------
/_posts/2012-09-16-loaders-part4.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: 'Tutorial: AppListLoader (part 4)'
4 | date: 2012-09-16
5 | permalink: /2012/09/tutorial-loader-loadermanager.html
6 | related: ['/2012/07/loaders-and-loadermanager-background.html',
7 | '/2012/07/understanding-loadermanager.html',
8 | '/2012/08/implementing-loaders.html']
9 | ---
10 | This will be my fourth and final post on Loaders and the LoaderManager. Let me know in the comments if they have been helpful!
11 | Links to my previous Loader-related posts are given below:
12 |
13 | + **Part 1:** Life Before Loaders
14 | + **Part 2:** Understanding the LoaderManager
15 | + **Part 3:** Implementing Loaders
16 | + **Part 4:** Tutorial: AppListLoader
17 |
18 | Due to public demand, I've written a sample application that illustrates how to correctly implement a custom Loader.
19 | The application is named AppListLoader,
20 | and it is a simple demo application that queries and lists all installed applications on your Android device.
21 | The application is a modified, re-thought (and bug-free) extension of the
22 | LoaderCustom.java
23 | sample that is provided in the API Demos. The application uses an `AppListLoader`
24 | (a subclass of `AsyncTaskLoader`) to query its data, and the LoaderManager to
25 | manage the Loader across the Activity/Fragment lifecycle:
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | The AppListLoader registers two `BroadcastReceiver`s which observe/listen for system-wide broadcasts that
34 | impact the underlying data source. The `InstalledAppsObserver` listens for newly installed, updated, or
35 | removed applications, and the `SystemLocaleObserver` listens for locale changes. For example, if the user
36 | changes the language from English to Spanish, the `SystemLocaleObserver` will notify the AppListLoader to
37 | re-query its data so that the application can display each application's name in Spanish (assuming an alternate
38 | Spanish name has been provided). Click "Change language" in the options menu and watch the Loader's seamless
39 | reaction to the event (it's awesome, isn't it? :P).
40 |
41 | Log messages are written to the logcat whenever an important Loader/LoaderManager-related event occurs, so be
42 | sure to run the application while analyzing the logcat! Hopefully it'll give you a better understanding of how
43 | Loaders work in conjunction with the LoaderManager and the Activity/Fragment lifecycle. Be sure to filter the
44 | logcat by application name ("com.adp.loadercustom") for the best results!
45 |
46 |
47 |
48 |
49 |
50 | You can download the application from Google Play by clicking the badge below:
51 |
52 |
53 |
54 |
55 |
56 | The source code is available on GitHub.
57 | An excessive amount of comments flesh out the entire application-Loader workflow. Download it,
58 | import it as an eclipse project, and modify it all you want!
59 |
60 | Let me know if these posts have been helpful by leaving a comment below! As always,
61 | don't hesitate to ask questions either!
62 |
--------------------------------------------------------------------------------
/_posts/2012-10-11-sqlite-content-providers-thread-safety.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: 'SQLite, Content Providers, & Thread Safety'
4 | date: 2012-10-11
5 | permalink: /2012/10/sqlite-contentprovider-thread-safety.html
6 | related: ['/2012/05/correctly-managing-your-sqlite-database.html',
7 | '/2012/06/content-resolvers-and-content-providers.html',
8 | '/2012/07/understanding-loadermanager.html']
9 | ---
10 | A common source of confusion when implementing `ContentProvider`s is that of thread-safety.
11 | We all know that any potentially expensive query should be asynchronous so as not to block
12 | the UI thread, but when, if ever, is it OK to make calls to the `ContentProvider` from
13 | multiple threads?
14 |
15 |
16 |
17 | ### Threads and Content Providers
18 |
19 | The documentation
20 | on ContentProviders warns that its methods may be called from multiple threads and therefore
21 | must be thread-safe:
22 |
23 | > Data access methods (such as `insert(Uri, ContentValues)` and
24 | > `update(Uri, ContentValues, String, String[]))` may be called from many
25 | > threads at once, and must be thread-safe.
26 |
27 | In other words, Android **does not** synchronize access to the ContentProvider for you.
28 | If two calls to the same method are made simultaneously from separate threads, neither
29 | call will wait for the other. Requiring the client to deal with concurrency themselves
30 | makes sense from a framework developer's point of view. The abstract `ContentProvider` class
31 | cannot assume that its subclasses will require synchronization, as doing so would be
32 | horribly inefficient.
33 |
34 | ### Ensuring Thread Safety
35 |
36 | So now that we know that the ContentProvider is not thread safe, what do we need to
37 | do in order to eliminate potential race conditions? Just make every method
38 | `synchronized`, right?
39 |
40 | Well... no, not necessarily. Consider a ContentProvider that uses a `SQLiteDatabase`
41 | as its backing data source. As per the
42 | documentation,
43 | access to the `SQLiteDatabase` is synchronized by default, thus guaranteeing that
44 | no two threads will ever touch it at the same time. In this case, synchronizing
45 | each of the ContentProvider's methods is both unnecessary and costly. Remember
46 | that a `ContentProvider` serves as a wrapper around the underlying data source;
47 | whether or not you must take extra measures to ensure thread safety often depends
48 | on the data source itself.
49 |
50 | ### Conclusion
51 |
52 | Although the ContentProvider lacks in thread-safety, often times you will find that
53 | no further action is required on your part with respect to preventing potential
54 | race conditions. The canonical example is when your ContentProvider is backed by
55 | a `SQLiteDatabase`; when two threads attempt to write to the database at the same
56 | time, the `SQLiteDatabase` will lock itself down, ensuring that one will wait until
57 | the other has completed. Each thread will be given mutually exclusive access to the
58 | data source, ensuring the thread safety is met.
59 |
60 | This has been a rather short post, so don't hesitate to leave a comment if you have
61 | any clarifying questions. Don't forget to +1 this post below if you found it helpful!
--------------------------------------------------------------------------------
/_posts/2013-01-12-use-go-to-implement-android-backends.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: 'Use Go to Implement your Android Backends'
4 | date: 2013-01-12
5 | permalink: /2013/01/gcm-appengine-golang-android-backends.html
6 | ---
7 | A couple weeks ago I wrote a library
8 | that simplifies the interaction between Go-based application servers and Google Cloud
9 | Messaging servers. I plan on covering GCM (both the application-side and server-side
10 | aspects) in more detail in a future blog post, but for now I will just leave a link
11 | to the library to encourage more people to write their GCM application servers using
12 | the Go Programming Language
13 | (Google App Engine,
14 | hint hint).
15 |
16 | _...but why Go?_
17 |
18 | I'm glad you asked. There are several reasons:
19 |
20 |
21 |
22 | + Go is modern. Programming languages like C, C++, and Java
23 | are old, designed before the advent of multicore machines, networking, and web
24 | application development. Go was designed to be suitable for writing large Google
25 | programs such as web servers.
26 |
27 | + Go is concise, yet familiar. Tasks that require 40+ lines of code
28 | in Java (i.e. setting up HTTP servers and parsing JSON responses) can be done in 1 or 2
29 | lines. Go significantly reduces the amount of work required to write simple programs,
30 | and yet the language's syntax is not too radical, still resembling the most common
31 | procedural languages.
32 |
33 | + Go is easy to learn. Learn the language in a day:
34 | A Tour of Go and
35 | Effective Go.
36 |
37 | + Go was invented at Google. Enough said. :)
38 |
39 | That's all for now... but expect a lot more on GCM, Google App Engine, and Golang
40 | later! The comments are open as always, and don't forget to +1 this post!
41 |
42 | ### Links
43 |
44 | + Google Cloud Messaging for Go
45 | + Google App Engine
46 | + A Tour of Go
47 | + Effective Go
48 | + golang.org
49 |
--------------------------------------------------------------------------------
/_posts/2013-01-14-how-to-leak-a-context-handlers-inner-classes.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: 'How to Leak a Context: Handlers & Inner Classes'
4 | date: 2013-01-14
5 | permalink: /2013/01/inner-class-handler-memory-leak.html
6 | updated: '2014-12-12'
7 | related: ['/2012/07/understanding-loadermanager.html',
8 | '/2013/04/activitys-threads-memory-leaks.html',
9 | '/2013/04/retaining-objects-across-config-changes.html']
10 | ---
11 | Consider the following code:
12 |
13 | ```java
14 | public class SampleActivity extends Activity {
15 |
16 | private final Handler mLeakyHandler = new Handler() {
17 | @Override
18 | public void handleMessage(Message msg) {
19 | // ...
20 | }
21 | };
22 | }
23 | ```
24 |
25 | While not readily obvious, this code can cause cause a massive memory leak.
26 | Android Lint will give the following warning:
27 |
28 | > In Android, Handler classes should be static or leaks might occur.
29 |
30 | But where exactly is the leak and how might it happen? Let's determine the
31 | source of the problem by first documenting what we know:
32 |
33 |
34 |
35 | 1. When an Android application first starts, the framework creates a
36 | `Looper`
37 | object for the application's main thread. A `Looper` implements a simple message queue,
38 | processing `Message`
39 | objects in a loop one after another. All major application framework events (such
40 | as Activity lifecycle method calls, button clicks, etc.) are contained inside
41 | `Message` objects, which are added to the `Looper`'s message queue and are processed
42 | one-by-one. The main thread's `Looper` exists throughout the application's lifecycle.
43 |
44 | 2. When a `Handler`
45 | is instantiated on the main thread, it is associated with the `Looper`'s message queue.
46 | Messages posted to the message queue will hold a reference to the `Handler` so that the
47 | framework can call
48 | `Handler#handleMessage(Message)`
49 | when the `Looper` eventually processes the message.
50 |
51 | 3. In Java, non-static inner and anonymous classes hold an implicit reference to their
52 | outer class. Static inner classes, on the other hand, do not.
53 |
54 | So where exactly is the memory leak? It's very subtle, but consider the following code as an example:
55 |
56 | ```java
57 | public class SampleActivity extends Activity {
58 |
59 | private final Handler mLeakyHandler = new Handler() {
60 | @Override
61 | public void handleMessage(Message msg) {
62 | // ...
63 | }
64 | };
65 |
66 | @Override
67 | protected void onCreate(Bundle savedInstanceState) {
68 | super.onCreate(savedInstanceState);
69 |
70 | // Post a message and delay its execution for 10 minutes.
71 | mLeakyHandler.postDelayed(new Runnable() {
72 | @Override
73 | public void run() { /* ... */ }
74 | }, 1000 * 60 * 10);
75 |
76 | // Go back to the previous Activity.
77 | finish();
78 | }
79 | }
80 | ```
81 |
82 | When the activity is finished, the delayed message will continue to live in the main thread's
83 | message queue for 10 minutes before it is processed. The message holds a reference to the
84 | activity's `Handler`, and the `Handler` holds an implicit reference to its outer class (the
85 | `SampleActivity`, in this case). This reference will persist until the message is processed,
86 | thus preventing the activity context from being garbage collected and leaking all of the
87 | application's resources. Note that the same is true with the anonymous Runnable class on
88 | line 15. Non-static instances of anonymous classes hold an implicit reference to their outer
89 | class, so the context will be leaked.
90 |
91 | To fix the problem, subclass the `Handler` in a new file or use a static inner class instead.
92 | Static inner classes do not hold an implicit reference to their outer class, so the activity
93 | will not be leaked. If you need to invoke the outer activity's methods from within the
94 | `Handler`, have the Handler hold a `WeakReference` to the activity so you don't accidentally
95 | leak a context. To fix the memory leak that occurs when we instantiate the anonymous Runnable
96 | class, we make the variable a static field of the class (since static instances of anonymous
97 | classes do not hold an implicit reference to their outer class):
98 |
99 | ```java
100 | public class SampleActivity extends Activity {
101 |
102 | /**
103 | * Instances of static inner classes do not hold an implicit
104 | * reference to their outer class.
105 | */
106 | private static class MyHandler extends Handler {
107 | private final WeakReference mActivity;
108 |
109 | public MyHandler(SampleActivity activity) {
110 | mActivity = new WeakReference(activity);
111 | }
112 |
113 | @Override
114 | public void handleMessage(Message msg) {
115 | SampleActivity activity = mActivity.get();
116 | if (activity != null) {
117 | // ...
118 | }
119 | }
120 | }
121 |
122 | private final MyHandler mHandler = new MyHandler(this);
123 |
124 | /**
125 | * Instances of anonymous classes do not hold an implicit
126 | * reference to their outer class when they are "static".
127 | */
128 | private static final Runnable sRunnable = new Runnable() {
129 | @Override
130 | public void run() { /* ... */ }
131 | };
132 |
133 | @Override
134 | protected void onCreate(Bundle savedInstanceState) {
135 | super.onCreate(savedInstanceState);
136 |
137 | // Post a message and delay its execution for 10 minutes.
138 | mHandler.postDelayed(sRunnable, 1000 * 60 * 10);
139 |
140 | // Go back to the previous Activity.
141 | finish();
142 | }
143 | }
144 | ```
145 |
146 |
147 | The difference between static and non-static inner classes is subtle, but is something
148 | every Android developer should understand. What's the bottom line? **Avoid using non-static
149 | inner classes in an activity if instances of the inner class could outlive the activity's
150 | lifecycle.** Instead, prefer static inner classes and hold a weak reference to the activity inside.
151 |
152 | As always, leave a comment if you have any questions and don't forget to +1 this blog in
153 | the top right corner! :)
154 |
--------------------------------------------------------------------------------
/_posts/2014-01-08-redesigning-android-design-patterns.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: Redesigning Android Design Patterns
4 | thumbnails: ['/assets/images/posts/2014/01/08/adp-n7-screenshot-after.png']
5 | related: ['/2013/07/binders-window-tokens.html',
6 | '/2012/06/app-force-close-honeycomb-ics.html',
7 | '/2012/08/exit-application-dialogs-are-evil-dont.html']
8 | updated: '2014-03-11'
9 | ---
10 | A couple weeks ago, I began the ambitious task of rewriting this blog from scratch.
11 | Today, I'm happy to introduce a brand new look: one that is _cleaner_, _faster_, and more
12 | _responsive_.
13 |
14 | Several of the major changes are listed below. If this is your first time visiting this blog, you can find the old
15 | version of the site [here](http://androiddesignpatterns.blogspot.com) to use as a reference.
16 |
17 |
18 |
19 | + **Goodbye Blogger, hello Jekyll.** I've never been a huge fan of Blogger and was eager to
20 | try something new. After a bit of research I decided to give [Jekyll](http://jekyllrb.com/)
21 | a shot. Unlike Blogger,
22 | which dynamically parses content and templates on each request, Jekyll generates the entire
23 | website once beforehand to serve statically and is much more efficient as a result. It's a bit
24 | under-documented and I'm not a huge fan of [Liquid](https://github.com/Shopify/liquid)
25 | (the templating language Jekyll uses to process templates), but other than that I have no complaints.
26 | I'd take Jekyll over Blogger any day.
27 |
28 | + **100% open-source.** The source code powering this blog can
29 | be found on [GitHub](https://github.com/alexjlockwood/alexjlockwood.github.io), and may be used
30 | by others as the basis of their own blogging templates under the
31 | [MIT license](https://github.com/alexjlockwood/alexjlockwood.github.io/blob/master/README.md#license-and-copyright)
32 | (with the exception of the contents of the actual posts, of course :P).
33 | Given that Android Design Patterns wouldn't even exist without Android—one of the largest open-source
34 | projects in the world—making this blog 100% open-source seemed fitting. Another cool implication of an entirely
35 | open-source blog is that readers can propose corrections themselves by submitting pull requests
36 | to GitHub.
37 |
38 | + **Faster page load times.** Check out the [old version](http://androiddesignpatterns.blogspot.com) of this blog
39 | and see for yourself! [Page Speed](https://developers.google.com/speed/pagespeed/) reports an increase from 65/100 to 89/100 for mobile
40 | devices and 86/100 to 95/100 for desktop computers.
41 |
42 | + **Clean, responsive, and mobile-friendly.** First of all, I'd like to thank [+Shannon Lee](https://plus.google.com/116871425473751000037)
43 | for coming up with most of the new design. I consider myself a beginner at web design, so this couldn't have been done without her!
44 | That said, I definitely recommend checking out the site on your phone or tablet, as it's one of my favorite
45 | aspects of the new design. Below is a comparison of the old vs. new versions of the site on a Nexus 7:
46 |
47 |
55 |
56 | + **Disqus comments.** Picking a third-party commenting platform to use was difficult, as there weren't
57 | many options to choose from. I ended up choosing [Disqus](http://disqus.com/), as it was one of the few commenting systems that I could find
58 | that would correctly and reliably import my old comments from Blogger (spam detection is also a plus). One of the consequences of
59 | the migration, however, is that all old threaded comments are now unthreaded, meaning that most of the old
60 | comments are a bit of a mess right now. I plan on manually cleaning up these at some point in
61 | the future. Going forward, all new comments will thread normally.
62 |
63 | Let me know what you think of the new design in the comments below! Make sure to also leave any
64 | suggestions, criticisms, or feature requests too. The design will continue to be refined over time until
65 | it's perfect. :)
66 |
--------------------------------------------------------------------------------
/_posts/2014-01-13-thread-scheduling-in-android.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: Thread Scheduling in Android
4 | related: ['/2013/04/activitys-threads-memory-leaks.html',
5 | '/2012/10/sqlite-contentprovider-thread-safety.html',
6 | '/2013/07/binders-window-tokens.html']
7 | ---
8 | This post will give an overview of how thread scheduling works in Android, and will briefly
9 | demonstrate how to explicitly set
10 | [thread priorities](http://developer.android.com/reference/android/os/Process.html)
11 | yourself to ensure that your application remains responsive even as multiple threads
12 | run in the background.
13 |
14 | For those who are unfamiliar with the term, a _thread scheduler_ is the part of the operating system
15 | in charge of deciding which threads in the system should run, when, and for how long. Android's thread
16 | scheduler uses two main factors to determine how threads are scheduled across the entire
17 | system: _nice values_ and _cgroups_.
18 |
19 |
20 |
21 | ### Nice values
22 |
23 | Similar to how they are used in Linux's completely fair scheduling policy, _nice values_ in Android
24 | are used as a measure of a thread's priority. Threads with a higher nice value (i.e., lower priority,
25 | as in they are being "nice" to other threads in the system) will run less often than
26 | those with lower nice values (i.e., higher priority). The two most important of these are the
27 | [default](http://developer.android.com/reference/android/os/Process.html#THREAD_PRIORITY_DEFAULT)
28 | and [background](http://developer.android.com/reference/android/os/Process.html#THREAD_PRIORITY_BACKGROUND)
29 | thread priorities. Intuitively, thread priorities should be chosen
30 | inverse-proportionally to the amount of work the thread is expected to do: the more work the
31 | thread will do, the less favorable thread priority it should get so that it doesn't
32 | starve the system. For this reason, user interface threads (such as the main thread of a foreground `Activity`)
33 | are typically given a default priority, whereas background threads (such as a thread executing an `AsyncTask`)
34 | are typically given a background priority.
35 |
36 | Nice values are theoretically important because they help reduce background work that might otherwise
37 | interrupt the user interface. In practice, however, they alone are not sufficient. For example, consider
38 | twenty background threads and a single foreground thread driving the UI. Despite their low
39 | individual priorities, collectively the twenty background threads will still likely impact the performance
40 | of the single foreground thread, resulting in lag and hurting the user experience. Since at any given moment
41 | several applications could potentially have background threads waiting to run, the Android OS
42 | must somehow address these scenarios. Enter _cgroups_.
43 |
44 | ### Cgroups
45 |
46 | To address this problem, Android enforces an even stricter foreground vs. background scheduling policy
47 | using Linux [_cgroups_](http://en.wikipedia.org/wiki/Cgroups) (control groups). Threads with
48 | background priorities are implicitly moved into a background cgroup, where they are
49 | limited to only a small percentage1 of the available
50 | CPU if threads in other groups are busy. This separation allows background threads to make some
51 | forward progress, without having enough of an impact on the foreground threads to be visible
52 | to the user.
53 |
54 | In addition to automatically assigning low-priority threads to the background cgroup, Android ensures that all
55 | threads belonging to applications not currently running in the foreground are implicitly moved to the background cgroup as well. This automatic assignment of application threads to cgroups ensures that the current foreground
56 | application thread will always be the priority, regardless of how many applications are running in the background.
57 |
58 | ### Setting Priorities with `Process#setThreadPriority(int)`
59 |
60 | For the most part, the Android APIs already assign worker threads a background priority for you
61 | (for example, see the source code for
62 | [`HandlerThread`](https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/os/HandlerThread.java)
63 | and [`AsyncTask`](https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/os/AsyncTask.java)). It is important to remember, however, that this will not always be the case.
64 | `Thread`s and `ExecutorService`s that are instantiated on the main UI thread, for example,
65 | will inherit a default, foreground priority, making lag more likely and possibly hurting
66 | the application's performance. In these cases, you should _always_ remember to set the thread's
67 | priority by calling
68 | `Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)`
69 | before the `Thread` is run. Doing so is straightforward, as shown in the example below:
70 |
71 | ```java
72 | new Thread(new Runnable() {
73 | @Override
74 | public void run() {
75 | Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
76 |
77 | // ...
78 | }
79 | }).start();
80 | ```
81 |
82 | As always, thanks for reading, and leave a comment if you have any questions. Don't forget to +1 this blog post too!
83 |
84 |
85 |
86 | 1 This percentage was 5% at the time of this writing, though it is possible that this value could change in the future. As of Android 4.4.2, cgroup mount points are created and initialized at boot-up in [`/system/core/rootdir/init.rc`](https://android.googlesource.com/platform/system/core/+/android-sdk-4.4.2_r1/rootdir/init.rc) (see lines 100-123). ↩
--------------------------------------------------------------------------------
/_posts/2018-11-13-android-studio-svg-to-vector-cli.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: "How to use Android Studio's SVG-to-VectorDrawable converter from the command line"
4 | date: 2018-11-13
5 | permalink: /2018/11/android-studio-svg-to-vector-cli.html
6 | related: ['/2013/08/fragment-transaction-commit-state-loss.html',
7 | '/2016/11/introduction-to-icon-animation-techniques.html',
8 | '/2016/08/contextcompat-getcolor-getdrawable.html']
9 | ---
10 |
11 |
12 |
13 | Since the very beginning, one of the most annoying aspects of using `VectorDrawable`s on Android has been the lack of a reliable SVG converter. Google has recently made huge strides towards improving Android Studio's SVG-to-`VectorDrawable` tool in order to improve this experience.
14 |
15 | However, there has always been one major issue for me: the tool doesn't support batch conversion of SVGs and can't be invoked from the command line. Working at Lyft, it's not uncommon for me to need to convert hundreds of SVGs into `VectorDrawable`s at a time. Having to go through Android Studio's GUI in order to convert each SVG one-by-one is simply not realistic.
16 |
17 |
18 |
19 | Well, this weekend my good buddy [Nick Butcher](https://twitter.com/crafty) taught me how to build the tool as a binary that can be executed from the command line, and I'm so excited about it that I had to share it with the world! :)
20 |
21 | ## Where can I download it?
22 |
23 | I anticipate many won't want to go through the trouble of building these binaries from scratch, so I built them myself and hosted them on [Google Drive here](https://j.mp/svg-to-vector-google-drive).
24 |
25 | ## How do I run it?
26 |
27 | The following command will convert all SVGs in a directory called `svgs/`, convert them all into `VectorDrawable`s, and write them to a directory called `vectors/`. Note that both directories must exist beforehand.
28 |
29 | ```
30 | ./vd-tool -c -in svgs/ -out vectors/
31 | ```
32 |
33 | ## How do I build it?
34 |
35 | In case you want to build these yourself, here's how I did it.
36 |
37 | First, follow the [Downloading the Source](https://source.android.com/source/downloading.html) guide to install and set up the `repo` tool, but instead of running the listed `repo` commands to initialize the repository, run the folowing:
38 |
39 | ```
40 | repo init -u https://android.googlesource.com/platform/manifest -b
41 | ```
42 |
43 | At the time of this writing, the most recent Android Studio branch was `studio-3.2.1`. This will obviously change over time as newer versions of Android Studio are released.
44 |
45 | Now that your repository is set to pull only what you need for building and running the tool, download the code using the following command (you might want to grab a coffee or something too, as this command might take a while to complete):
46 |
47 | ```
48 | repo sync -j8 -c
49 | ```
50 |
51 | Finally, execute the following to build the binaries:
52 |
53 | ```
54 | cd ./tools/base
55 | ../gradlew publishLocal
56 | ```
57 |
58 | Once it completes, you should find the binaries in a `/out/build/base/vector-drawable-tool/build/distributions/vd-tool.zip` file. Unzip it and it will extract a `/bin` directory that contains binaries compatible with Mac OS X, Linux, and Windows.
59 |
60 | ## How do I report bugs?
61 |
62 | Now for the most important part of this blog post...
63 |
64 | Please, please, **please** file bugs if you discover SVGs that don't convert properly! File the bugs in the [Android Studio public issue tracker](https://issuetracker.google.com/issues?q=componentid:192708%20status:open). Here's [an example bug](https://issuetracker.google.com/issues/119372339) I recently reported if you need a template to go by.
65 |
66 | My goal is to make the Android Studio converter the most reliable SVG-to-`VectorDrawable` converter out there. So if and when you file a bug, feel free to [hit me up on Twitter](https://twitter.com/alexjlockwood) with a link to the report and I'll do my best to ensure the bug is fixed as quickly as possible!
67 |
68 | Happy converting!
69 |
--------------------------------------------------------------------------------
/about/index.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: About Me
4 | id: 'about/index'
5 | ---
6 |
About Me
7 |
8 |
9 |
10 |
Hi, my name's Alex. I'm a passionate Android developer and a huge fan of design patterns.
11 |
12 |
As a contributor to several open-source projects and an active user
13 | on StackOverflow, I've encountered too many applications that suffer due to poor
14 | code design. Organizing the code that makes up your Android project can be a challenge,
15 | but it is essential when writing an application that can be easily extended and maintained
16 | in the future.
17 |
18 |
The goal of this blog is simple: to encourage proper coding practices when it comes
19 | to Android development. The blog posts range from in-depth tutorials to casual rants
20 | on Android-related topics. I hope that each post will give you with a better understanding
21 | as to why proper code design in Android development is so important.
22 |
23 |
If you have any questions, don't hesitate to leave a comment!
24 | Feel free to shoot me an email at
25 | ale...@androiddesignpatterns.com
26 | if you have any suggestions about the site. You can add me to your circles on
27 | Google+
28 | as well!