Tuesday, January 17, 2017

[Java] Giới thiệu về Generic và Annotation

Chào các bạn, hôm nay mình sẽ giới thiệu về kỹ thuật Generic và Annotation trong java.
Cả hai kỹ thuật này đều được thêm vào từ Java 5.

Generic

  1. Về generic:
    1. Là một feature được thêm vào từ Java 5.0 
    2. Generic thể hiện tính trừu tượng trong Java, bản thân generic cũng có thể kế thừa hoặc được kế thùa từ một kiểu dử liệu khác. 
    3. Generic mô tả một cách trừu tượng class sẽ được sử dụng trong class hay method. 
    4. Mục đích của nó: Cung cấp tính an toàn về kiểu trong thời điểm biên dịch. 
    5. Generic được sử dụng trong: Class Generic, Method Generic,Interface Generic.
  2. Generic giúp giải quyết?

    1. Giúp bộ dịch xác minh được kiểu dữ liệu. 
    2. Bộ dịch sẽ biết chính xác cần phải ép kiểu thể nào.
Annotation:
  1. Một số bài toán:
    1. Bài toán của Hibernate: đây là một frame làm việc với database thông qua việc mapping object. Từ Java Bean phải mapping qua bảng tương ứng với database. Sau đó hibernate sẽ chuyển thành các câu lệnh SQL tương ứng và thực thi. Nhưng không phải lúc nào các trường này được ánh xạ chính xác với database nên ta phải mô tả code. 
    2. Trước khi annatotion ra đời, để biểu diễn meta data cho một class, property, method developer phải sử dụng XML, Properties, Comment. Đến java 5 Sun thêm vào cái gọi là annotation.
  2. Annotation là gì:
    1. Là một feature được thêm vào từ Java 5.0
    2. Là một dạng meta data đặc ta cho một đối tượng hoặc một method hay là một property mà bạn có thể thêm vào Java Code. 
    3. Mục đích:
      1. Chỉ dẫn cho trình compiler 
      2. Chỉ dẫn Build-time 
      3. Chỉ dẫn trong thời điểm Runtime.
  3. Annatotion: chỉ dẫn cho trình compiler?
    1. Java cung cấp sẵn một số annotation thường gặp như: 
      1. @Override 
      2. @Deprecated 
      3. @SuppressWarnings
      4. @SafeVarargs 
      5. @Documented. 
    2. Để tự tạo ra các chỉ dẫn để trình compiler có thể hiểu được thì sử dụng Annotation processing tool. (APT)
  4. Annatotion: chỉ dẫn Build-time?
    1. Annotation được sử dụng trong lúc build-time để tạo ra các mã nguồn, biên dịch mã nguồn, tạo ra các file XML. Xây dụng các tool tự động. 
    2. Ví dụ như tool Hiberate: đọc database sẽ tự động build thành các class, xml tương ứng.
    3. Thông thường sau khi biên dịch thì các annotations không có mặt trong mã Java. Tuy nhiên vẫn có thể sử dụng reflection để đọc các annotations lúc run-time. 
    4. Để làm việc nay thì thiết lập như sau: 
      1. @Retention(RetentionPolicy.RUNTIME)
Đây là 2 kỹ thuật nâng cao của Java mà bất kỹ Senior Java nào cũng phải biết. 
Hy vọng với bài viết này bạn sẽ có thể hình dung tổng quát và hiểu được khái niệm Generic và Annotation cũng như trường hợp sử dụng chúng.
Với bài viết sau, tôi sẽ có bài toán cũng như ví dụ cụ thể về 2 kỹ thuật này.

Sunday, January 15, 2017

[Swift] Sử dụng NSUserDefaults để lưu dữ liệu


Một bộ nhớ ứng dụng được tạo ra để lưu trữ dữ liệu trong ứng dụng. Điều đó có nghĩa là khi xóa ứng dụng thì bộ nhớ này sẽ mất đi. Nó được gọi là NSUserDefaults, NSUserDefaults  có thể lưu trữ các kiểu dữ liệu integers, booleans, strings, arrays, dictionaries, dates...

Nhưng hãy cần thận, nếu bạn lưu trữ quá nhiều dữ liệu sẽ ảnh hưởng đến tốc độ khi bật ứng dụng.

Để sử dụng NSUserDefaults làm như sau

let defaults = NSUserDefaults.standardUserDefaults()
defaults.setInteger(25, forKey: "Age")
defaults.setBool(true, forKey: "Gender")
defaults.setObject("Paul Hudson", forKey: "Name")
defaults.setObject(NSDate(), forKey: "LastRun")

Dữ liệu được lưu vào NSUserDefaults không bị mất đi khi bạn thoát ứng dụng.

Để lấy dữ liệu đã lưu trong NSUserDefaults ta làm như sau:

let defaults = NSUserDefaults.standardUserDefaults()
let age = defaults.integerForKey("Age")
let gender= defaults.boolForKey("Gender")
let name= defaults.objectForKey("Name")

[Design Pattern] Singleton trong java và swift


Mẫu thiết kế singleton:
Nó là gì?
Mẫu thiết kế singleton đảm bảo chỉ duy nhất môt thực thể của một class được tạo ra và nó sẽ cung cấp cho bạn một phương thức để truy cập đến thực thế đó.
Kiểm soát việc tạo ra các thực thể nhưng có thể lấy ra thực thế.
Dùng nó trong trường hợp nào?
Khi bạn tạo ra một class mà bạn chỉ muốn chỉ có duy nhất một thực thể là thể hiện của class đó và bạn có thể truy cập đến nó ở bất kỳ nơi đâu khi bạn muốn.
Ví dụ như : Khi bạn tạo ra một class làm việc với file, config ,class lưu collection dùng chung, hoặc database . Bản chỉ cần duy nhất một thực thể của class đó và bạn sẽ sử dụng nó ở bất kỳ nơi đâu.
Dùng nó như thế nào?
Đầu tiên tôi tạo ra một class với tên là Database. Để không class nào có thể khỏi tạo nó (đảm bảo duy nhất có một thực thể) tôi sẽ private contructor của class trên.
  1. In Java
  2. public class Database{
  3.     private Database();
  4. }
  5. In Swift
  6. class Database{
  7.     private init();
  8. }
Và tạo một thuộc tính có tên là INSTANCE có kiểu Database  và một phương trả về thuộc tính đó. Để các class khác có thể sử dụng phương thức này, tôi thêm từ khóa static để biến phương thức này thành phương thức của lớp.
  1. In Java
  2. private Database INSTANCE;
  3. public static Database getInstance(){
  4.    if(INSTANCE == null){
  5.       INSTANCE = new Database();
  6.    }
  7.    return INSTANCE;
  8. }
  9. In Swift
  10. var Database sharedInstance;
  11. class func getInstance() -> Database { 
  12.    if(sharedInstance == nil) { 
  13.       sharedInstance = Database() 
  14.    } 
  15.    return sharedInstance 
  16. }
Như trên tôi kiểm tra xem INSTANCE có bằng null hay không. Nếu bằng null thì tôi tạo một đối tượng. Và trả về INSTANCE.
Có một vấn đề xảy ra. Nếu có hai luồng (thread) chạy song song và thực hiện hàm if thì sẽ có 2 thực thể được tạo ra. Để tránh trường hợp này mình thêm từ khóa synchronized. Khi hàm getInstance đã được chạy thì bất kỳ các luồng khác phải đợi hàm này chạy xong mới gọi được.

  1. public static synchronized Database getInstance(){
  2.    if(INSTANCE == null){
  3.      INSTANCE = new Database();
  4.    }
  5.    return INSTANCE;
  6. }
Ok đến đây đã khá ổn nhưng sử dụng từ khóa synchronized đồng nghĩa với việc các luồng có thể phải đợi chờ lâu vì phải đợi luồng đang gọi hạm getInstance chạy xong mới gọi được. Để tránh trường hợp này, tôi sẽ tạo 1 thực thể của lớp Database ngày khi class này được sử dụng, và sử dụng từ khóa final để ngăn không cho thay đổi đối tượng mà INSTANCE trỏ đến  :

  1. In Java:
  2. private static final Database INSTANCE = new Database();
  3. In Swift
  4. static let sharedInstance = Database()
Lúc này hàm getInstance sẽ trả về đối tượng INSTANCE:
  1. In Java:
  2. public static Database getInstance(){
  3.    return INSTANCE;
  4. }
  5. In Swift
  6. class func getInstance() -> Database { 
  7.    return sharedInstance 
  8. }
Để truy cập đến thực thể của class Database bạn thực hiện : Database.getInstance() lúc này trả về 1 thực thể có kiểu Database.
Với swift ta làm như sau:

OK ! Đến đây bạn có thể chắc chắn rằng sẽ chỉ có duy nhất một thực thể của class Database được tạo ra và bạn có thể sử dụng hàm getInstance để truy cập vào thực thế đó. Việc còn lại là bạn viết các phương thức, các setter, getter cho nó. Đây chính là mẫu thiết kế singleton.

[Android] Ẩn bàn phím khi start activity (fragment)


Để ẩn bàn phím khi start một activity hoặc add fragment ta làm như sau:
Cách 1: Trong file AndroidManifest.xml add dòng sau vào activity mà bạn muốn

android:windowSoftInputMode="stateHidden"
Cách 2: Trong file giao diện xml thêm dòng sau vào view cha của editext

android:focusable="true"
android:focusableInTouchMode="true"

Done.

Thursday, January 5, 2017

Java Core - Enum Types


Enum là một kiểu dữ liệu đặc biệt, nó cho phép chứa tập hợp các biến hay còn gọi là kiểu dữ liệu liệt kê. Vậy tại sao lại có kiểu dữ liệu enum và nó sẽ giúp chúng ta như thế nào.
Mình sẽ lấy vị dụ như sau : Trong game thường có các vật phẩm tăng gold hay exp sau mỗi màn đánh. Mình định nghĩa một enum như sau :

  1. public enum EffectItem {
  2. EXP,GOLD;
  3. }
Ok vậy là ta có có một tập hợp các hiệu ứng khi sử dụng vật phẩm là tăng gold và exp. Nhưng ta vẫn chưa định nghĩa tăng bao nhiêu cả.Ta làm như sau:

  1. public enum EffectItem {
  2. EXP(20),GOLD(30);
  3.         private int value;// khai báo một biến value.

  4. EffectItem(int value) { //một contructor với tham số value
  5. this.value = value;
  6. }

  7. public int getValue() {//hàm lấy ra giá trị value
  8. return this.value;
  9. }
  10. }
Nhìn có vẻ đây là một class thực sự với thuộc tính value và contructor với đầu vào int. Còn dòng 2 như các thực thể được khởi tạo vơi các giá trị cụ thể 20,30.

Một vấn đề nữa, tôi muốn với mỗi giá trị của item ta sẽ có một mô tả tương ứng. Ta làm như sau:
  1. public enum EffectItem {
  2. EXP(20),GOLD(30);
  3.         private int value;// khai báo một biến value.

  4. EffectItem(int value) { //một contructor với tham số value
  5. this.value = value;
  6. }

  7. public int getValue() {//hàm lấy ra giá trị value
  8. return this.value;
  9. }
  10.         
  11.         public String getString() {// với mỗi giá trị của enum sẽ có mô tả tương ứng.
  12. switch (this) {
  13. case EXP:
  14. return "Tang EXP 20%";
  15. case GOLD:
  16. return "Tang EXP 30%";
  17. default:
  18. return "";
  19. }
  20. }
  21. }

Đến đây ta đã cơ bản tạo xong một enum. Vậy sử dụng nó như thế nào?
 - Vì enum là một kiểu dữ liệu vì vậy ta khai báo một thuộc tính của class cần dùng như sau:

  1. public class Item {
  2. private String name;
  3. private EffectItem effect;

  4. public Item(EffectItem effect) {
  5. this.effect = effect;
  6. }

  7. public String getName() {
  8. return name;
  9. }

  10. public void setName(String name) {
  11. this.name = name;
  12. }

  13. public EffectItem getEffect() {
  14. return effect;
  15. }

  16. public void setEffect(EffectItem effect) {
  17. this.effect = effect;
  18. }
  19. }
Sử dụng phương thức effect.getValue() để lấy ra giá trị của enum và  effect.getString() để có được mô tả.
Ngoài ra, bản thân enum có một class mô tả nó với các phương thức và thuộc tính. Ví dụ như:  values() : trả về tập 1 mảng chứa cả các giá trị của enum. Ta có thể dùng vòng foreach để duyệt.

Done. Mong bài viết sẽ có ích với các bạn :D