[Android] JSon trong Android – Phần 4: Xử lý lấy JSon bằng Java

Hế lô các bạn, Dự đây sẽ là phần cuối trong loạt bài JSon trong Android. Chúng ta sẽ viết nốt code java xử lý và quan trọng nhất là lấy JSon mà chúng ta đã xuất ra từ các phần trước.

Update: 21/08/2015 – Tối ưu hóa code.

Cấu trúc java của chúng ta gồm các file sau (Do số lượng file ít nên mình không có phân thành các package).

java old lover

Viết các class cấu hình, chuẩn bị

Nói nó hơi khó hiểu nhưng thật ra là thế này. Chúng ta cần một số hằng số để lưu một số giá trị nhất định và nó nằm trong class Var. Để thao tác dễ dàng với các đối tượng “người yêu cũ” thì chúng ta cần có một class Lover. Và để lấy JSon xuống thì chúng ta cần class LoadJson làm việc đó.

Xây dựng các hằng số

package cachhoc.net.demojson;

import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.widget.Toast;

public class Var {


    // const for load and put data with server
    public static final String KEY_METHOD = "method";

    public static final String KEY_NICK = "nick";
    public static final String KEY_PASS = "pass";

    public static final String KEY_ID = "id";
    public static final String KEY_NAME = "name";
    public static final String KEY_PHONE = "phone";
    public static final String KEY_BEGIN_DATE = "begin_date";
    public static final String KEY_END_DATE = "end_date";

    public static final String KEY_LOGIN = "login";
    public static final String KEY_REGISTER = "register";
    public static final String KEY_ADD = "add";

    public static final int METHOD_LOGIN = 1;
    public static final int METHOD_REGISTER = 2;
    public static final int METHOD_GET_OLD_LOVER = 3;
    public static final int METHOD_ADD_OLD_LOVER = 4;


    public static void showToast(Context context, String sms) {
        Toast.makeText(context, sms, Toast.LENGTH_SHORT).show();
    }

    // method for save and get nick and pass user

    public static void save(Context context, String key, String value) {
        SharedPreferences.Editor editor = PreferenceManager
                .getDefaultSharedPreferences(context.getApplicationContext())
                .edit();
        editor.putString(key, value);
        editor.apply();
    }

    public static String get(Context context, String key) {
        SharedPreferences settings = PreferenceManager
                .getDefaultSharedPreferences(context.getApplicationContext());
        return settings.getString(key, null);
    }
}

Không có gì là khó hiểu, trong class này mình chỉ lưu ý là chúng ta sử dụng SharedPreferences để lưu trữ nick và pass khi người dùng muốn ghi nhớ cho lần đăng nhập sau. Và nó cũng thường dùng để lưu các cài đặt (setting) cho các ứng dụng.

Xây dựng class Lover

Lover của chúng ta sẽ có 5 trường chính là id, name, phone, begin date (ngày bắt đầu yêu) và end date (ngày chia tay).

package cachhoc.net.demojson;

import org.json.JSONException;
import org.json.JSONObject;

public class Lover {
    private int id;
    private String name;
    private String phone;
    private String beginDate;
    private String endDate;

    public Lover() {
    }

    public Lover(int id, String name, String phone, String beginDate, String endDate) {
        this.id = id;
        this.name = name;
        this.phone = phone;
        this.beginDate = beginDate;
        this.endDate = endDate;
    }

    public int getId() {
        return id;
    }

    public Lover setId(int id) {
        this.id = id;
        return this;
    }

    public String getName() {
        return name;
    }

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

    public String getPhone() {
        return phone;
    }

    public Lover setPhone(String phone) {
        this.phone = phone;
        return this;
    }

    public String getBeginDate() {
        return beginDate;
    }

    public Lover setBeginDate(String beginDate) {
        this.beginDate = beginDate;
        return this;
    }

    public String getEndDate() {
        return endDate;
    }

    public Lover setEndDate(String endDate) {
        this.endDate = endDate;
        return this;
    }

