Bài 61: Cách đưa định dạng JSon về Java class bằng GSon


bài 51 Tui đã trình bày cách xử lý JSon trong Android, nhưng nó là cách tiếp cận cũ và cũng được viết bằng Eclipse cũ. Trong bài này Tui muốn trình bày cho các bạn một cách tiếp cận mới đó là đưa định dạng JSon về Java class để dễ xử lý cũng như tăng tốc quá trình truy suất và sửa lỗi. Các bài mới Tui sẽ lồng ghép từng bước cách xử dụng luôn công cụ Android Studio để các bạn tiện thể sử dụng (nói theo ngôn ngữ của bác Hoàng Phi Hồng là Nhất tiễn hạ song điêu).

Tui sẽ dùng Facebook Graph của anh Nguyễn Hoàng Phong (http://graph.facebook.com/nguyen.hoangphong.50) để phân tích cấu trúc của JSon, sau đó ta sẽ viết class để chuyển đổi.

Bài này Tui sẽ đưa ra một vài ví dụ từ dễ lên khó đủ để bao quát hết cách xử lý các trường hợp trong định dạng JSon qua Java class. Trước tiên ta phân tích http://graph.facebook.com/nguyen.hoangphong.50 xem bên trong nó có cái gì?

android_61_0Ở trên ta thấy dữ liệu được để trong cặp ngoặc nhọn {}, Bên trong nó có 8 dòng ngăn cách bởi dấu phẩy, và mỗi dòng lại được ngăn cách bởi dấu hai chấm :

Đó chính là định dạng JSon được đề cập trong bài 51 (Nhớ đọc lại lý thuyết về JSon trong bài 51 này).

Ta để ý rằng tại mỗi dòng thì vế trái của dấu 2 chấm chính là thuộc tính của đối tượng, vế phải chính là giá trị của thuộc tính, giá trị vế phải nó quyết định tới kiểu dữ liệu của thuộc tính. Ví dụ:

id“:”100003307875109” thì:

id là thuộc tính và 100003307875109 là giá trị có kiểu chuỗi của thuộc tính id vì 100003307875109 nằm trong nháy đôi–> suy ra thuộc tính id sẽ khai báo kiểu String. Tương tự cho các thuộc tính khác, giờ Tui sẽ làm ví dụ để biến định dạng JSon này thành Java class để dễ tương tác, sau đó sẽ có những bài phức tạp hơn có sự lồng ghép lung tung trong JSon gốc (Ta sẽ đi từ từ, không cần nóng vội).

– Tạo một Project tên là FaceBookTool (các bước tạo project đã được trình bày ở bài trước, nếu bạn nào chưa biết thì xem lại bài 59). Chú ý là package trong ví dụ này bạn đặt tùy ý nhé, đặt sao mang tính gợi nhớ và có ý nghĩa. Bạn sử dụng package nào thì các hướng dẫn ở dưới bạn sẽ theo package bạn đã đặt tên chứ không phải giống như Tui đặt bên dưới nhé.

android_61_1Tiếp theo ta tạo một package tên là “com.tranduythanh.model” để lưu trữ class Java dành cho JSon.

Để cho lẹ thì ta bấm chuột phải vào java/chọn new/chọn Package như hình dưới đây:

android_61_2Màn hình yêu cầu chọn nơi lưu trữ hiện thị xuất hiện, ta nhấn nút OK:

android_61_3Sau khi bấm OK, màn hình yêu cầu nhập tên Package xuất hiện, ta nhập tên package rồi nhấn nút OK:

android_61_4Ở trên Tui đặt com.tranduythanh.model với mục đích tạo ra sub model để lưu trữ Class dành cho định dạng JSon.

Sau khi bấm OK, ta quan sát cấu trúc hiển thị package bị thay đổi như sau:

android_61_5– Bây giờ ta tiến hành tạo 1 class tên là FaceBook nằm bên trong model(bạn đặt tên gì cũng được, miễn sao nó đại diện đủ ý nghĩa cho cấu trúc JSon, trong trường hợp này là http://graph.facebook.com/nguyen.hoangphong.50).

Tất cả dữ liệu trong định dạng JSon mà nằm trong cặp ngoặc nhọn thì đó chính là 1 Đối tượng (Object)–> cần có 1 class cho nó, các thuộc tính bên trong JSon–> thuộc tính trong class Java:

android_61_6– Bây giờ ta bấm chuột phải vào model/ chọn New / Java Class:

android_61_7Màn hình new class hiển thị ra:

android_61_8Trong mục Name, Ta đặt tên class là FaceBook rồi nhấn nút OK.

Mặc định ta có kết quả như sau:

android_61_9Bây giờ ta tiến hành khai báo các thuộc tính trong định dạng JSon cho Java class này, có 2 chú ý bạn cần rõ là:

-Bạn chú ý là không nhất thiết phải lấy hết các thuộc tính trong JSon để khai báo trong này mà những thuộc tính nào bạn cần truy suất thì mới khai báo mà thôi.

-Trong JSon thuộc tính tên nó như thế nào thì bạn phải copy paste y xì như vậy vào Java class.

Tức là ta có như sau:


package com.tranduythanh.model;

/**
 * Created by drthanh on 02/04/2015.
 */
public class FaceBook {
    private String id;
    private String name;
    private String gender;
    private String username;
}

Bạn thấy đấy ở trên Tui chỉ muốn truy suất id, name, genderusername. Còn các thuộc tính first_name, last_name, link, locale Tui không muốn truy suất thì Tui không phải báo ở đây.

Tiếp theo ta tạo các phương thức get,set cho class Facebook. Dùng tool mà Android Studio hỗ trợ cho lẹ.

Trong class FaceBook, ta nhấn tổ hợp phím Alt + Insert hoặc vào menu code/ chọn Generate…:

android_61_10Ở trên Tui tạo Getter và Setter nên Tui chọn Getter and Setter, nếu muốn chọn constructor thì bạn chọn Constructor… Khi bạn click chuột hoặc enter vào chức năng nào thì nó tạo cho bạn. Ví dụ Tui chọn Getter and Setter thì màn hình chọn thuộc tính để tạo Getter và Setter như sau:

android_61_11Ở màn hình trên nếu bạn muốn tạo đồng loạt cho tất cả thuộc tính thì nhấn tổ hợp phím Ctrl +A cho lẹ, còn muốn chọn rời rạc thì đề Ctrl rồi nhấn chuột từng thuộc tính —> sau đó nhấn OK để tạo, bạn sẽ thấy kết quả:


package com.tranduythanh.model;

/**
* Created by drthanh on 02/04/2015.
*/
public class FaceBook {
private String id;
private String name;
private String gender;
private String username;

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getName() {
return name;
}

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

public String getGender() {
return gender;
}

public void setGender(String gender) {
this.gender = gender;
}

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}
}

– Như vậy ta đã tạo xong Java class để lưu trữ thông tin chuyển đổi từ định dạng JSon của Facebook.

– Tiếp theo bạn tải thư viện Gson ở đây : https://google-gson.googlecode.com/files/google-gson-2.2.4-release.zip

Giải nén ra trong đó có 3 tập tin thì bạn chọn 1 tập tin là gson-2.2.4.jar.

android_61_12Project Android Studio của mình sẽ tham chiếu tới thư viện này. Cách tham chiếu như sau:

– Trước tiên chuyển qua chế độ xem Project:

android_61_13– Bạn tìm tới thư mục libs rồi copy thư viện đó vào đây như sau:

android_61_14– Sau khi copy xong ta phải tham chiếu tới nó mới được, tham chiếu bằng mở màn hình Project Structer lên (có nhiều cách mở và đặc biệt là mở ở chế độ view nào cũng được: Android, Project.. đều được):

+ Cách 1: Nếu đang chọn tên Project thì nhấn phím F4 ngay và luôn

+ Cách 2: Bấm chuột phải vào vị trí bất kỳ trong Project/ chọn Open Module Settings

android_61_15

+Cách 3: Vào Menu File/ chọn Project Structer…

android_61_16==> Cả 3 cách trên ta đều có Màn hình Cấu hình Project như sau:

android_61_17– Bạn bấm vào mục số 1 trước

– Sau đó ở mục số 2 chọn Dependencies

– Tiếp theo nhấn vào hình dấu + ở mục số 3:

android_61_18Ta sẽ chọn File dependency (nó bắt di chuyển phím mũi tên lên xuống để chọn, muốn xác nhận thì phải nhấn phím Enter không dùng chuột):

android_61_19Ta tìm tới đúng nơi lưu trữ thư viện rồi bấm ok. ta được kết quả như sau:

android_61_20Tiếp tục bấm OK 1 lần nữa nha, nếu bấm cancel thì làm lại từ đầu.

Sau đó nếu như Android studio chưa phải ở chế độ Android thì nhớ chuyển về Android để lập trình cho dễ (vì bước mở Cấu trình Project ở trên có thể mở ở bất kỳ chế độ xem nào nên khi lập trình phải chuyển qua Android).

Ta có thể xem nơi khai báo lưu trữ để biên dịch thư viện trên nằm ở đâu:

android_61_21– Bây giờ các bạn tiến hành thiết kế giao diện để lấy thông tin từ 1 facebook bất kỳ về android client như sau: android_61_22-Tui chụp cấu trúc layout của giao diện trên như sau:

android_61_23Bạn có thể nhìn vào nhóm Component Tree để kéo thả các control cho phù hợp. Cách thiết kế cũng tương tự như trong Eclipse cũ nên Tui không giải thích kỹ chỗ này. Tuy nhiên lần đầu tạo layout thì nó mặc định là ReletavieLayout, bạn nhớ vào tab Text trong mục Control (palette) để tự sửa lại thành LinearLayout vertical để kéo thả các control tiếp theo được dễ dàng hơn.

Nhớ đặt tên id cho các control như trong mục Component Tree.

Bạn có thể sao chép XML cho layout trên ở đây:


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"
android:orientation="vertical">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Link Facebook:"
android:id="@+id/textView"
/>

<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/txtLinkFacebook" />

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Tải về"
android:id="@+id/btnDownload"
android:layout_gravity="center_horizontal" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Id:"
android:id="@+id/textView2" />

<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/txtId" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Username:"
android:id="@+id/textView3" />

<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/txtUserName" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Name:"
android:id="@+id/textView4" />

<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/txtName" />

<RadioGroup
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_gravity="center_horizontal">

<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Nam"
android:id="@+id/radMale" />

<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Nữ"
android:id="@+id/radFemale"
android:checked="true" />
</RadioGroup>

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Xem hình"
android:id="@+id/btnShowImage"
android:layout_gravity="center_horizontal" />
</LinearLayout>

– Sau đó ta vào MainActivity để tiến hành coding. Chú ý là khi có tương tác Internet thì bắt buộc ta phải dùng kỹ thuật Đa Tiến trình để viết và phải cấp quyền sử dụng internet trong Manifest, Nếu bạn nào chưa am hiểu kỹ thuật đa tiến trình trong Android thì học tại đây:

Bài tập 34: đa tiến trình trong Android (Multi-Threading)

Bài 35 : Vẽ Button lúc Runtime, dùng Using Message của Handler class

Bài 36: Update ListView At runtime by Handler class using post

Bài 37: Xử lý đa tiến trình bằng AsyncTask

Quay lại coding trong MainActivity của ứng dụng:

 


package com.tranduythanh.facebooktool;

import android.os.AsyncTask;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.Toast;

import com.google.gson.Gson;
import com.tranduythanh.model.FaceBook;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;

public class MainActivity extends ActionBarActivity {

    EditText txtLinkFacebook,txtId,txtUserName,txtName;
    RadioButton radMale,radFemale;
    Button btnDownloadInfor,btnShowImage;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //gọi addControl trước
        addControls();
        //gọi addevent sau
        addEvents();
    }

    /**
     * hàm khởi tạo cho các Control
     */
    public void addControls()
    {
        txtLinkFacebook= (EditText) findViewById(R.id.txtLinkFacebook);
        btnDownloadInfor= (Button) findViewById(R.id.btnDownload);
        txtId= (EditText) findViewById(R.id.txtId);
        txtUserName= (EditText) findViewById(R.id.txtUserName);
        txtName= (EditText) findViewById(R.id.txtName);
        radMale= (RadioButton) findViewById(R.id.radMale);
        radFemale= (RadioButton) findViewById(R.id.radFemale);
        btnShowImage= (Button) findViewById(R.id.btnShowImage);
        txtLinkFacebook.setText("http://graph.facebook.com/nguyen.hoangphong.50");
    }

    /**
     * hàm gán sự kiện cho các control
     */
    public void addEvents()
    {
        btnDownloadInfor.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                processDownload();
            }
        });
    }

    /**
     * hàm gọi đa tiến trình để tải dữ liệu từ internet
     */
    private void processDownload() {
        DownloadTask task=new DownloadTask();
        task.execute(txtLinkFacebook.getText()+"");
    }
    private  class DownloadTask extends AsyncTask<String,FaceBook,Void>
    {
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            Toast.makeText(MainActivity.this,"Chuẩn bị tải Facebook",Toast.LENGTH_LONG).show();
        }

        @Override
        protected Void doInBackground(String... params) {
            //Lấy link facebook từ hàm processDownload truyền vào
            String link=params[0];
            try {
                URL url=new URL(link);
//              //đọc stream Json từ internet có đọc UTF8
                InputStreamReader reader=new InputStreamReader(url.openStream(),"UTF-8");
                //chuyển định dạng JSon về java class
                FaceBook fb=new Gson().fromJson(reader,FaceBook.class);
                //gửi qua onProgressUpdate để cập nhật giao diện
                publishProgress(fb);
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onProgressUpdate(FaceBook... values) {
            super.onProgressUpdate(values);
            //lấy FaceBook được truyền từ doInBackground
            FaceBook fb=values[0];
            //tiến hành đưa thông tin lên giao diện:
            txtId.setText(fb.getId());
            txtUserName.setText(fb.getUsername());
            txtName.setText(fb.getName());
            radFemale.setChecked(true);

            if(fb.getGender()!=null&& fb.getGender().equalsIgnoreCase("male"))
            {
                radMale.setChecked(true);
            }
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
            Toast.makeText(MainActivity.this, "Tải Facebook thành công", Toast.LENGTH_LONG).show();
        }
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

 

– Sau cùng ta cấp quyền sử dụng Internet:

android_61_24Bạn chú ý là version Android Studio hiện tại chưa cung cấp giao diện để cấp quyền, mà bạn phải gõ bằng lệnh trong AndroidManifest, tuy nhiên android Studio hỗ trợ chức năng gợi nhớ giúp ta dễ dàng chọn lựa:

android_61_25– Cũng tương tự như việc gợi ý sửa lỗi trong Android Studio chính là gõ tổ hợp phím Alt+Enter (bên Eclipse cũ là Ctrl+1). Vậy bạn chú ý là muốn xem gợi ý sửa lỗi nhanh thì nên gõ Alt+Enter (ta thường dùng nhiều nhất trong trường hợp Tự động Ép Kiểu , Tự động Import thư viện và tự động implement các Abstract method).

– Tới đây  là bạn đã thực hiện được việc đọc JSon từ internet và đưa nó về Java class phục vụ cho các mục đích khác.

– Bài tiếp theo Tui sẽ hướng dẫn các bạn cách chuyển JSon có định dạng phức tạp (đối tượng chứa đối tượng, đối tượng chứa danh sách đối tượng…) về Java class

– Các bạn có thể tải source code mẫu của bài này ở đây: http://www.mediafire.com/download/t4kp87nh57y8nnx/FaceBookTool.rar

– Chúc các bạn thành công!

16 responses

  1. Bài viết hay lắm thưa thầy…giúp giảm tải code Json đi nhiều…cám ơn thầy.Em có chút ý kiến là lúc add cái Gson vào mình chỉ cần click chuột phải vào cái Gson trong libs đó chọn Add as Library…là nó tự add và ép vào build.gradle.

  2. […] bài tập 61 các bạn đã được học qua cách đưa định dạng JSon cơ bản qua Java class, trong […]

  3. […] bài 61 và bài 62 các bạn đã biết cách chuyển định dạng JSon qua Java class, trong bài […]

  4. […] Bài 61: Cách đưa định dạng JSon về Java class bằng GSon […]

  5. Khi thực hiện Webservices gọi function Lay1SanPham() thì nó trả ra như sau

    {“MaSP”:”sp_1xxx”,”TenSP”:”DELL Inspiron 14NR”,”SoLuong”:100,”DonGia”:150000,”ThanhTien”:0,”Hinh”:”https://duythanhcse.wordpress.com/h1.png”}

    Có cách nào xử lý bỏ các Tag XML được không ?. Chỉ lấy giá trị nằm trong {}.

    Mong hồi âm. Thanks a lot

    1. kết quả phía trên có các tag của XML \
      {“MaSP”:”sp_1xxx”,”TenSP”:”DELL Inspiron 14NR”,”SoLuong”:100,”DonGia”:150000,”ThanhTien”:0,”Hinh”:”https://duythanhcse.wordpress.com/h1.png”}\

    2. Mình dán các Tag của XML vào đây nó mắt tiêu rồi.

      1. Em có thể chụp hình rồi gửi link!

      2. https://drive.google.com/file/d/0BzNEr9qNUWuiV1JBUERQTnAzcW8/view

        Trong hình trên có Tag {chuỗi cần lấy}

        Tôi chỉ cần lấy đoạn trong ngoặc nhọn thôi

  6. Trung Hoàngg Hoang | Reply

    sao em truy cập url trên thì không được vậy thầy?

  7. thầy ơi cho em hỏi là sao eclipse của em không tìm thấy project structure thầy ạ

  8. bài viết hay quá 😀

  9. […] Bài 61: Cách đưa định dạng JSon về Java class bằng GSon […]

  10. […] Bài 61: Cách đưa định dạng JSon về Java class bằng GSon […]

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.