Kinh nghiệm với lập trình Android
Cấu trúc thư mục cho code Android
Mục này mình có tham khảo ở nhiều nguồn để ghép vào phần dự án mình đang làm. Theo mình thấy thì dự án chia cây thư mục như sau sẽ rõ ràng hơn các cách chia khác.
Android_structure
├─ gdg.lbs
│ ├─ activities
│ ├─ adapters
│ ├─ fragments
│ ├─ example
│ ├─ interfaces
│ ├─ models
│ ├─ navigates
│ ├─ networks
│ ├─ notifications
│ ├─ utils
│ └─ views
Trong đó mỗi một thành phần sẽ có một ý nghĩa riêng như sau:
Ngoài những thư mục (package) kể trên thì mình còn sử dụng thêm một vài package nữa tuy nhiên không phổ biến lắm nên mình không có liệt kê tại đây.
Sử dụng DebugLog.java thay vì Log.java
Thông thường khi muốn viêt lại log để hỗ trợ việc debug android được tốt hơn, các bạn sẽ sử dụng lớp được cũng cấp sẵn là
Log.i(String, String);
. Tuy nhiên vấn đề bạn đang gặp phải là những đoạn log này chỉ hữu ích với việc debug mà thôi. Khi sản phẩm được tung ra thị trường thì những đoạn log này vô tình lại đang làm hại chính các bạn. Vậy trong trường hợp này ta phải làm sao? Chẳng lẽ lại tìm từng chỗ viết log rồi xóa tay trước khi build?
Một gợi ý nhỏ đó là chúng ta sẽ sử dụng một biến static có tên là
IS_DEBUG
như sau:if (Config.IS_DEBUG) {
Log.i(String, String);
}
Cũng khá ổn rồi nhưng mà bây giờ mỗi lần sử dụng chẳng lẽ lại viết đi viết lại mất công quá. Chưa kể là thành viên mới vào team có khi còn quên việc phải sử dụng code như vậy nữa. Vậy nên chăng ta nên sử dụng một lớp là
DebugLog.java
như sau:public class DebugLog {
public static void i(String tag, String msg) {
if (Config.IS_DEBUG) {
Log.i(tag, msg);
}
}
}
Tốt rồi, code đã trở nên sáng sủa hơn nhiều.Thế nhưng có một vấn đề nhỏ với DebugLog.
DebugLog.i(TAG, "String: " + numberOfString);
Đoạn code trên tưởng chừng như vô hai nhưng lại khiến cho ta tốn thêm 4 bước thuật toán cộng chuỗi trong khi chuỗi mới chẳng được sử dụng nếu cờ
Chẳng có cách nào để khắc phục việc này đâu. Hãy coi đây là một cái giá phải trả cho việc quản lí dễ dàng hơn.
IS_DEBUG
được đặt bằng false
. Vậy cách giải quyết ở đây là gì nhỉ?Chẳng có cách nào để khắc phục việc này đâu. Hãy coi đây là một cái giá phải trả cho việc quản lí dễ dàng hơn.
Lưu mật khẩu signing key vào file gradle.properties
signingConfigs {
release {
storeFile file("release.keystore")
storePassword "storepassword"
keyAlias "myproject"
keyPassword "keypassword"
}
}
Sau đó bạn đẩy file này lên version control như GIT hoặc SVN. Tình cờ thế nào ai đó có quyền truy cập vào version control của bạn. Và bạn mất đi signing key, một trong những chìa khóa cốt lõi cho file apk của bạn trên GooglePlay.
Một giải pháp cho vấn đề này là chúng ta sẽ sử dụng file
Một giải pháp cho vấn đề này là chúng ta sẽ sử dụng file
gradle.properties
như sau:KEYSTORE_PASSWORD=storepassword
KEY_PASSWORD=keypassword
Và thay vì viết một kịch bản như trên, bạn có cách viết lại khác hơn nhiều:
signingConfigs {
release {
try {
storeFile file("release.keystore")
storePassword KEYSTORE_PASSWORD
keyAlias "myproject"
keyPassword KEY_PASSWORD
}
catch (ex) {
throw new InvalidUserDataException("You should define KEYSTORE_PASSWORD and KEY_PASSWORD in gradle.properties.")
}
}
}
Lúc này, chúng ta chỉ cần pull kịch bản lên version control và giữ lại password cho riêng mình.
Sử dụng thư viện Volley hoặc OkHttp thay vì tự viết một HTTP client của riêng bạn
ResponseData responseData = new ResponseData();
String data = generalRequest.toString();
if (!Utility.isNetworkConnected(mContext)) {
responseData.setStatus(Response.CLIENT_ERROR_NO_CONNECTION);
return responseReceiver.parseResponse(idLoader, responseData, requestType);
}
String url;
if (Method.POST == generalRequest.getMethod()) {
url = Config.SERVER_URL;
} else {
url = Config.IMAGE_SERVER_URL + data;
}
ContentResponse outData = sendRequest(url, generalRequest.getMethod(), data, timeoutConnect, timeoutRead);
if (outData.status == Response.CLIENT_SUCCESS) {
responseData.setStatus(Response.CLIENT_SUCCESS);
responseData.setText(outData.content);
if (requestType == RequestType.JSON && responseData.getText() != null) {
try {
responseData.makeJSONObject();
int code = getResponseCode(responseData.getJSONObject());
if (code == Response.SERVER_BLOCKED_USER || code == Response.SERVER_USER_NOT_EXIST) {
sendBroadcastHasBlockAndDeactive(code);
}
} catch (JSONException e) {
e.printStackTrace();
outData.status = Response.CLIENT_ERROR_PARSE_JSON;
responseData.setStatus(outData.status);
}
}
} else {
responseData.setStatus(outData.status);
}
if (responseReceiver == null)
return null;
return responseReceiver.parseResponse(idLoader, responseData, requestType);
Quá nhiều dòng code cho một chức năng. Chưa kể bạn còn phải quan tâm rất nhiều thứ khác nữa để tạo ra được một thư viện http tuyệt vời cho riêng bạn. Mình đã từng nếm trái đắng, siêu đắng khi tự viết một framework liên kết với raspberry pi. Tất cả mọi chuyện kết thúc khi mình chuyển qua dùng okhttp với vài ba dòng lệnh đơn giản:
public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
OkHttpClient client = new OkHttpClient();
String post(String url, String json) throws IOException {
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder().url(url).post(body).build();
Response response = client.newCall(request).execute();
return response.body().string();
}
Giữ cho file colors.xml của bạn hữu ích hơn bằng cách sử dụng bảng màu
<!-- Palette -->
<color name="primary">#FFC0392B</color>
<color name="primary_dark">#FFD32F2F</color>
<color name="primary_light">#FFFFCDD2</color>
<color name="secondary">#FF449D44</color>
<color name="secondary_light">#FF6EC02B</color>
<color name="divider">#FFB6B6B6</color>
<color name="divider_highlight">#FFFFFFFF</color>
<!-- Text view -->
<color name="icons">#FFFFFFFF</color>
<color name="secondary_text">#FFB0ADAD</color>
<color name="secondary_text_highlight">#FFDADADA</color>
<color name="primary_text">#FF595959</color>
<color name="primary_text_highlight">#FF929292</color>
Theo đó thì từng màu được định nghĩa sẽ có những ý nghĩa khác nhau như sau:
- primary: Màu chủ đạo của ứng dụng. Thông thường màu này sẽ nằm trên navigation bar, các text view làtitle của màn hình.
- primary_dark: Ít khi được dùng nhưng thường có để làm nổi bật màu primary
- primary_light: Ít khi được dùng nhưng thường có để làm nổi bật màu primary
- secondary: Màu thứ hai được dùng nhiều trong ứng dụng. Màu này sẽ nằm ở các đoạn text được highlight hoặc những vị trí thấp hơn tone màu primary
- secondary_light: Ít khi được dùng nhưng thường có để làm nổi bật màu secondary
- divider: Dành cho các vách ngăn, đường viền của các view.
- divider_highlight: Dành cho những cách ngăn nhạt màu hơn. Thường được dùng khi màu nền không phải là màu đơn sắc.
- icons: Màu chủ đạo dành cho icon, chữ nằm trên nền có màu. Thông thường toàn bộ nút trong ứng dụngsẽ sử dụng màu này.
- primary_text: Các phần chữ nội dung có tone màu chính.
- primary_text_highlight: Nhấn mạnh màu primary_text
- secondary_text: Các phần chữ nội dung có tone màu yếu hơn.
- secondary_text_highlight: Nhấn mạnh màu secondary_text
Các trường hợp tuyệt đối tránh trong colors.xml
1.Định nghĩa màu
Làm thế nào để bạn phân biệt được giữa màu xám, màu xám nhạt, màu xám nhạt hơn chút nữa?
Làm thế nào để bạn phân biệt được giữa màu xám, màu xám nhạt, màu xám nhạt hơn chút nữa?
<color name="gray">#FFDADADA</color>
<color name="gray_light">#FFDBDBDB</color>
<color name="gray_more_light">#FFDCDCDC</color>
2.Khai báo màu đã được định nghĩa trong Android
Chắc chắn là chúng ta sẽ không bao giờ định nghĩa là màu
Chắc chắn là chúng ta sẽ không bao giờ định nghĩa là màu
transparent
rồi.Hãy cho dimens.xml học theo colors.xml
Một ví dụ cho cách định nghĩa dimen:
<!-- font sizes -->
<dimen name="font_larger">22sp</dimen>
<dimen name="font_large">18sp</dimen>
<dimen name="font_normal">15sp</dimen>
<dimen name="font_small">12sp</dimen>
<!-- typical spacing between two views -->
<dimen name="spacing_huge">40dp</dimen>
<dimen name="spacing_large">24dp</dimen>
<dimen name="spacing_normal">14dp</dimen>
<dimen name="spacing_small">10dp</dimen>
<dimen name="spacing_tiny">4dp</dimen>
<!-- typical sizes of views -->
<dimen name="button_height_tall">60dp</dimen>
<dimen name="button_height_normal">40dp</dimen>
<dimen name="button_height_short">32dp</dimen>
Với cách định nghĩa này, bạn sẽ không cần phải định nghĩa quá nhiều những thông số dimen với nhau. Thông thường thì một view sẽ có kích thước tương quan với các view bên cạnh nó. Nhất là khi bạn phải thực hiện code trên nhiều kích thước thiết bị. Định nghĩa như thế này sẽ giúp bạn thu nhỏ hoặc phóng to các thành phần trong màn hình của bạn được dễ dàng hơn.
theo : http://daynhauhoc.com/
No comments: