Bài 62: Cách đưa định dạng JSon về Java class bằng GSon (tiếp 1)

[polldaddy poll=9764234]

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 bài này Tui sẽ hướng dẫn các bạn cách đưa 1 định dạng JSon phức tạp qua Java class, chẳng hạn như cấu trúc sau http://graph.facebook.com/taylorSwift :

android_62_0Bạn quan sát ở trên thì tổng cộng có 3 cặp ngoặc nhọn.

Ngoặc nhọn ngoài cùng chính là lớp FaceBook mà ta đã tạo, 2 cặp nhọn bên trong là 2 thuộc tính có kiểu đối tượng của lớp FaceBook. Như vậy ta phải tạo thêm 2 class bên trong, thông thường ta sẽ tạo lớp với quy tắc là giống tên thuộc tính có kiểu đối tượng nhưng các Ký Tự đầu của mỗi từ viết Hoa. Ví dụ:

android_62_1Ở trên là ta tạo 1 class tên Cover, nhớ là C viết hoa. Còn thuộc tính cover thì nằm trong class FaceBook có kiểu Cover.

Phân tích cấu trúc JSon của Taylor Swift, giả sử trong lớp FaceBook Tui chỉ quan tâm các thuộc tính sau:

id (có kiểu chuỗi)

username (có kiểu chuỗi)

name (có kiểu chuỗi)

gender(không có trong JSon của Taylor Swift)

likes (có kiểu số)

cover (có kiểu Cover)

+ Phân tích Cover giả sử Tui Tui chỉ quan tâm tới cover_id, source (là hình ảnh đại diện):

cover_id

source

ví dụ bạn copy toàn bộ giá trị của source sẽ có hình sau(ta sẽ coding để hiển thị lên Client android):

android_62_2–> Tương tự như vậy bạn có thể suy luận nếu như có sự chồng lắp (lồng ghép) các cặp ngoặc nhọn để biết cách tạo class.

*Bây giờ bạn mở Project của bài 61 lên rồi chỉnh sửa coding:

android_62_3Bạn tiến hành dùng công cụ để tạo get/set giống như đã hướng dẫn ở bài trước, ta được kết quả như sau:

[code language=”java”]

package com.tranduythanh.model;

/**
* Created by drthanh on 03/04/2015.
*/
public class Cover {
private String cover_id;
private String source;

public String getCover_id() {
return cover_id;
}

public void setCover_id(String cover_id) {
this.cover_id = cover_id;
}

public String getSource() {
return source;
}

public void setSource(String source) {
this.source = source;
}
}

[/code]

– Kế đến chỉnh sửa class FaceBook giống như mô tả:

android_62_4Ở trên Tui bổ sung thêm 2 thuộc tính là likes và cover (chú ý là phải copy thuộc tính từ Json nhé). Tiến hành tạo get/set:

[code language=”java”]

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;
private long likes;
private Cover cover;

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;
}

public long getLikes() {
return likes;
}

public void setLikes(long likes) {
this.likes = likes;
}

public Cover getCover() {
return cover;
}

public void setCover(Cover cover) {
this.cover = cover;
}
}

[/code]

– Ta có thể xem mô hình mối quan hệ giữa 2 lớp này như sau:

android_62_14– Tiếp theo hiệu chỉnh Layout của ứng dụng để hiển thị thêm thông tin likescover.

android_62_5Ở trên Tui bổ sung thêm Số lượng like vào giao diện + ScrollView trong trường hợp màn hình nhỏ thì nó có thể trượt xuống để xem hết thông tin.

XML layout của màn hình được sửa lại như sau:

[code language=”xml”]

<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">
<ScrollView
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
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>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="số lượng like:"
android:id="@+id/textView5" />

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

<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>
</ScrollView>
</LinearLayout>

[/code]

-Như vậy trong MainActivity ta sẽ bổ sung thêm đối tượng EditText like để hiển thị số lượng like:

EditText txtLike;

public void addControls()
    {
      //…
        txtLike= (EditText) findViewById(R.id.txtLike);
    }

protected void onProgressUpdate(FaceBook… values) {
            super.onProgressUpdate(values);
            //…….
            txtLike.setText(fb.getLikes()+””);
        }

-Đồng thời bổ sung thêm biến lưu trữ source để xem hình ảnh:

String source=””;

protected void onProgressUpdate(FaceBook… values) {
super.onProgressUpdate(values);
//………………..
txtLike.setText(fb.getLikes()+””);
     if(fb.getCover()!=null)
                source=fb.getCover().getSource();
}

– Để hiển thị hình ảnh ta cần có 1 Activity mới (dùng đa tiến trình để hiển thị hình ảnh), ta cần viết sự kiện cho nút Xem hình ảnh trong MainActivity (dùng Intent để truyền source qua màn hình xem hình ảnh).

Các bước làm như sau:

Bước 1: Bấm chuột phải vào Package/ chọn New/ chọn Activity/ chọn Blank Activity:

android_62_6– Ở màn hình mới này ta đặt tên XemHinhActivity:

android_62_7Bấm Finish để xác nhận tạo Activity mới, ta sẽ thấy nó xuất hiện như dưới đây:

android_62_8Kế đến ta vào AndroidManifest để coi thử activity XemHinhActivity có được tự động đưa vào đây hay chưa (nếu chưa đưa vào thì chạy lên sẽ báo lỗi, vì android yêu cầu bất kỳ Activity nào muốn thực thi thì phải được khai báo trong Manifest).:

