├── LICENSE
├── README.en.md
├── README.md
├── templates
└── rx-architecture
│ ├── .gitignore
│ ├── README.md
│ ├── app
│ ├── .gitignore
│ ├── build.gradle
│ ├── checkstyle.xml
│ ├── example.keystore
│ ├── proguard-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── com
│ │ │ └── futurice
│ │ │ └── project
│ │ │ └── test
│ │ │ ├── device
│ │ │ └── BookFragmentTest.java
│ │ │ └── robolectric
│ │ │ ├── RobolectricGradleTestRunner.java
│ │ │ └── models
│ │ │ └── BiographiesModelTest.java
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ └── com
│ │ │ └── futurice
│ │ │ └── project
│ │ │ ├── MainActivity.java
│ │ │ ├── fragments
│ │ │ └── BookFragment.java
│ │ │ ├── models
│ │ │ ├── BiographiesModel.java
│ │ │ └── pojo
│ │ │ │ ├── Author.java
│ │ │ │ ├── Book.java
│ │ │ │ └── SearchEngineResults.java
│ │ │ ├── network
│ │ │ ├── ApiConstants.java
│ │ │ ├── JacksonConverter.java
│ │ │ ├── MyProjectApi.java
│ │ │ └── SearchEngineService.java
│ │ │ └── utils
│ │ │ └── SubscriptionUtils.java
│ │ └── res
│ │ ├── drawable-hdpi
│ │ └── ic_launcher.png
│ │ ├── drawable-mdpi
│ │ └── ic_launcher.png
│ │ ├── drawable-xhdpi
│ │ └── ic_launcher.png
│ │ ├── drawable-xxhdpi
│ │ └── ic_launcher.png
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ └── fragment_main.xml
│ │ ├── menu
│ │ └── main.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
│ ├── gradlew
│ ├── gradlew.bat
│ └── settings.gradle
└── translations
└── Japanese
└── README.ja.md
/LICENSE:
--------------------------------------------------------------------------------
1 | Creative Commons Corporation (“Creative Commons”) is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an “as-is” basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible.
2 |
3 | Using Creative Commons Public Licenses
4 |
5 | Creative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses.
6 |
7 | Considerations for licensors: Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC-licensed material, or material used under an exception or limitation to copyright. More considerations for licensors.
8 |
9 | Considerations for the public: By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensor’s permission is not necessary for any reason–for example, because of any applicable exception or limitation to copyright–then that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. Although not required by our licenses, you are encouraged to respect those requests where reasonable. More considerations for the public.
10 |
11 | Creative Commons Attribution 4.0 International Public License
12 |
13 | By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions.
14 |
15 | Section 1 – Definitions.
16 |
17 | Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image.
18 | Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License.
19 | Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights.
20 | Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements.
21 | Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material.
22 | Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License.
23 | Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license.
24 | Licensor means the individual(s) or entity(ies) granting rights under this Public License.
25 | Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them.
26 | Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world.
27 | You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning.
28 |
29 | Section 2 – Scope.
30 |
31 | License grant.
32 | Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to:
33 | reproduce and Share the Licensed Material, in whole or in part; and
34 | produce, reproduce, and Share Adapted Material.
35 | Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions.
36 | Term. The term of this Public License is specified in Section 6(a).
37 | Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material.
38 | Downstream recipients.
39 | Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License.
40 | No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material.
41 | No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i).
42 |
43 | Other rights.
44 | Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise.
45 | Patent and trademark rights are not licensed under this Public License.
46 | To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties.
47 |
48 | Section 3 – License Conditions.
49 |
50 | Your exercise of the Licensed Rights is expressly made subject to the following conditions.
51 |
52 | Attribution.
53 |
54 | If You Share the Licensed Material (including in modified form), You must:
55 | retain the following if it is supplied by the Licensor with the Licensed Material:
56 | identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated);
57 | a copyright notice;
58 | a notice that refers to this Public License;
59 | a notice that refers to the disclaimer of warranties;
60 | a URI or hyperlink to the Licensed Material to the extent reasonably practicable;
61 | indicate if You modified the Licensed Material and retain an indication of any previous modifications; and
62 | indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License.
63 | You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information.
64 | If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable.
65 | If You Share Adapted Material You produce, the Adapter's License You apply must not prevent recipients of the Adapted Material from complying with this Public License.
66 |
67 | Section 4 – Sui Generis Database Rights.
68 |
69 | Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material:
70 |
71 | for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database;
72 | if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material; and
73 | You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database.
74 |
75 | For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights.
76 |
77 | Section 5 – Disclaimer of Warranties and Limitation of Liability.
78 |
79 | Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.
80 | To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.
81 |
82 | The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability.
83 |
84 | Section 6 – Term and Termination.
85 |
86 | This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically.
87 |
88 | Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates:
89 | automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or
90 | upon express reinstatement by the Licensor.
91 | For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License.
92 | For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License.
93 | Sections 1, 5, 6, 7, and 8 survive termination of this Public License.
94 |
95 | Section 7 – Other Terms and Conditions.
96 |
97 | The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed.
98 | Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License.
99 |
100 | Section 8 – Interpretation.
101 |
102 | For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License.
103 | To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions.
104 | No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor.
105 | Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority.
106 |
107 | Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at creativecommons.org/policies, Creative Commons does not authorize the use of the trademark “Creative Commons” or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses.
108 |
109 | Creative Commons may be contacted at creativecommons.org.
--------------------------------------------------------------------------------
/README.en.md:
--------------------------------------------------------------------------------
1 | # Best practices in Android development
2 |
3 | Lessons learned from Android developers in [Futurice](http://www.futurice.com). Avoid reinventing the wheel by following these guidelines. If you are interested in iOS or Windows Phone development, be sure to check also our [**iOS Good Practices**](https://github.com/futurice/ios-good-practices) and [**Windows App Development Best Practices**](https://github.com/futurice/windows-app-development-best-practices) documents.
4 |
5 | [](https://android-arsenal.com/details/1/1091)
6 |
7 | ## Summary
8 |
9 | #### Use Gradle and its recommended project structure
10 | #### Put passwords and sensitive data in gradle.properties
11 | #### Don't write your own HTTP client, use Volley or OkHttp libraries
12 | #### Use the Jackson library to parse JSON data
13 | #### Avoid Guava and use only a few libraries due to the *65k method limit*
14 | #### Use Fragments to represent a UI screen
15 | #### Use Activities just to manage Fragments
16 | #### Layout XMLs are code, organize them well
17 | #### Use styles to avoid duplicate attributes in layout XMLs
18 | #### Use multiple style files to avoid a single huge one
19 | #### Keep your colors.xml short and DRY, just define the palette
20 | #### Also keep dimens.xml DRY, define generic constants
21 | #### Do not make a deep hierarchy of ViewGroups
22 | #### Avoid client-side processing for WebViews, and beware of leaks
23 | #### Use Robolectric for unit tests, Robotium for connected (UI) tests
24 | #### Use Genymotion as your emulator
25 | #### Always use ProGuard or DexGuard
26 |
27 |
28 | ----------
29 |
30 | ### Android SDK
31 |
32 | Place your [Android SDK](https://developer.android.com/sdk/installing/index.html?pkg=tools) somewhere in your home directory or some other application-independent location. Some IDEs include the SDK when installed, and may place it under the same directory as the IDE. This can be bad when you need to upgrade (or reinstall) the IDE, or when changing IDEs. Also avoid putting the SDK in another system-level directory that might need sudo permissions, if your IDE is running under your user and not under root.
33 |
34 | ### Build system
35 |
36 | Your default option should be [Gradle](http://tools.android.com/tech-docs/new-build-system). Ant is much more limited and also more verbose. With Gradle, it's simple to:
37 |
38 | - Build different flavours or variants of your app
39 | - Make simple script-like tasks
40 | - Manage and download dependencies
41 | - Customize keystores
42 | - And more
43 |
44 | Android's Gradle plugin is also being actively developed by Google as the new standard build system.
45 |
46 | ### Project structure
47 |
48 | There are two popular options: the old Ant & Eclipse ADT project structure, and the new Gradle & Android Studio project structure. You should choose the new project structure. If your project uses the old structure, consider it legacy and start porting it to the new structure.
49 |
50 | Old structure:
51 |
52 | ```
53 | old-structure
54 | ├─ assets
55 | ├─ libs
56 | ├─ res
57 | ├─ src
58 | │ └─ com/futurice/project
59 | ├─ AndroidManifest.xml
60 | ├─ build.gradle
61 | ├─ project.properties
62 | └─ proguard-rules.pro
63 | ```
64 |
65 | New structure:
66 |
67 | ```
68 | new-structure
69 | ├─ library-foobar
70 | ├─ app
71 | │ ├─ libs
72 | │ ├─ src
73 | │ │ ├─ androidTest
74 | │ │ │ └─ java
75 | │ │ │ └─ com/futurice/project
76 | │ │ └─ main
77 | │ │ ├─ java
78 | │ │ │ └─ com/futurice/project
79 | │ │ ├─ res
80 | │ │ └─ AndroidManifest.xml
81 | │ ├─ build.gradle
82 | │ └─ proguard-rules.pro
83 | ├─ build.gradle
84 | └─ settings.gradle
85 | ```
86 |
87 | The main difference is that the new structure explicitly separates 'source sets' (`main`, `androidTest`), a concept from Gradle. You could, for instance, add source sets 'paid' and 'free' into `src` which will have source code for the paid and free flavours of your app.
88 |
89 | Having a top-level `app` is useful to distinguish your app from other library projects (e.g., `library-foobar`) that will be referenced in your app. The `settings.gradle` then keeps references to these library projects, which `app/build.gradle` can reference to.
90 |
91 | ### Gradle configuration
92 |
93 | **General structure.** Follow [Google's guide on Gradle for Android](http://tools.android.com/tech-docs/new-build-system/user-guide)
94 |
95 | **Small tasks.** Instead of (shell, Python, Perl, etc) scripts, you can make tasks in Gradle. Just follow [Gradle's documentation](http://www.gradle.org/docs/current/userguide/userguide_single.html#N10CBF) for more details.
96 |
97 | **Passwords.** In your app's `build.gradle` you will need to define the `signingConfigs` for the release build. Here is what you should avoid:
98 |
99 | _Don't do this_. This would appear in the version control system.
100 |
101 | ```groovy
102 | signingConfigs {
103 | release {
104 | storeFile file("myapp.keystore")
105 | storePassword "password123"
106 | keyAlias "thekey"
107 | keyPassword "password789"
108 | }
109 | }
110 | ```
111 |
112 | Instead, make a `gradle.properties` file which should _not_ be added to the version control system:
113 |
114 | ```
115 | KEYSTORE_PASSWORD=password123
116 | KEY_PASSWORD=password789
117 | ```
118 |
119 | That file is automatically imported by gradle, so you can use it in `build.gradle` as such:
120 |
121 | ```groovy
122 | signingConfigs {
123 | release {
124 | try {
125 | storeFile file("myapp.keystore")
126 | storePassword KEYSTORE_PASSWORD
127 | keyAlias "thekey"
128 | keyPassword KEY_PASSWORD
129 | }
130 | catch (ex) {
131 | throw new InvalidUserDataException("You should define KEYSTORE_PASSWORD and KEY_PASSWORD in gradle.properties.")
132 | }
133 | }
134 | }
135 | ```
136 |
137 | **Prefer Maven dependency resolution instead of importing jar files.** If you explicitly include jar files in your project, they will be of some specific frozen version, such as `2.1.1`. Downloading jars and handling updates is cumbersome, this is a problem that Maven solves properly, and is also encouraged in Android Gradle builds. For example:
138 |
139 | ```groovy
140 | dependencies {
141 | compile 'com.squareup.okhttp:okhttp:2.2.0'
142 | compile 'com.squareup.okhttp:okhttp-urlconnection:2.2.0'
143 | }
144 | ```
145 |
146 | **Avoid Maven dynamic dependency resolution**
147 | Avoid the use of dynamically versioned, such as `2.1.+` as this may result in different in unstable builds or subtle, untracked differences in behavior between builds. The use of static versions such as `2.1.1` helps create a more stable, predictable and repeatable development environment.
148 |
149 | ### IDEs and text editors
150 |
151 | **Use whatever editor, but it must play nicely with the project structure.** Editors are a personal choice, and it's your responsibility to get your editor functioning according to the project structure and build system.
152 |
153 | The most recommended IDE at the moment is [Android Studio](https://developer.android.com/sdk/installing/studio.html), because it is developed by Google, is closest to Gradle, uses the new project structure by default, is finally in stable stage, and is tailored for Android development.
154 |
155 | You can use [Eclipse ADT](https://developer.android.com/sdk/installing/index.html?pkg=adt) if you wish, but you need to configure it, since it expects the old project structure and Ant for building. You can even use a plain text editor like Vim, Sublime Text, or Emacs. In that case, you will need to use Gradle and `adb` on the command line. If Eclipse's integration with Gradle is not working for you, your options are using the command line just to build, or migrating to Android Studio. This is the best option due to ADT plugin was deprecated recently.
156 |
157 | Whatever you use, just make sure Gradle and the new project structure remain as the official way of building the application, and avoid adding your editor-specific configuration files to the version control system. For instance, avoid adding an Ant `build.xml` file. Especially don't forget to keep `build.gradle` up-to-date and functioning if you are changing build configurations in Ant. Also, be kind to other developers, don't force them to change their tool of preference.
158 |
159 | ### Libraries
160 |
161 | **[Jackson](http://wiki.fasterxml.com/JacksonHome)** is a Java library for converting Objects into JSON and vice-versa. [Gson](https://code.google.com/p/google-gson/) is a popular choice for solving this problem, however we find Jackson to be more performant since it supports alternative ways of processing JSON: streaming, in-memory tree model, and traditional JSON-POJO data binding. Keep in mind, though, that Jackson is a larger library than GSON, so depending on your case, you might prefer GSON to avoid 65k methods limitation. Other alternatives: [Json-smart](https://code.google.com/p/json-smart/) and [Boon JSON](https://github.com/RichardHightower/boon/wiki/Boon-JSON-in-five-minutes)
162 |
163 | **Networking, caching, and images.** There are a couple of battle-proven solutions for performing requests to backend servers, which you should use perform considering implementing your own client. Use [Volley](https://android.googlesource.com/platform/frameworks/volley) or [Retrofit](http://square.github.io/retrofit/). Volley also provides helpers to load and cache images. If you choose Retrofit, consider [Picasso](http://square.github.io/picasso/) for loading and caching images, and [OkHttp](http://square.github.io/okhttp/) for efficient HTTP requests. All three Retrofit, Picasso and OkHttp are created by the same company, so they complement each other nicely. [OkHttp can also be used in connection with Volley](http://stackoverflow.com/questions/24375043/how-to-implement-android-volley-with-okhttp-2-0/24951835#24951835).
164 |
165 | **RxJava** is a library for Reactive Programming, in other words, handling asynchronous events. It is a powerful and promising paradigm, which can also be confusing since it's so different. We recommend to take some caution before using this library to architect the entire application. There are some projects done by us using RxJava, if you need help talk to one of these people: Timo Tuominen, Olli Salonen, Andre Medeiros, Mark Voit, Antti Lammi, Vera Izrailit, Juha Ristolainen. We have written some blog posts on it: [[1]](http://blog.futurice.com/tech-pick-of-the-week-rx-for-net-and-rxjava-for-android), [[2]](http://blog.futurice.com/top-7-tips-for-rxjava-on-android), [[3]](https://gist.github.com/staltz/868e7e9bc2a7b8c1f754), [[4]](http://blog.futurice.com/android-development-has-its-own-swift).
166 |
167 | If you have no previous experience with Rx, start by applying it only for responses from the API. Alternatively, start by applying it for simple UI event handling, like click events or typing events on a search field. If you are confident in your Rx skills and want to apply it to the whole architecture, then write Javadocs on all the tricky parts. Keep in mind that another programmer unfamiliar to RxJava might have a very hard time maintaining the project. Do your best to help them understand your code and also Rx.
168 |
169 | **[Retrolambda](https://github.com/evant/gradle-retrolambda)** is a Java library for using Lambda expression syntax in Android and other pre-JDK8 platforms. It helps keep your code tight and readable especially if you use a functional style with for example with RxJava. To use it, install JDK8, set that as your SDK Location in the Android Studio Project Structure dialog, and set `JAVA8_HOME` and `JAVA7_HOME` environment variables, then in the project root build.gradle:
170 |
171 | ```groovy
172 | dependencies {
173 | classpath 'me.tatarka:gradle-retrolambda:2.4.1'
174 | }
175 | ```
176 |
177 | and in each module's build.gradle, add
178 |
179 | ```groovy
180 | apply plugin: 'retrolambda'
181 |
182 | android {
183 | compileOptions {
184 | sourceCompatibility JavaVersion.VERSION_1_8
185 | targetCompatibility JavaVersion.VERSION_1_8
186 | }
187 |
188 | retrolambda {
189 | jdk System.getenv("JAVA8_HOME")
190 | oldJdk System.getenv("JAVA7_HOME")
191 | javaVersion JavaVersion.VERSION_1_7
192 | }
193 | ```
194 |
195 | Android Studio offers code assist support for Java8 lambdas. If you are new to lambdas, just use the following to get started:
196 |
197 | - Any interface with just one method is "lambda friendly" and can be folded into the more tight syntax
198 | - If in doubt about parameters and such, write a normal anon inner class and then let Android Studio fold it into a lambda for you.
199 |
200 | **Beware of the dex method limitation, and avoid using many libraries.** Android apps, when packaged as a dex file, have a hard limitation of 65536 referenced methods [[1]](https://medium.com/@rotxed/dex-skys-the-limit-no-65k-methods-is-28e6cb40cf71) [[2]](http://blog.persistent.info/2014/05/per-package-method-counts-for-androids.html) [[3]](http://jakewharton.com/play-services-is-a-monolith/). You will see a fatal error on compilation if you pass the limit. For that reason, use a minimal amount of libraries, and use the [dex-method-counts](https://github.com/mihaip/dex-method-counts) tool to determine which set of libraries can be used in order to stay under the limit. Especially avoid using the Guava library, since it contains over 13k methods.
201 |
202 | ### Activities and Fragments
203 |
204 | [Fragments](http://developer.android.com/guide/components/fragments.html) should be your default option for implementing a UI screen in Android. Fragments are reusable user interfaces that can be composed in your application. We recommend using fragments instead of [activities](http://developer.android.com/guide/components/activities.html) to represent a user interface screen, here are some reasons why:
205 |
206 | - **Solution for multi-pane layouts.** Fragments were primarily introduced for extending phone applications to tablet screens, so that you can have both panes A and B on a tablet screen, while either A or B occupy an entire phone screen. If your application is implemented in fragments from the beginning, you will make it easier later to adapt your application to different form-factors.
207 |
208 | - **Screen-to-screen communication.** Android's API does not provide a proper way of sending complex data (e.g., some Java Object) from one activity to another activity. With fragments, however, you can use the instance of an activity as a channel of communication between its child fragments. Even though this is better than Activity-to-Activity communication, you might want to consider an Event Bus architecture, using e.g. [Otto](https://square.github.io/otto/) or [greenrobot EventBus](https://github.com/greenrobot/EventBus), as a cleaner approach. RxJava can also be used for implementing an Event Bus, in case you want to avoid adding yet another library.
209 |
210 | - **Fragments are generic enough to not be UI-only.** You can have a [fragment without a UI](http://developer.android.com/guide/components/fragments.html#AddingWithoutUI) that works as background workers for the activity. You can take that idea further to create a [fragment to contain the logic for changing fragments](http://stackoverflow.com/questions/12363790/how-many-activities-vs-fragments/12528434#12528434), instead of having that logic in the activity.
211 |
212 | - **Even the ActionBar can be managed from within fragments.** You can choose to have one Fragment without a UI with the sole purpose of managing the ActionBar, or you can choose to have each currently visible Fragment add its own action items to the parent Activity's ActionBar. [Read more here](http://www.grokkingandroid.com/adding-action-items-from-within-fragments/).
213 |
214 | That being said, we advise not to use [nested fragments](https://developer.android.com/about/versions/android-4.2.html#NestedFragments) extensively, because [matryoshka bugs](http://delyan.me/android-s-matryoshka-problem/) can occur. Use nested fragments only when it makes sense (for instance, fragments in a horizontally-sliding ViewPager inside a screen-like fragment) or if it's a well-informed decision.
215 |
216 | On an architectural level, your app should have a top-level activity that contains most of the business-related fragments. You can also have some other supporting activities, as long as their communication with the main activity is simple and can be limited to [`Intent.setData()`](http://developer.android.com/reference/android/content/Intent.html#setData(android.net.Uri)) or [`Intent.setAction()`](http://developer.android.com/reference/android/content/Intent.html#setAction(java.lang.String)) or similar.
217 |
218 | ### Java packages architecture
219 |
220 | Java architectures for Android applications can be roughly approximated in [Model-View-Controller](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller). In Android, [Fragment and Activity are actually controller classes](http://www.informit.com/articles/article.aspx?p=2126865). On the other hand, they are explicity part of the user interface, hence are also views.
221 |
222 | For this reason, it is hard to classify fragments (or activities) as strictly controllers or views. It's better to let them stay in their own `fragments` package. Activities can stay on the top-level package as long as you follow the advice of the previous section. If you are planning to have more than 2 or 3 activities, then make also an `activities` package.
223 |
224 | Otherwise, the architecture can look like a typical MVC, with a `models` package containing POJOs to be populated through the JSON parser with API responses, and a `views` package containing your custom Views, notifications, action bar views, widgets, etc. Adapters are a gray matter, living between data and views. However, they typically need to export some View via `getView()`, so you can include the `adapters` subpackage inside `views`.
225 |
226 | Some controller classes are application-wide and close to the Android system. These can live in a `managers` package. Miscellaneous data processing classes, such as "DateUtils", stay in the `utils` package. Classes that are responsible for interacting with the backend stay in the `network` package.
227 |
228 | All in all, ordered from the closest-to-backend to the closest-to-the-user:
229 |
230 | ```
231 | com.futurice.project
232 | ├─ network
233 | ├─ models
234 | ├─ managers
235 | ├─ utils
236 | ├─ fragments
237 | └─ views
238 | ├─ adapters
239 | ├─ actionbar
240 | ├─ widgets
241 | └─ notifications
242 | ```
243 |
244 | ### Resources
245 |
246 | **Naming.** Follow the convention of prefixing the type, as in `type_foo_bar.xml`. Examples: `fragment_contact_details.xml`, `view_primary_button.xml`, `activity_main.xml`.
247 |
248 | **Organizing layout XMLs.** If you're unsure how to format a layout XML, the following convention may help.
249 |
250 | - One attribute per line, indented by 4 spaces
251 | - `android:id` as the first attribute always
252 | - `android:layout_****` attributes at the top
253 | - `style` attribute at the bottom
254 | - Tag closer `/>` on its own line, to facilitate ordering and adding attributes.
255 | - Rather than hard coding `android:text`, consider using [Designtime attributes](http://tools.android.com/tips/layout-designtime-attributes) available for Android Studio.
256 |
257 | ```xml
258 |
259 |
266 |
267 |
275 |
276 |
277 |
278 |
279 | ```
280 |
281 | As a rule of thumb, attributes `android:layout_****` should be defined in the layout XML, while other attributes `android:****` should stay in a style XML. This rule has exceptions, but in general works fine. The idea is to keep only layout (positioning, margin, sizing) and content attributes in the layout files, while keeping all appearance details (colors, padding, font) in styles files.
282 |
283 | The exceptions are:
284 |
285 | - `android:id` should obviously be in the layout files
286 | - `android:orientation` for a `LinearLayout` normally makes more sense in layout files
287 | - `android:text` should be in layout files because it defines content
288 | - Sometimes it will make sense to make a generic style defining `android:layout_width` and `android:layout_height` but by default these should appear in the layout files
289 |
290 | **Use styles.** Almost every project needs to properly use styles, because it is very common to have a repeated appearance for a view. At least you should have a common style for most text content in the application, for example:
291 |
292 | ```xml
293 |
297 | ```
298 |
299 | Applied to TextViews:
300 |
301 | ```xml
302 |
308 | ```
309 |
310 | You probably will need to do the same for buttons, but don't stop there yet. Go beyond and move a group of related and repeated `android:****` attributes to a common style.
311 |
312 | **Split a large style file into other files.** You don't need to have a single `styles.xml` file. Android SDK supports other files out of the box, there is nothing magical about the name `styles`, what matters are the XML tags `
291 | ```
292 |
293 | TextView에 적용해보면:
294 |
295 | ```xml
296 |
302 | ```
303 |
304 | 아마 버튼들에도 같은 일을 해주어야 하겠지만, 멈추지 말자. 계속 진행하면서 연관되어있고 중복된 `android:****` 속성들을 일반 스타일로 묶자.
305 |
306 | **큰 스타일 파일은 다른 파일들로 나누자.** 단 하나의 `styles.xml` 파일을 가질 필요는 없다. Android SDK는 박스 외부의 파일들도 지원하는데, `styles`라는 이름엔 전혀 마법같은 무언가가 없이 파일 안에 `
7 |
8 |
12 |
13 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/templates/rx-architecture/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | mavenCentral()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:1.0.0'
9 | }
10 | }
11 |
12 | allprojects {
13 | repositories {
14 | mavenCentral()
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/templates/rx-architecture/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Settings specified in this file will override any Gradle settings
5 | # configured through the IDE.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/templates/rx-architecture/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minsoopark/android-best-practices-kor/c4eb353ddc46b51b0487faf18240a37e0d082a0f/templates/rx-architecture/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/templates/rx-architecture/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Dec 09 11:05:19 EET 2014
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
7 |
--------------------------------------------------------------------------------
/templates/rx-architecture/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/templates/rx-architecture/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/templates/rx-architecture/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/translations/Japanese/README.ja.md:
--------------------------------------------------------------------------------
1 | # Androidの開発におけるベストプラクティス
2 |
3 | 以下は[Futurice](http://www.futurice.com)で働くAndroidアプリ開発者が学んだ教訓である. これらをしっかり読んで車輪の再開発はやめよう. もしiOSやWindows Phoneの開発に興味があるなら,[**iOS Good Practices**](https://github.com/futurice/ios-good-practices)と[**Windows client Good Practices**](https://github.com/futurice/win-client-dev-good-practices)を必ず確認しよう。
4 |
5 | フィードバックは歓迎しているが、まずは[ガイドライン](https://github.com/futurice/android-best-practices/tree/master/CONTRIBUTING.md)を読んでほしい.
6 |
7 | [](https://android-arsenal.com/details/1/1091)
8 |
9 | ## Summary
10 |
11 | #### Gradleで推奨されるプロジェクト構成で開発しよう
12 | #### パスワードや注意を要するデータはgradle.propertiesに書こう
13 | #### 自分でHTTP Clientは作らず、VolleyやOkHttpを使おう
14 | #### JSONをパースするならJacksonを使おう
15 | #### メソッド数に65kの制限があるので、Guavaは避けて、かつライブラリは最小限に抑えよう
16 | #### UIの描画はFragmentを使おう
17 | #### ActivityはFragmentをただ管理するために使おう
18 | #### Layout xmlをうまく整理しよう
19 | #### Layout xmlの属性が重複するのを避けるためStyleを使おう
20 | #### 大きなStyleを定義するよりも複数のStyleを定義しよう
21 | #### colors.xmlは短くDRY(「Don't Repeat Yourself」意味が重複しないよう)にして、パレットで定義しよう
22 | #### dimens.xmlもDRYにして、一般の定数を定義しよう
23 | #### ViewGroupのネストは深くせずに浅くしよう
24 | #### WebViewはメモリリークするため、クライアント側での処理は避けよう
25 | #### ユニットテストにはRobolectricを、結合テストにはRobotiumを使おう
26 | #### emulatorはGenymotionで決まり
27 | #### 必ずProGuardもしくはDexGuardを使おう
28 |
29 |
30 | ----------
31 |
32 | ### Android SDK
33 |
34 | [Android SDK](https://developer.android.com/sdk/installing/index.html?pkg=tools)はホームディレクトリか他のアプリから独立した場所に置こう。いくつかのIDEはSDKを含んでいて、インストール時にSDKをIDEと同じディレクトリに置く事がある。このままではIDEをアップグレードや再インストールする場合、またIDEを変更する場合に面倒になる。
35 | また、IDEがrootでないアカウントで動いている場合に、sudoが必要な他のシステムレベルのディレクトリにSDKを置く事も避けよう。
36 |
37 | ### Build system
38 |
39 | デフォルトオプションに[Gradle](http://tools.android.com/tech-docs/new-build-system)を使おう。Antは制限が多く、コストが大きい。しかし、Gradleなら下記のことがシンプルに可能だ。
40 |
41 | - あなたのアプリの異なるFlavorやVariantをビルドできる
42 | - スクリプトのようにタスクを作る事ができる
43 | - 依存関係を管理しつつダウンロードできる
44 | - keystoreをカスタマイズできる
45 | - その他諸々
46 |
47 | そして、Googleは、AndroidのGradleプラグインを標準のビルドシステムとして盛んに開発している。
48 |
49 | ### プロジェクト構成
50 |
51 | プロジェクト構成については、これまでのAnt & Eclipse ADTのプロジェクト構成と 新しいGradle & Android Studioのプロジェク構成の二つが有名であるが、後者の新しいプロジェクト構成を選ぶべきだ。もし前者の古いプロジェクト構成をつかっているなら、それは遺産だと考えて、新しいプロジェクト構成に変える事を考えた方がいい。
52 |
53 | 古い構成:
54 |
55 | ```
56 | old-structure
57 | ├─ assets
58 | ├─ libs
59 | ├─ res
60 | ├─ src
61 | │ └─ com/futurice/project
62 | ├─ AndroidManifest.xml
63 | ├─ build.gradle
64 | ├─ project.properties
65 | └─ proguard-rules.pro
66 | ```
67 |
68 | 新しい構成:
69 |
70 | ```
71 | new-structure
72 | ├─ library-foobar
73 | ├─ app
74 | │ ├─ libs
75 | │ ├─ src
76 | │ │ ├─ androidTest
77 | │ │ │ └─ java
78 | │ │ │ └─ com/futurice/project
79 | │ │ └─ main
80 | │ │ ├─ java
81 | │ │ │ └─ com/futurice/project
82 | │ │ ├─ res
83 | │ │ └─ AndroidManifest.xml
84 | │ ├─ build.gradle
85 | │ └─ proguard-rules.pro
86 | ├─ build.gradle
87 | └─ settings.gradle
88 | ```
89 |
90 | 一番の違いは新しいプロジェクト構成では'Source sets'(main, androidTest)が明確に分けられている事だ。これはGradleのコンセプトでもある。
91 | これによって例えば`paid`と`free`というSource setを`src`の中に追加すると、'paid'と'free'というFlavorができる。
92 |
93 | さらに`app`がtop-levelにあると、アプリで参照される`library-foobar`などの他のライブラリプロジェクトを区別するのに役立つ。`setting.gradle`が各ライブラリへの参照をもち、`app/build.gradle`から参照する事ができる。
94 |
95 | ### Gradleの設定
96 |
97 | **一般的な構成**
98 | [Google's guide on Gradle for Android](http://tools.android.com/tech-docs/new-build-system/user-guide)を参照の事。
99 |
100 | **小さなタスク**
101 | shell, Python, Perlなどのスクリプトの代わりに、Gradleの中にタスクをつくることができる。詳細は[Gradle's documentation](http://www.gradle.org/docs/current/userguide/userguide_single.html#N10CBF)を参照の事。
102 |
103 | **パスワード**
104 | リリースビルドのために`build.gradle`の中で`signingConfigs`を定義しなければならないときがある。
105 |
106 | 下記はダメなケース。これではバージョン管理システムで管理されてしまう。
107 |
108 | ```groovy
109 | signingConfigs {
110 | release {
111 | storeFile file("myapp.keystore")
112 | storePassword "password123"
113 | keyAlias "thekey"
114 | keyPassword "password789"
115 | }
116 | }
117 | ```
118 |
119 | その代わりに、`gradle.properties`に下記のように書いて、このファイルをバージョン管理の管理外としよう。
120 |
121 | ```
122 | KEYSTORE_PASSWORD=password123
123 | KEY_PASSWORD=password789
124 | ```
125 |
126 | このファイルはgradleによって自動でimportされるので、このときの`build.gradle`は下記のように書くとよい。
127 |
128 | ```groovy
129 | signingConfigs {
130 | release {
131 | try {
132 | storeFile file("myapp.keystore")
133 | storePassword KEYSTORE_PASSWORD
134 | keyAlias "thekey"
135 | keyPassword KEY_PASSWORD
136 | }
137 | catch (ex) {
138 | throw new InvalidUserDataException("You should define KEYSTORE_PASSWORD and KEY_PASSWORD in gradle.properties.")
139 | }
140 | }
141 | }
142 | ```
143 |
144 | **jarファイルを直接importするよりMavenを使う方が良い**
145 | jarファイルをプロジェクトに直接includeしている場合、version`2.1.1`のようにversionが固定されてしまう。さらに、jarファイルをダウンロードして、手動でアップデートするはめになり効率が悪い。Mavenならこれを解決できるし、Android StudioもMevenの使用をすすめている。`2.1.+`というようにversionの範囲を指定することもでき、指定した範囲の中での最新にアップデートしてくれる。
146 | たとえば下記のように書く。
147 |
148 | ```groovy
149 | dependencies {
150 | compile 'com.netflix.rxjava:rxjava-core:0.19.+'
151 | compile 'com.netflix.rxjava:rxjava-android:0.19.+'
152 | compile 'com.fasterxml.jackson.core:jackson-databind:2.4.+'
153 | compile 'com.fasterxml.jackson.core:jackson-core:2.4.+'
154 | compile 'com.fasterxml.jackson.core:jackson-annotations:2.4.+'
155 | compile 'com.squareup.okhttp:okhttp:2.0.+'
156 | compile 'com.squareup.okhttp:okhttp-urlconnection:2.0.+'
157 | }
158 | ```
159 |
160 | ### IDEとテキストエディタ
161 |
162 | **エディターは何を使っても良いが、例のプロジェクト構成のまま扱えるものが良い**
163 | エディターはプロジェクト構成、ビルドシステムにあったものを選べば良い。
164 |
165 | 一番推奨されるIDEは[Android Studio](https://developer.android.com/sdk/installing/studio.html)である。Google が開発しており、Gradleと親和性が高いうえ、プロジェクト構成もデフォルトで推奨されているものを採用しているからだ。
166 |
167 | もしお望みなら[Eclipse ADT](https://developer.android.com/sdk/installing/index.html?pkg=adt)をつかってもいいが、デフォルトで古いプロジェクト構成でかつAntを採用しているので設定が必要である。EclipseのGraldeプラグインが動かない場合はコマンドラインでやるか、Android Studioに移行するかしかない。
168 | またVim、Sublime TextやEmacsといった純粋なテキストエディタを使用することさえできる。その場合は、コマンドラインからGradleとadbを使えるよう準備する必要がある。
169 |
170 | 何を使っても良いが、Graldeを使う事と新しいプロジェクト構成で開発する事がオフィシャルな方法である事を頭に入れておかねばならない。またAntの`build.xml`などのエディタ特有の設定ファイルなどはバージョン管理外とすることもお忘れなく。特に、Antのビルド設定を変更した際は`build.gradle`が最新であり機能する事を確認することを怠ってはならない。また他の開発者が使っているツールの設定を強要することがないようにしよう。
171 |
172 | ### Libraries
173 |
174 | **[Jackson](http://wiki.fasterxml.com/JacksonHome)** はObjectをJSONに変換、またその逆を行うライブラリである。[GSON](https://code.google.com/p/google-gson/)もJsonのライブラリとして有名だが、streaming、in-memory tree model, Json data binding等をサポートしている点でJacksonの方がいくらか優れていると判断した。ただ覚えておいてほしいのはJacksonがGsonよりボリュームの大きなライブラリである事だ。65k制限を避ける為にGSONの方が有効なケースもあり得る。また他には[json-smart](https://code.google.com/p/json-smart/)、[Boon JSON](https://github.com/boonproject/boon/wiki/Boon-JSON-in-five-minutes)という選択肢もある。
175 |
176 | **ネットワーク、キャッシュ、画像処理について。**バックエンドへのリクエスト処理の実装についていろいろ試した結果言えるのは、自分でクライアントを実装しない方がいいということだ。[Volley](https://android.googlesource.com/platform/frameworks/volley)や[Retrofit](http://square.github.io/retrofit/)を使おう。Volleyはまた画像のロード、キャッシュのヘルパーを提供してくれている。Retrofitを選ぶ人は、[Picasso](http://square.github.io/picasso/)という画像ライブラリ、またHttpリクエストに有効な[OkHttp](http://square.github.io/okhttp/)の導入も考えると良い。この三つのRetrofit、Picasso、OkHttpは一つの会社で作られている。そのため、これらのライブラリは互いをよく補っている。現に[OkHttpはVolleyと共に使われることがよくある。](http://stackoverflow.com/questions/24375043/how-to-implement-android-volley-with-okhttp-2-0/24951835#24951835)
177 |
178 | **RxJava**はリアクティブプログラミングを行う、つまり非同期イベントを扱う為のライブラリだ。これは強力で有望なものだが、通常のプログラミングと異なりすぎる為に困惑をもたらす事がある。私たちはこのライブラリをアプリ全体のアーキテクチャに使う前に注意して扱うことをお勧めする。RxJavaを用いて作った我々のプロジェクトがいくつかあった。もし助力が必要なら次のメンバに話してみると良いかもしれない: Timo Tuominen, Olli Salonen, Andre Medeiros, Mark Voit, Antti Lammi, Vera Izrailit, Juha Ristolainen
179 | またいくつかブログの記事も書いている。[\[1\]](http://futurice.com/blog/tech-pick-of-the-week-rx-for-net-and-rxjava-for-android) [\[2\]](http://futurice.com/blog/top-7-tips-for-rxjava-on-android) [\[3\]](https://gist.github.com/staltz/868e7e9bc2a7b8c1f754) [\[4\]](http://futurice.com/blog/android-development-has-its-own-swift)
180 |
181 | もしRxを使った経験が以前にないのなら、まずはAPIのレスポンスのみ、もしくはクリックイベントや検索フィールドのテキスト変更イベントなどのUIのイベントハンドリングのみに適用するところから始めると良い。
182 | 逆にRxに自信があってプロジェクト全体で使いたい場合は、トリッキーな場所にJavadocを書くと良い。RxJavaのようなよく知られていない他のプログラミング手法を使用する場合はメンテナンスが大変であることを忘れてはいけない。あなたのRxで書かれたコードが他の人も理解できるようにベストを尽くそう。
183 |
184 | **[Retrolambda](https://github.com/evant/gradle-retrolambda)**はAndroidやJDK8以前のプラットフォームでlambda記法を使う事ができるようになるライブラリである。特にRxJavaなど関数型スタイルを採用する場合において、これはコードを短く、見やすくする。
185 | JDK8をインストールして、SDKのときと同じようにAndroid Studioに設定する必要がある。
186 | `JAVA8_HOME`と`JAVA7_HOME`を設定後、ルートのbuild.gradleを下記のように書き
187 |
188 | ```groovy
189 | dependencies {
190 | classpath 'me.tatarka:gradle-retrolambda:2.4.+'
191 | }
192 | ```
193 |
194 | そしてそれぞれのモジュールをbuild.gradleに追加する
195 |
196 | ```groovy
197 | apply plugin: 'retrolambda'
198 |
199 | android {
200 | compileOptions {
201 | sourceCompatibility JavaVersion.VERSION_1_8
202 | targetCompatibility JavaVersion.VERSION_1_8
203 | }
204 |
205 | retrolambda {
206 | jdk System.getenv("JAVA8_HOME")
207 | oldJdk System.getenv("JAVA7_HOME")
208 | javaVersion JavaVersion.VERSION_1_7
209 | }
210 | ```
211 |
212 | Android StudioはJava8のlambda記法のためのコードアシストをサポートしている。もし、あなたがlambdaのビギナーであれば、下記にならって使ってみよう
213 |
214 | - 一つだけメソッドがあるインターフェイスはどれも“lambdaに親和性あり“で、構文をより短くできる
215 | - もしパラメータなどに迷ったときは、普通のインナークラスを書いて、Android Studioでそれをlambdaに盛り込ませてみよう
216 |
217 | **65k制限に注意して、たくさんのライブラリを使うのを避けよう。**
218 | Androidアプリはdexファイルにパッケージングする際に関数の参照は65536個までという厳格な制限がある。[\[1\]](https://medium.com/@rotxed/dex-skys-the-limit-no-65k-methods-is-28e6cb40cf71) [\[2\]](http://blog.persistent.info/2014/05/per-package-method-counts-for-androids.html) [\[3\]](http://jakewharton.com/play-services-is-a-monolith/)。制限を超えた場合はFatal Errorが起きる、そのため、ライブラリは最小限とし、制限内に収まるよう[dex-method-counts](https://github.com/mihaip/dex-method-counts)ツールを使って使用するライブラリを決めよう。特にGuavaは13kも関数があるので避けた方がいい。
219 |
220 | ### Activities and Fragments
221 |
222 | AndroidにおいてはUIの実装は[Fragments](http://developer.android.com/guide/components/fragments.html)で行うべきである。Fragmentsは、アプリ内で構成出来る再利用可能なUIである。ActiivtyではUIの実装をせずにFragmentsで行うことをすすめる。理由は下記である。
223 |
224 | - **multi-pane layoutの解決について。** Fragmentは元はphoneアプリケーションをTableアプリケーションへ拡張するためのものとして紹介された。phoneアプリでAもしくはBというpaneが占めている場合に、TabletではAとBを表示することができる。はじめからfragmentを使っているなら、あとで異なるフォームファクタへ変更する事が簡単になる。
225 |
226 | - **スクリーン間のコミニケーションについて。** AndroidはActivity間の通信として複雑なデータ(たとえばJava Object)を送るAPIを提供していない。Fragmentであれば、その子Fragment間の通信経路としてActivityのインスタンスを使う事ができる。とはいえ、[Otto](https://square.github.io/otto/)や[greenrobot-EventBus](https://github.com/greenrobot/EventBus)を使ってEventBusを使いたいと思うだろう。他のライブラリの追加を避けたい場合はRxJavaを用いてEventBusを実装する事も可能である。
227 |
228 | - **FragmentはUIだけじゃなくても十分につかえる。** ActivityのbackgroundワーカとしてfragmentをUIなしでもつこともできる。Activityにロジックを持たせる代わりに、[複数のfragmentを変更するロジックを持ったfragmentを作ることも可能である](http://stackoverflow.com/questions/12363790/how-many-activities-vs-fragments/12528434#12528434)。
229 |
230 | - **FragmentからActionBarを管理できる。** ActionBarを管理するだけのUIを持っていないFragmentをもっても良いし、また現在表示されているFragmentにActionBarの振る舞いをまかせても良い。詳しくは[こちら](http://www.grokkingandroid.com/adding-action-items-from-within-fragments/)を参考にしてほしい。
231 |
232 | [matryoshka bugs](http://delyan.me/android-s-matryoshka-problem/)が起きるので、[Fragmentを大規模にネスト](https://developer.android.com/about/versions/android-4.2.html#NestedFragments)すべきではない。例えば、横スライドするViewPagerをもったfragmentのなかに表示するfragmentといった理にかなったケースもしくは十分に考えられている場合のみ使用すべきである。
233 |
234 | 設計レベルの話をすると、アプリは一つのトップレベルのActivityを持つべきである。他のActivityは[`Intent.setData()`](http://developer.android.com/reference/android/content/Intent.html#setData(android.net.Uri))や[`Intent.setAction()`](http://developer.android.com/reference/android/content/Intent.html#setAction(java.lang.String))などで簡単に遷移でき、メインのActivityをサポートするくらいにすると良い。
235 |
236 | ### Java package 構成
237 |
238 | Androidにおける設計はおおよそ[Model-View-controller](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller)である。[Androidにおいては、FragmentとActivityがControllerに相当する](http://www.informit.com/articles/article.aspx?p=2126865)が、一方で、これらは明らかにユーザインターフェイスであり、Viewでもある。
239 |
240 | 以上のことから、FragmentまたはActivityを厳格にControllerかViewかに分類する事は難しい。そのため分類せずにfragmentは`fragments`というパッケージに納めると良い。Activityはトップレベルのパッケージに置いても良いが、もし2つ3つ以上あるなら`activities`というパッケージを作ると良い。
241 |
242 | その他は典型的なMVCだ。`models`パッケージはAPIレスポンスをJSONパースした結果のPOJOを入れ、`views`にはカスタムView,Notifications,ActionBar View, ウィジェットなどを配置する。Adapterはviewとデータの間にいるので微妙だが、`getView()`メソッドからViewを生成する必要がよくあるので、`views`パッケージのサブパッケージとして`adapters`を作りそこに配置すると良い。
243 |
244 | アプリ内で多様に使われAndroidシステムに密接なコントローラクラスは`managers`パッケージへ、各Dataを混ぜこぜにつかうDataUtilのようなクラスは`utils`へ、バックエンドとインタラクティブに反応するクラスは`network`パッケージに配置しよう。
245 |
246 | バックエンドに最も近いところからユーザに最も近いところへという順で並べると下記のような構成になる。
247 |
248 | ```
249 | com.futurice.project
250 | ├─ network
251 | ├─ models
252 | ├─ managers
253 | ├─ utils
254 | ├─ fragments
255 | └─ views
256 | ├─ adapters
257 | ├─ actionbar
258 | ├─ widgets
259 | └─ notifications
260 | ```
261 |
262 | ### Resources
263 |
264 | **命名規則について。**
265 | たとえば、`fragment_contact_details.xml`, `view_primary_button.xml`, `activity_main.xml`といったように、`type_foo_bar.xml`というタイプを接頭辞とする慣習に従おう。
266 |
267 | **Layout xmlを整理しよう。**
268 | もしLayout xmlのフォーマット方法が不明確なら下記の慣習が役立つと思われる。
269 |
270 | - 1 attribute につき 1 lineでインデントは4スペース
271 | - `android:id`は常に一番始めに
272 | - `android:layout_****`は上に
273 | - `style`は一番下
274 | - attributeを追加しやすいように`/>`のみで1 line
275 | - `android:text`をハードコーディングするよりは、[Designtime attributes](http://tools.android.com/tips/layout-designtime-attributes)を使う事を考えた方が良い
276 |
277 | ```xml
278 |
279 |
286 |
287 |
295 |
296 |
297 |
298 |
299 | ```
300 |
301 | 大雑把に言うと、`android:layout_****`はLayout xmlで定義して、それ以外の`android:****`はStyle xmlの中で定義すると良い。下記を除くと大抵この方法でうまくいく。
302 |
303 | - `android:id`は確実にLayout xml内に
304 | - LinearLayoutの'android:orientation`はLayout xml内に
305 | - `android:text`はLayout xmlに
306 | - 時々Style xmlに`android:layout_width`と`android:layout_height`を定義してうまく行く事がある。(しかし、デフォルトではこれらはlayout filesの中にある)
307 |
308 | **Styleを使おう。**
309 | Viewに統一感を持たせる為にStyleを適切に使う必要がある。Viewが繰り返し出ることはよくあることだからだ。少なくとも下記のようにText用のStyleは持っておいた方が良い。
310 |
311 | ```xml
312 |
316 | ```
317 |
318 | このスタイルはTextViewで下記の用に使う事ができる。
319 |
320 | ```xml
321 |
327 | ```
328 |
329 | 同じことをボタンにもする必要があるが、そこで終わりにせず、関連性のあるまたは繰り返されたグループを移動して、`android:****`を共通のStyleに書き出そう。
330 |
331 | **大きなStyle Fileを避け、複数に分けよう。**
332 | 1つの`styles.xml`だけを持つ事は止めた方が良い。styleファイルは`style_home.xml`、`style_item_details.xml`、`styles_forms.xml`と言ったように複数持つ事ができる。`res/values`の中のファイル名は任意である。
333 |
334 | **`color.xml`はカラーパレットである。**
335 | colors.xmlは色の名前で定義しよう。下記のように各ボタンによって定義するといったようなことはすべきじゃない。
336 |
337 | *下記は良くない例。*
338 |
339 | ```xml
340 |
341 | #FFFFFF
342 | #2A91BD
343 | #5F5F5F
344 | #939393
345 | #FFFFFF
346 | #FF9D2F
347 | ...
348 | #323232
349 | ```
350 |
351 | こういう書き方をしてしまうと基本色を変更する場合などに対応しづらい。"button"や"comment"といった内容はbutton styleで定義すればよく、`colors.xml`の中に定義すべきではない。
352 |
353 | `colors.xml`は下記のように定義しよう。
354 |
355 | ```xml
356 |
357 |
358 |
359 | #FFFFFF
360 | #DBDBDB
361 | #939393
362 | #5F5F5F
363 | #323232
364 |
365 |
366 | #27D34D
367 | #2A91BD
368 | #FF9D2F
369 | #FF432F
370 |
371 |
372 | ```
373 |
374 | nameは色の名前でなく"brand_primary", "brand_secondary", "brand_negative"などとしても良い。そうする事で色の変更がしやすくなり、またどれだけの色が使われているかがわかりやすい。通常、きれいなUIの為には使用する色を減らす事も重要だ。
375 |
376 | **dimens.xmlもcolors.xmlのように扱おう。**
377 | 典型的なスペースやフォントサイズをcolors.xmlのパレットのように定義しよう。下記は良い例である。
378 |
379 | ```xml
380 |
381 |
382 |
383 | 22sp
384 | 18sp
385 | 15sp
386 | 12sp
387 |
388 |
389 | 40dp
390 | 24dp
391 | 14dp
392 | 10dp
393 | 4dp
394 |
395 |
396 | 60dp
397 | 40dp
398 | 32dp
399 |
400 |
401 | ```
402 |
403 | marginやpaddingをハードコードするのではなく、`spacing_****`を使用するようにしよう。そうする事で簡単に全体に統一感を持たす事ができ、また整理も簡単にできる。
404 |
405 | **Viewの深いネストは止めよう。**
406 | 下記のようにLinearLayoutを組み合わせてViewを作ろうとすることがある。
407 | そうするとLayout xmlは下記のようになる。
408 |
409 | ```xml
410 |
415 |
416 |
419 |
420 |
423 |
424 |
427 |
428 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 | ```
441 |
442 | もし、一つのLayout ファイルに書いていなくてもJava側でinflateした際に同じ状況になる事もあり得る。
443 |
444 | これはいくつかの問題起こす。まずはきっとあなたも経験しただろう、UIの煩雑さによるパフォーマンス低下の問題である。他にも深刻な[StackOverFlow](http://stackoverflow.com/questions/2762924/java-lang-stackoverflow-error-suspected-too-many-views)を起こす可能性もある。
445 |
446 | 以上の理由から、Viewの階層はなるべくフラットにするべきである。そのために[RelativeLayout](https://developer.android.com/guide/topics/ui/layout/relative.html)の使い方、[Layoutの最適化](http://developer.android.com/training/improving-layouts/optimizing-layout.html)の方法、[\タグ](http://stackoverflow.com/questions/8834898/what-is-the-purpose-of-androids-merge-tag-in-xml-layouts)の使い方を知っておこう。
447 |
448 | **WebViewの参照問題に気をつけよう。**
449 | 例えばNewsの記事などのweb pageを表示する必要がある場合、クライアントサイドでHTMLを整形する事は止めた方が良い。HTMLはバックグラウンドプログラマに用意してもらおう。また[WebViewはActivityの参照を持つときにメモリリークしうる](http://stackoverflow.com/questions/3130654/memory-leak-in-webview)。Activityの代わりにApplicationContextを使用しよう。単純なテキストやボタンを表示するのにTextViewやButtonではなくWebViewを使用する事も避けた方がいい。
450 |
451 |
452 | ### テストフレームワーク
453 |
454 | Android SDKのテストフレームワークは特にUIテストにおいてまだまだ未熟なところがある。
455 | Android Gradleに、あなたがAndroidのJUnitのヘルパーを使って書いたJUnitのテストを走らせる[connectedAndroidTest](http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Testing)がある。これはdeviceもしくはemulatorをつなぐ必要がある。次のテストガイドを見ておこう。[\[1\]](http://developer.android.com/tools/testing/testing_android.html) [\[2\]] (http://developer.android.com/tools/testing/activity_test.html)
456 |
457 | **viewを使わないUnitテストには[Robolectric](http://robolectric.org/)を使おう。**
458 | このテストフレームワークはデバイスにつなぐ必要がないため開発効率があがる。UIのテストには向いていないがモデルとViewモデルのテストに適している。
459 |
460 | **[Robotium](https://code.google.com/p/robotium/)は簡単にUIテストを作る事ができる。**
461 | このテストフレームワークにはViewの取得、解析する為のヘルパーメソッド、スクリーンをコントロールする為のヘルパーメソッドが多く用意されている。テストケースも下記のようにシンプルに書く事ができる。
462 |
463 | ```java
464 | solo.sendKey(Solo.MENU);
465 | solo.clickOnText("More"); // searches for the first occurence of "More" and clicks on it
466 | solo.clickOnText("Preferences");
467 | solo.clickOnText("Edit File Extensions");
468 | Assert.assertTrue(solo.searchText("rtf"));
469 | ```
470 |
471 | ### Emulator
472 |
473 | Androidアプリを専門で開発していくなら[Genymotion emulator](http://www.genymotion.com/)のライセンスは買っておいた方が良い。Genymotionは通常のAVD Emulatorよりも早い。またアプリのデモ、ネットワーク接続品質のエミュレート、GPS、などなどを行う為のツールがそろっている。
474 | テストはたくさんの端末で行わなければならないが、実際にたくさんの端末を買うよりはGenymotionのライセンスを買う方がコスパが良い。
475 |
476 | 注: GenymotionはGoogle Play StoreやMapなどがインストールされていない。またSumsungの特定のAPIをテストしたい場合は、実際のSumsungの端末を使う必要がある。
477 |
478 | ### Proguardの設定
479 |
480 | [ProGuard](http://proguard.sourceforge.net/)はAndroid Projectでコードを圧縮、難読化するために使われる。
481 |
482 | Proguardを使用するか否かはプロジェクトの設定に依る。通常リリースapkをビルドする際にProguardを使う場合gradleを下記のように設定する。
483 |
484 | ```groovy
485 | buildTypes {
486 | debug {
487 | runProguard false
488 | }
489 | release {
490 | signingConfig signingConfigs.release
491 | runProguard true
492 | proguardFiles 'proguard-rules.pro'
493 | }
494 | }
495 | ```
496 |
497 | どのコードを保存し、どのコードを捨て難読化するかをを明確に示さなければならない。デフォルトの設定では`SDK_HOME/tools/proguard/proguard-android.txt`を使用する。また`my-project/app/proguard-rules.pro`に定義する事でデフォルトのものに追加することができる。
498 |
499 | ProGuard関連のよくある問題でビルドが成功したにもかかわらず、アプリの起動で`ClassNotFoundException`や`NoSuchFieldException`などのExceptionを発生してアプリがクラッシュすることがある。これは以下の二つのどちらかを意味する。
500 |
501 | 1. ProGuardが必要なクラス、enum、関数、フィールド、アノテーションを削除してしまった。
502 | 2. リフレクションなどを使っており難読化によってリネームされたクラスへの参照ができない。
503 |
504 | もしあるオブジェクトが削除されている疑いがあるなら`app/build/outputs/proguard/release/usage.txt`を確認しよう。オブジェクトの難読化結果を見るなら`app/build/outputs/proguard/release/mapping.txt`を確認しよう。
505 |
506 | 必要なクラスや関数の削除を防ぐには`keep`オプションをproguard configに追加しよう。
507 | ```
508 | -keep class com.futurice.project.MyClass { *; }
509 | ```
510 |
511 | 難読化を防ぐには`keepnames`を使う。
512 | ```
513 | -keepnames class com.futurice.project.MyClass { *; }
514 | ```
515 |
516 | サンプルとして[こちら](https://github.com/futurice/android-best-practices/blob/master/templates/rx-architecture/app/proguard-rules.pro)を確認しよう。また[Proguard](http://proguard.sourceforge.net/#manual/examples.html)も読んでおくと良い。
517 |
518 | **Tip**
519 | リリースするたびに`mapping.txt`を保存しておこう。ユーザがバグを踏み、難読化されたスタックトレースを送ってきた際にデバッグする事ができる。
520 |
521 | **DexGuard**
522 | さらに最適化され、さらに難読化されたものを考えるならDexGuardの採用を考えよう。DexGuardはProGuardを作った同じチームが開発している商用のものである。さらにDexGuardなら簡単にDexファイルを分割し65k制限を解決する。
523 |
524 | ### Thanks to
525 |
526 | Antti Lammi, Joni Karppinen, Peter Tackage, Timo Tuominen, Vera Izrailit, Vihtori Mäntylä, Mark Voit, Andre Medeiros, Paul Houghton and other Futurice developers for sharing their knowledge on Android development.
527 |
528 | ### License
529 |
530 | [Futurice Oy](www.futurice.com)
531 | Creative Commons Attribution 4.0 International (CC BY 4.0)
532 |
533 |
534 | Translation
535 | ===========
536 |
537 | Translated to Japanese (`ja`) by **Shinnosuke Kugimiya, Aska Kadowaki**.
538 |
539 | Original content by [Futurice Oy](http://www.futurice.com).
540 |
541 |
--------------------------------------------------------------------------------