    public String toJSON() {
        JSONObject jsonObject = new JSONObject();
        try {
            jsonObject.put(Var.KEY_ID, getId());
            jsonObject.put(Var.KEY_NAME, getName());
            jsonObject.put(Var.KEY_PHONE, getPhone());
            jsonObject.put(Var.KEY_BEGIN_DATE, getBeginDate());
            jsonObject.put(Var.KEY_END_DATE, getEndDate());

            return jsonObject.toString();
        } catch (JSONException e) {
            e.printStackTrace();
            return "";
        }
    }
}

Các bạn chú ý thông thường các phương thức getter chúng ta không trả về giá trị gì và thường là public void… tuy nhiên mình viết chúng trả về chính đối tượng Lover (return this). Điều này giúp cho chúng ta thao tác dễ hơn. Ví dụ như khi các bạn muốn set 2 giá trị name và phone thì các bạn phải viết 2 lần là lover.setName và lover.setPhone như thế có thể làm máy chạy chậm hơn giống như khi bạn đi chợ, bạn mua rau rồi chạy về, rồi lại chạy ra mua đậu,… Còn mình chỉ cần lover.setName(…).setPhone(…) tức là đi chợ mua rau và mua luôn cả đậu. =))

Phương thức toJSON mình viết để chuyển 1 đối tượng sang dạng JSon để dễ dàng cho các thao tác gửi dữ liệu lên server, tuy nhiên trong App này thì mình không dùng nó, viết để các bạn biết và có thể dùng cho các app khác thôi.

Xây dựng class LoadJSon

Thực ra trong này không chỉ lấy JSon về mà còn gửi dữ liệu lên để xử lý nữa. Và như hôm trước khi xây dựng file lover.php mình có nói là chúng ta phân biệt các hành động thông qua biến method.

package cachhoc.net.demojson;

import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.RequestParams;

import org.apache.http.Header;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.HashMap;

public class LoadJson {

    public static final String LINK = "https://cachhoc.net/mobile/demo-json/lover.php";