android_62_9Bước 2: Tiếp theo ta hiệu chỉnh Layout XemHinhActivity để hiển thị hình ảnh, XML layout đơn giản như sau:

[code language=”xml”]

<RelativeLayout 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="com.tranduythanh.facebooktool.XemHinhActivity">

<ImageView
android:id="@+id/imgShow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher" />

</RelativeLayout>

[/code]

-Bước 3: Tiến hành tạo một ImageLoadTask kế thừa từ AsyncTask để hiển thị hình ảnh lên giao diện bằng đa tiến trình:

android_62_11Source code ImageLoadTask:

[code language=”java”]

package com.tranduythanh.facebooktool;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.widget.ImageView;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

/**
* Created by drthanh on 03/04/2015.
*/
public class ImageLoadTask extends AsyncTask&lt;Void, Void, Bitmap&gt; {

//Link url hình ảnh bất kỳ
private String url;
//Control ImageView bất kỳ
private ImageView imageView;

public ImageLoadTask(String url, ImageView imageView) {
this.url = url;
this.imageView = imageView;
}

@Override
protected Bitmap doInBackground(Void… params) {
try {
//Tiến hành tạo đối tượng URL
URL urlConnection = new URL(url);
//Mở kết nối
HttpURLConnection connection = (HttpURLConnection) urlConnection
.openConnection();
connection.setDoInput(true);
connection.connect();
//Đọc dữ liệu
InputStream input = connection.getInputStream();
//Tiến hành convert qua hình ảnh
Bitmap myBitmap = BitmapFactory.decodeStream(input);
return myBitmap;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

@Override
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
//lấy kết quả hiển thị lên giao diện:
imageView.setImageBitmap(result);
}

}

[/code]

-Bước 4: Tiến hành coding cho XemHinhActivity:

[code language=”java”]

package com.tranduythanh.facebooktool;

import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ImageView;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class XemHinhActivity extends ActionBarActivity {
ImageView imgView;
String source=&quot;&quot;;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_xem_hinh);
imgView=(ImageView) findViewById(R.id.imgShow);
//Lấy Intent từ MainActivity
Intent in= getIntent();
//Lấy link hình ảnh ra được truyền từ MainActivity
source=in.getStringExtra(&quot;URL_IMG&quot;);
}

@Override
protected void onResume() {
super.onResume();
new ImageLoadTask(source, imgView).execute();
}

@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_xem_hinh, 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);
}

}

[/code]

– Bước 5: Hiệu chỉnh MainActivity để truyền source qua XemHinhActivity để hiển thị lên giao diện:

public void addEvents()
{
btnShowImage.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
Intent in=new Intent
(MainActivity.this, XemHinhActivity.class);
in.putExtra(“URL_IMG”, source);
startActivity(in);
}
});
}

Cuối cùng ta có coding của MainActivity như sau:

[code language=”java”]

package com.tranduythanh.facebooktool;

import android.content.Intent;
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,txtLike;
RadioButton radMale,radFemale;
Button btnDownloadInfor,btnShowImage;
String source=&quot;&quot;;
@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(&quot;http://graph.facebook.com/taylorswift&quot;);
txtLike= (EditText) findViewById(R.id.txtLike);
}

/**
* 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();
}
});
btnShowImage.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
Intent in=new Intent
(MainActivity.this, XemHinhActivity.class);
in.putExtra(&quot;URL_IMG&quot;, source);
startActivity(in);
}
});
}

/**
* 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()+&quot;&quot;);
}
private  class DownloadTask extends AsyncTask&lt;String,FaceBook,Void&gt;
{
@Override
protected void onPreExecute() {
super.onPreExecute();
Toast.makeText(MainActivity.this,&quot;Chuẩn bị tải Facebook&quot;,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(),&quot;UTF-8&quot;);
//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);
txtLike.setText(fb.getLikes()+&quot;&quot;);
if(fb.getCover()!=null)
source=fb.getCover().getSource();

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

@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
Toast.makeText(MainActivity.this, &quot;Tải Facebook thành công&quot;, 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);
}
}

[/code]

– Bây giờ tiến hành thực thi ứng dụng ta được kết quả như sau: android_62_12-Ở hình trên ta thấy khi bấm vào nút Xem Hình ta sẽ có kết quả là hình Taylor Swift được hiển thị lên ở màn hình mới.

– Nếu bạn muốn hình ảnh nằm trên màn hình Nằm ngang:

android_62_13Thì tiến hành hiệu chỉnh trong AndroidManifest:

[code language=”xml”]

<activity
android:name=".XemHinhActivity"
android:label="@string/title_activity_xem_hinh"
android:screenOrientation="landscape"
>
</activity>

[/code]

-Chú ý là trong Android Studio nếu bạn lỡ tay đặt sai tên Class mà bạn muốn đặt lại thì chọn File đó rồi nhấn Shift+F6 để hiệu chỉnh nhé(trong eclipse cũ là F2).

– Như vậy bạn đã biết cách chuyển định dạng JSon phức tạp (đối tượng chứa đối tượng) thành Java class, đồng thời ôn lại được đa tiến trình cũng như Intent.

-Chú ý là phải tham chiếu tới thư viện gson-2.2.4.jar nhé.

– Bài kế tiếp Tui sẽ hướng dẫn các bạn cách chuyển JSon phức tạp hơn qua Java class (Đối tượng chứa đối tượng và danh sách đối tượng khác- mảng)

-Bạn có thể tải coding đầy đủ của bài này ở đây: http://www.mediafire.com/download/sijdct656vavk8u/FaceBookTool_version2.rar

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