    public void sendDataToServer(int method, HashMap<String, String> map) {
        AsyncHttpClient client = new AsyncHttpClient();
        RequestParams params = new RequestParams();

        // put data to server
        params.put(Var.KEY_METHOD, method);

        if (map != null) {
            for (String key : map.keySet()) {
                params.put(key, map.get(key));
            }
        }

        System.out.println("Post...");

        client.post(LINK, params, new AsyncHttpResponseHandler() {

            @SuppressWarnings("deprecation")
            @Override
            public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
                String json = new String(responseBody);
                System.out.println("onSuccess:" + json);
                onFinishLoadJSonListener.finishLoadJSon(null, json);
            }

            @SuppressWarnings("deprecation")
            @Override
            public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
                System.out.println("onFailure:" + statusCode);

                String e;

                if (statusCode == 404) {
                    e = "Requested resource not found";
                } else if (statusCode == 500) {
                    e = "Something went wrong at server end";
                } else {
                    e = "Device might not be connected to Internet";
                }
                onFinishLoadJSonListener.finishLoadJSon(e, null);
            }
        });
    }

    public static Lover jsonToLover(JSONObject jsonObject) {
        try {
            int id = jsonObject.getInt(Var.KEY_ID);
            String name = jsonObject.getString(Var.KEY_NAME);
            String phone = jsonObject.getString(Var.KEY_PHONE);
            String beginDate = jsonObject.getString(Var.KEY_BEGIN_DATE);
            String endDate = jsonObject.getString(Var.KEY_END_DATE);
            return new Lover(id, name, phone, beginDate, endDate);
        } catch (JSONException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static ArrayList<Lover> jsonToListLover(String json) {
        ArrayList<Lover> list = new ArrayList<>();

        try {
            JSONArray arraySMSJson = new JSONArray(json);
            for (int i = 0; i < arraySMSJson.length(); i++) {
                JSONObject jsonObject = arraySMSJson.getJSONObject(i);
                Lover lover = jsonToLover(jsonObject);
                if (lover != null) {
                    list.add(lover);
                }
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return list;
    }


    public interface OnFinishLoadJSonListener {
        void finishLoadJSon(String error, String json);
    }

    public OnFinishLoadJSonListener onFinishLoadJSonListener;

    public void setOnFinishLoadJSonListener(OnFinishLoadJSonListener onFinishLoadJSonListener) {
        this.onFinishLoadJSonListener = onFinishLoadJSonListener;
    }
}

Trong đó:

  • Hằng số LINK là đường dẫn đến file xuất JSon – file lover.php đã xây dựng hôm trước.

  • Phương thức sendDataToServer có 2 đối số là method để phân biệt hành động (login, register, load json, add lover) để file lover.php trên server phân biệt xử lý. Biến HashMap<String, String> map là một danh sách các cặp key-value để chúng ta đưa dữ liệu lên, trên server sẽ dựa vào các key để lấy value tương ứng.

  • Khi chúng ta gọi client.post() thì hệ thông sẽ thực hiện chạy ngầm để gửi dữ liệu lên server. Khi kết thúc thì hệ thống sẽ tự động gọi phương thức onSuccess (thành công) hoặc onFailure (có lỗi) và trả về các giá trị tuơng ứng. Trong phương thức onSuccess thì responseBody chính là Json chúng ta lấy được về, nó ở dạng byte và ta cần chuyển sang dạng string.

  • Để lấy được JSon và phục vụ cho các class khác xử lý, chúng ta xây dựng một interface là OnFinishLoadJSonListener có phương thức finishLoadJSon(String error, String json) để các class khác implements lấy JSon hoặc lỗi để xử lý tiếp sau đó.

  • Trong này mình cũng xây dựn 2 phương thức jsonToLoverjsonToListLover để chuyển đổi chuỗi json về đối tượng Lover hoặc danh sách Lover.

Đến đây nghe vẻ hơi dài dài rồi. Phần quan trọng nhất là lấy JSon đã ổn. Chúng ta tiếp tục xử lý 4 Activity.

Xử lý các Activity

Tương tự như phần giao diện, chúng ta sẽ đi làm lần lượt các bước:
Cấu hình, Chuẩn bị -> Login -> Register -> List Old Lover -> Add Lover
Và trong code mình cũng đặt tên các phương thức khá rõ ràng nên sẽ không cần giải thích nhiều.

Activity Login

Để login vào được thì chúng ta sẽ phải gửi nick và pass lên hệ thông kiểm tra, file lover.php sẽ kiểm tra và nếu đúng thì mới login vào được.

package cachhoc.net.demojson;

import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.CheckBox;
import android.widget.EditText;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.HashMap;

public class LoginActivity extends AppCompatActivity implements View.OnClickListener, LoadJson.OnFinishLoadJSonListener {

    private EditText editNick, editPass;
    private CheckBox cbRememberPass;

    private LoadJson loadJson;

    private Context context;

    private ProgressDialog progressDialog;

    private String nick, pass;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

        context = this;

        setupToolbar();

        connectView();

        loadJson = new LoadJson();
        loadJson.setOnFinishLoadJSonListener(this);
        progressDialog = new ProgressDialog(context);
        progressDialog.setMessage(context.getResources().getString(R.string.wait));
    }

    private void setupToolbar() {
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        if (toolbar != null) {
            setSupportActionBar(toolbar);
            if (getSupportActionBar() != null) {
                getSupportActionBar().setTitle(R.string.login);
            }
        }
    }

    private void connectView() {
        editNick = (EditText) findViewById(R.id.edit_nick);
        editPass = (EditText) findViewById(R.id.edit_pass);
        cbRememberPass = (CheckBox) findViewById(R.id.cb_remember);

        findViewById(R.id.btn_login).setOnClickListener(this);
        findViewById(R.id.btn_register).setOnClickListener(this);

        // get nick and pass if it be remember
        nick = Var.get(context, Var.KEY_NICK);
        pass = Var.get(context, Var.KEY_PASS);

        if (nick != null && pass != null) {
            editNick.setText(nick);
            editPass.setText(pass);
            cbRememberPass.setChecked(true);
        }

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_login:
                login();
                break;
            case R.id.btn_register:
                register();
                break;
            default:
                break;
        }
    }

    private void register() {
        Intent intent = new Intent(context, RegisterActivity.class);
        startActivity(intent);
    }

    private void login() {
        nick = editNick.getText().toString().trim();
        pass = editPass.getText().toString().trim();

        // not enter nick name
        if (nick.length() == 0) {
            editNick.requestFocus();
            Var.showToast(context, context.getResources().getString(R.string.enter_nick));
            return;
        }

        // not enter pass
        if (pass.length() == 0) {
            editPass.requestFocus();
            Var.showToast(context, context.getResources().getString(R.string.enter_pass));
            return;
        }

        // save nick and pass
        if (cbRememberPass.isChecked()) {
            Var.save(context, Var.KEY_NICK, nick);
            Var.save(context, Var.KEY_PASS, pass);
        } else {
            Var.save(context, Var.KEY_NICK, null);
            Var.save(context, Var.KEY_PASS, null);
        }

        HashMap<String, String> map = new HashMap<>();
        map.put(Var.KEY_NICK, nick);
        map.put(Var.KEY_PASS, pass);

        loadJson.sendDataToServer(Var.METHOD_LOGIN, map);
        progressDialog.show();
    }

    @Override
    public void finishLoadJSon(String error, String json) {
        if (progressDialog.isShowing()) {
            progressDialog.hide();
        }
        try {
            if (json != null) {
                JSONObject jsonObject = new JSONObject(json);
                if (jsonObject.getBoolean(Var.KEY_LOGIN)) {
                    Var.showToast(context, context.getResources().getString(R.string.login_success));

                    Intent intent = new Intent(context, MainActivity.class);
                    intent.putExtra(Var.KEY_NICK, nick);
                    startActivity(intent);

                    finish();
                } else {
                    Var.showToast(context, context.getResources().getString(R.string.login_fail));
                }
            } else {
                Var.showToast(context, error);
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
}

Activity Register

Nếu chưa có tài khoản, chúng ta cần phải đăng ký để hệ thông thêm vào database.

package cachhoc.net.demojson;

import android.app.ProgressDialog;
import android.content.Context;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.EditText;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.HashMap;

public class RegisterActivity extends AppCompatActivity implements View.OnClickListener, LoadJson.OnFinishLoadJSonListener {

    private EditText editNick, editPass, editRePass;

    private LoadJson loadJson;

    private Context context;

    private ProgressDialog progressDialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_register);

        context = this;

        setupToolbar();

        connectView();

        loadJson = new LoadJson();
        loadJson.setOnFinishLoadJSonListener(this);
        progressDialog = new ProgressDialog(context);
        progressDialog.setMessage(context.getResources().getString(R.string.wait));
    }

    private void setupToolbar() {
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        if (toolbar != null) {
            setSupportActionBar(toolbar);
            if (getSupportActionBar() != null) {
                getSupportActionBar().setTitle(R.string.register);
            }
        }
    }

    private void connectView() {
        editNick = (EditText) findViewById(R.id.edit_nick);
        editPass = (EditText) findViewById(R.id.edit_pass);
        editRePass = (EditText) findViewById(R.id.edit_re_pass);

        findViewById(R.id.btn_reset).setOnClickListener(this);
        findViewById(R.id.btn_register).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_reset:
                reset();
                break;
            case R.id.btn_register:
                register();
                break;
            default:
                break;
        }
    }

    private void reset() {
        editNick.setText("");
        editPass.setText("");
        editRePass.setText("");
        editNick.requestFocus();
    }

    private void register() {
        String nick = editNick.getText().toString().trim();
        String pass = editPass.getText().toString().trim();
        String repass = editRePass.getText().toString().trim();

        // not enter nick name
        if (nick.length() == 0) {
            editNick.requestFocus();
            Var.showToast(context, context.getResources().getString(R.string.enter_nick));
            return;
        }

        // not enter pass
        if (pass.length() == 0) {
            editPass.requestFocus();
            Var.showToast(context, context.getResources().getString(R.string.enter_pass));
            return;
        }

        // not enter pass
        if (repass.length() == 0) {
            editRePass.requestFocus();
            Var.showToast(context, context.getResources().getString(R.string.enter_repass));
            return;
        }

        if (!repass.equals(pass)) {
            editPass.requestFocus();
            Var.showToast(context, context.getResources().getString(R.string.pass_not_match));
            return;
        }

        HashMap<String, String> map = new HashMap<>();
        map.put(Var.KEY_NICK, nick);
        map.put(Var.KEY_PASS, pass);

        loadJson.sendDataToServer(Var.METHOD_REGISTER, map);
        progressDialog.show();
    }

    @Override
    public void finishLoadJSon(String error, String json) {
        if (progressDialog.isShowing()) {
            progressDialog.hide();
        }
        try {
            if (json != null) {
                JSONObject jsonObject = new JSONObject(json);
                if (jsonObject.getBoolean(Var.KEY_REGISTER)) {
                    Var.showToast(context, context.getResources().getString(R.string.register_success));
                    finish();
                } else {
                    Var.showToast(context, context.getResources().getString(R.string.register_fail));
                }
            } else {
                Var.showToast(context, error);
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
}

Activity Add Lover

package cachhoc.net.demojson;

import android.app.ProgressDialog;
import android.content.Context;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import com.wdullaer.materialdatetimepicker.date.DatePickerDialog;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.Calendar;
import java.util.HashMap;

public class AddLoverActivity extends AppCompatActivity implements View.OnClickListener, LoadJson.OnFinishLoadJSonListener, DatePickerDialog.OnDateSetListener {

    private EditText editName, editPhone;
    private Button btnBeginDate, btnEndDate;

    private LoadJson loadJson;

    private Context context;

    private ProgressDialog progressDialog;

    private String nick;

    // for begin date or end date
    private int typeDate;
    private String beginDate = "", endDate = "";

    public static final int BEGIN_DATE = 0;
    public static final int END_DATE = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_add_lover);

        context = this;

        setupToolbar();

        connectView();

        loadJson = new LoadJson();
        loadJson.setOnFinishLoadJSonListener(this);
        progressDialog = new ProgressDialog(context);
        progressDialog.setMessage(context.getResources().getString(R.string.wait));

        nick = getIntent().getStringExtra(Var.KEY_NICK);
    }

    private void setupToolbar() {
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        if (toolbar != null) {
            setSupportActionBar(toolbar);
            if (getSupportActionBar() != null) {
                getSupportActionBar().setTitle(R.string.title_activity_add_lover);
            }
        }
    }

    private void connectView() {
        editName = (EditText) findViewById(R.id.edit_name);
        editPhone = (EditText) findViewById(R.id.edit_phone);
        btnBeginDate = (Button) findViewById(R.id.btn_begin_date);
        btnEndDate = (Button) findViewById(R.id.btn_end_date);

        btnBeginDate.setOnClickListener(this);
        btnEndDate.setOnClickListener(this);

        findViewById(R.id.btn_add).setOnClickListener(this);
        findViewById(R.id.btn_reset).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_reset:
                reset();
                break;
            case R.id.btn_add:
                add();
                break;
            case R.id.btn_begin_date:
                typeDate = BEGIN_DATE;
                showDatePicker();
                break;
            case R.id.btn_end_date:
                typeDate = END_DATE;
                showDatePicker();
                break;
            default:
                break;
        }
    }

    private void showDatePicker() {
        Calendar now = Calendar.getInstance();
        DatePickerDialog dpd = DatePickerDialog.newInstance(
                this,
                now.get(Calendar.YEAR),
                now.get(Calendar.MONTH),
                now.get(Calendar.DAY_OF_MONTH)
        );

        String title;
        if (typeDate == BEGIN_DATE) {
            title = context.getResources().getString(R.string.begin_date);
        } else {
            title = context.getResources().getString(R.string.end_date);
        }
        dpd.show(getFragmentManager(), title);
    }

    @Override
    public void onDateSet(DatePickerDialog view, int year, int monthOfYear, int dayOfMonth) {
        String date = dayOfMonth + "/" + monthOfYear + "/" + year;
        if (typeDate == BEGIN_DATE) {
            beginDate = date;
            btnBeginDate.setText(date);
        } else {
            endDate = date;
            btnEndDate.setText(date);
        }
    }

    private void reset() {
        editName.setText("");
        editPhone.setText("");
        editName.requestFocus();
    }


    private void add() {
        String name = editName.getText().toString().trim();
        String phone = editPhone.getText().toString().trim();

        // not enter nick name
        if (name.length() == 0) {
            editName.requestFocus();
            Var.showToast(context, context.getResources().getString(R.string.enter_nick));
            return;
        }

        // not enter pass
        if (phone.length() == 0) {
            editPhone.requestFocus();
            Var.showToast(context, context.getResources().getString(R.string.enter_pass));
            return;
        }


        HashMap<String, String> map = new HashMap<>();
        map.put(Var.KEY_NICK, nick);
        map.put(Var.KEY_NAME, name);
        map.put(Var.KEY_PHONE, phone);
        map.put(Var.KEY_BEGIN_DATE, beginDate);
        map.put(Var.KEY_END_DATE, endDate);

        loadJson.sendDataToServer(Var.METHOD_ADD_OLD_LOVER, map);
        progressDialog.show();
    }

    @Override
    public void finishLoadJSon(String error, String json) {
        if (progressDialog.isShowing()) {
            progressDialog.hide();
        }
        try {
            if (json != null) {
                JSONObject jsonObject = new JSONObject(json);
                if (jsonObject.getBoolean(Var.KEY_ADD)) {
                    Var.showToast(context, context.getResources().getString(R.string.add_success));
                    finish();
                } else {
                    Var.showToast(context, context.getResources().getString(R.string.add_fail));
                }
            } else {
                Var.showToast(context, error);
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
}

Activity Main – List Lover

Trong này có 2 phần chúng ta cần xử lý là list và Adapter cho list.

File MainActivity.java

package cachhoc.net.demojson;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.HashMap;

public class MainActivity extends AppCompatActivity implements View.OnClickListener, LoadJson.OnFinishLoadJSonListener {

    private ItemAdapter adapter;
    private ArrayList<Lover> list;

    private LoadJson loadJson;

    private Context context;

    private ProgressBar progressBar;
    private ViewGroup layoutProgress;
    private TextView tvNotify;

    private String nick;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        context = this;

        loadJson = new LoadJson();
        loadJson.setOnFinishLoadJSonListener(this);

        setupToolbar();
        setupRecyclerView();

        findViewById(R.id.fab_add).setOnClickListener(this);
        layoutProgress = (ViewGroup) findViewById(R.id.layout_progress);
        progressBar = (ProgressBar) findViewById(R.id.progress);
        tvNotify = (TextView) findViewById(R.id.tv_notify);

        nick = getIntent().getStringExtra(Var.KEY_NICK);
    }

    private void setupToolbar() {
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        if (toolbar != null) {
            setSupportActionBar(toolbar);
        }
    }

    private void setupRecyclerView() {
        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.rv_lover);

        // If the size of views will not change as the data changes.
        recyclerView.setHasFixedSize(true);

        // Setting the LayoutManager.
        RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);

        // Setting the adapter.
        list = new ArrayList<>();
        adapter = new ItemAdapter(context, list);
        recyclerView.setAdapter(adapter);
    }

    public void onResume() {
        super.onResume();
        refresh();
    }

    /**
     * re load data from server
     */
    private void refresh() {
        HashMap<String, String> map = new HashMap<>();
        map.put(Var.KEY_NICK, nick);
        loadJson.sendDataToServer(Var.METHOD_GET_OLD_LOVER, map);
        layoutProgress.setVisibility(View.VISIBLE);
        progressBar.setVisibility(View.VISIBLE);
        tvNotify.setVisibility(View.GONE);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.action_logout:
                logout();
                break;
            case R.id.action_refresh:
                refresh();
                break;
        }
        return super.onOptionsItemSelected(item);
    }

    private void logout() {
        Intent intent = new Intent(context, LoginActivity.class);
        startActivity(intent);
        finish();
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.fab_add:
                addOldLover();
                break;
        }
    }

    private void addOldLover() {
        Intent intent = new Intent(context, AddLoverActivity.class);
        intent.putExtra(Var.KEY_NICK, nick);
        startActivity(intent);
    }

    @Override
    public void finishLoadJSon(String error, String json) {
        if (json != null) {
            layoutProgress.setVisibility(View.GONE);
            updateList(json);
        } else {
            showNotify(error);
        }
    }

    private void updateList(String json) {
        ArrayList<Lover> newList = LoadJson.jsonToListLover(json);
        list.clear();
        list.addAll(newList);
        adapter.notifyDataSetChanged();
        if (list.size() == 0) {
            showNotify(context.getResources().getString(R.string.no_lover));
        }
    }

    private void showNotify(String notify) {
        layoutProgress.setVisibility(View.VISIBLE);
        progressBar.setVisibility(View.GONE);
        tvNotify.setVisibility(View.VISIBLE);
        tvNotify.setText(notify);
    }

    /**
     * double click back then exit app (2 click in 2s to exit)
     */
    @Override
    public void onBackPressed() {
        if (doubleBackToExitPressedOnce) {
            super.onBackPressed();
            return;
        }

        this.doubleBackToExitPressedOnce = true;
        Var.showToast(context, context.getResources().getString(R.string.back_to_exit));
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                doubleBackToExitPressedOnce = false;
            }
        }, 2000);
    }

    private boolean doubleBackToExitPressedOnce;
}

Trong này các bạn chú ý là ở cuối mình viết đè phương thức onBackPressed để thông báo người dùng ấn back 2 lần trước khi thoát. 2 lần ấn này phải liên tiếp trong vòng 2s (200 mili giây)

File ItemAdapter.java

package cachhoc.net.demojson;

import android.content.Context;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.List;

public class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.RecyclerViewHolder> {

    private List<Lover> list;
    private Context context;

    public ItemAdapter(Context context, List<Lover> list) {
        this.context = context;
        this.list = list;
    }

    @Override
    public int getItemCount() {
        return list.size();
    }

    /**
     * connect to item view
     */
    @Override
    public RecyclerViewHolder onCreateViewHolder(ViewGroup viewGroup, int position) {
        LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
        View itemView = inflater.inflate(R.layout.item, viewGroup, false);
        return new RecyclerViewHolder(itemView);
    }

    /**
     * set data for item
     */
    @Override
    public void onBindViewHolder(RecyclerViewHolder viewHolder, int position) {
        Lover lover = list.get(position);
        viewHolder.tvName.setText(lover.getName());
        viewHolder.tvPhone.setText(lover.getPhone());
        viewHolder.tvBeginDate.setText(lover.getBeginDate());
        viewHolder.tvEndDate.setText(lover.getEndDate());
    }

    /**
     * ViewHolder for item view of list
     */

    public class RecyclerViewHolder extends RecyclerView.ViewHolder implements
            OnClickListener {

        public CardView container;
        public TextView tvName;
        public TextView tvPhone;
        public TextView tvBeginDate;
        public TextView tvEndDate;

        public RecyclerViewHolder(View itemView) {
            super(itemView);

            container = (CardView) itemView.findViewById(R.id.item_container);
            tvName = (TextView) itemView.findViewById(R.id.tv_name);
            tvPhone = (TextView) itemView.findViewById(R.id.tv_phone);
            tvBeginDate = (TextView) itemView.findViewById(R.id.tv_begin_date);
            tvEndDate = (TextView) itemView.findViewById(R.id.tv_end_date);

            container.setOnClickListener(this);
        }

        // click item then display note
        @Override
        public void onClick(View v) {
            Var.showToast(context, list.get(getAdapterPosition()).getName());
        }
    }
}

Vậy là chúng ta đã hoàn thiện ứng dụng. Bài tuy hơi dài nhưng không khó.
Các bạn có thể download project tại đây

Download File Chạy OldLover.apk

Chúc các bạn học tập vui vẻ 🙂

Bài viết được thực hiện trong loạt bài hướng dẫn JSon trong Android bởi nguyenvanquan7826