activity_main.xml ์์ฑํ๊ธฐ
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<Button
android:id="@+id/btnAdd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerInParent="false"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="10dp"
android:text="์ง์ ์ถ๊ฐ"
android:textSize="30sp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/btnAdd" />
<ProgressBar
android:id="@+id/progressBar2"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/btnAdd"
android:layout_centerHorizontal="true"
android:layout_marginTop="316dp"
android:visibility="visible" />
</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
JSON ๋ฐ์ดํฐ๋ฅผ ํ์ฑํ๊ณ RecyclerView๋ก ํ์ํ๋ ๊ณผ์
- JSON ๋ฐ์ดํฐ ์์ ๋ฐ ํ์ฑ : ์๋ฒ์์ JSON ํ์์ ๋ฐ์ดํฐ๋ฅผ ์์ , ํ์ฑ ๋ผ์ด๋ธ๋ฌ๋ฆฌ(Gson, Jackson ๋ฑ)๋ฅผ ์ฌ์ฉํ์ฌ JSON ๋ฐ์ดํฐ๋ฅผ ํ์ฑํ์ฌ Java ๊ฐ์ฒด๋ก ๋ณํ
- ์ด๋ํฐ ์์ฑ : RecyclerView.Adapter๋ฅผ ํ์ฅํ์ฌ ์ปค์คํ ์ด๋ํฐ๋ฅผ ๋ง๋ค๊ณ ์ด๋ํฐ ๋ด์์ ViewHolder ํด๋์ค๋ฅผ ์ ์ํ ํ, onBindViewHolder ๋ฉ์๋์์ ๋ฐ์ดํฐ๋ฅผ ๋ทฐ์ ๋ฐ์ธ๋ฉ
- RecyclerView ์ค์ : RecyclerView์ ๋ ์ด์์ ๋งค๋์ ๋ฅผ ์ค์ (์: LinearLayoutManager, GridLayoutManager ๋ฑ) ํ RecyclerView์ ์ด๋ํฐ๋ฅผ ์ค์
Json ๋ฐ์ดํฐ ํ์ฑํ๊ณ , ์ด๋ํฐ(adapter) ์ฌ์ฉํ์ฌ RecyclerView๋ก ๋ง๋ค๊ธฐ
JSON ๋ฐ์ดํฐ ํ์ฑํ๊ธฐ?
= ์ ์ด์จ์ผ๋ก ๋ฐ์์จ ๋ฐ์ดํฐ๋ฅผ ๊บผ๋ด์ ์ฌ์ฉํ๋ ๊ฒ์ด๋ค. try ์์์ ์ฝ๋๋ฅผ ์ ๋ ฅํด์ผ ํ๋ค.
RecyclerView๋ Android์์ ๋๋์ ๋ฐ์ดํฐ๋ฅผ ํจ์จ์ ์ผ๋ก ํ์ํ๊ธฐ ์ํ ๋ทฐ์ด๋ค. RecyclerView๋ ์คํฌ๋กค ์ ๋ทฐ๋ฅผ ์ฌ์ฌ์ฉ(recycle)ํ์ฌ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ ์ค์ด๊ณ , ์ฑ๋ฅ์ ํฅ์์ํจ๋ค. ๋ํ ๋ค์ํ ๋ ์ด์์ ๋งค๋์ ๋ฅผ ํตํด ๋ฆฌ์คํธ, ๊ทธ๋ฆฌ๋, ์คํ๊ฑฐ๋ ๋ ์ด์์ ๋ฑ์ ์ฝ๊ฒ ๊ตฌํํ ์ ์์ผ๋ฉฐ ์ ๋๋ฉ์ด์ ์ง์ ๊ธฐ๋ฅ์ด ์๋ค.
์ด๋ํฐ(Adapter)๋ ๋ฐ์ดํฐ ์์ค(์: JSON ๋ฐ์ดํฐ)์ RecyclerView๋ฅผ ์ฐ๊ฒฐํ๋ ์ญํ ์ ํ๋ฉฐ ๋ฐ์ดํฐ ํญ๋ชฉ์ ๊ฐ๋ณ ๋ทฐ ํ๋(ViewHolder)์ ๋ฐ์ธ๋ฉํ์ฌ ๊ฐ ํญ๋ชฉ์ RecyclerView์ ํ์ํ๋ค.
๋จผ์ ์ด ๋ฐ์ดํฐ๋ฅผ,
{"status":"success","data":[{"id":1,"employee_name":"Tiger Nixon","employee_salary":320800,"employee_age":61,"profile_image":""},{"id":2,"employee_name":"Garrett Winters","employee_salary":170750,"employee_age":63,"profile_image":""},{"id":3,"employee_name":"Ashton Cox","employee_salary":86000,"employee_age":66,"profile_image":""},{"id":4,"employee_name":"Cedric Kelly","employee_salary":433060,"employee_age":22,"profile_image":""},{"id":5,"employee_name":"Airi Satou","employee_salary":162700,"employee_age":33,"profile_image":""},{"id":6,"employee_name":"Brielle Williamson","employee_salary":372000,"employee_age":61,"profile_image":""},{"id":7,"employee_name":"Herrod Chandler","employee_salary":137500,"employee_age":59,"profile_image":""},{"id":8,"employee_name":"Rhona Davidson","employee_salary":327900,"employee_age":55,"profile_image":""},{"id":9,"employee_name":"Colleen Hurst","employee_salary":205500,"employee_age":39,"profile_image":""},{"id":10,"employee_name":"Sonya Frost","employee_salary":103600,"employee_age":23,"profile_image":""},{"id":11,"employee_name":"Jena Gaines","employee_salary":90560,"employee_age":30,"profile_image":""},{"id":12,"employee_name":"Quinn Flynn","employee_salary":342000,"employee_age":22,"profile_image":""},{"id":13,"employee_name":"Charde Marshall","employee_salary":470600,"employee_age":36,"profile_image":""},{"id":14,"employee_name":"Haley Kennedy","employee_salary":313500,"employee_age":43,"profile_image":""},{"id":15,"employee_name":"Tatyana Fitzpatrick","employee_salary":385750,"employee_age":19,"profile_image":""},{"id":16,"employee_name":"Michael Silva","employee_salary":198500,"employee_age":66,"profile_image":""},{"id":17,"employee_name":"Paul Byrd","employee_salary":725000,"employee_age":64,"profile_image":""},{"id":18,"employee_name":"Gloria Little","employee_salary":237500,"employee_age":59,"profile_image":""},{"id":19,"employee_name":"Bradley Greer","employee_salary":132000,"employee_age":41,"profile_image":""},{"id":20,"employee_name":"Dai Rios","employee_salary":217500,"employee_age":35,"profile_image":""},{"id":21,"employee_name":"Jenette Caldwell","employee_salary":345000,"employee_age":30,"profile_image":""},{"id":22,"employee_name":"Yuri Berry","employee_salary":675000,"employee_age":40,"profile_image":""},{"id":23,"employee_name":"Caesar Vance","employee_salary":106450,"employee_age":21,"profile_image":""},{"id":24,"employee_name":"Doris Wilder","employee_salary":85600,"employee_age":23,"profile_image":""}],"message":"Successfully! All records has been fetched."}
์ด ์ฐฝ์ ์ด์ด ๋ฃ์ ํ, copy๋ฅผ ๋๋ฌ์ค๋ค.
https://jsoneditoronline.org/#left=local.tusimo&right=local.qofoce
JSON Editor Online: edit JSON, format JSON, query JSON
JSON Editor Online is the original and most copied JSON Editor on the web. Use it to view, edit, format, repair, compare, query, transform, validate, and share your JSON data.
jsoneditoronline.org
์ค๊ดํธ {} ๋ object ๋ฐ์ดํฐ ํ์ ์ด๋ค.
๋๊ดํธ []๋ array ๋ฐ์ดํฐ ํ์ ์ด๋ค.
Adapter.java ํด๋์ค
(EmployeeAdapter.java๋ก ๋ง๋ค์ด์ฃผ์๋ค.)
package com.~.employee.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.~.employee.R;
import com.~.employee.model.Employer;
import java.text.DecimalFormat;
import java.util.ArrayList;
public class EmployerAdapter extends RecyclerView.Adapter<EmployerAdapter.ViewHolder> {
Context context;
ArrayList<Employer> employerArrayList;
public EmployerAdapter(Context context, ArrayList<Employer> employerArrayList) {
this.context = context;
this.employerArrayList = employerArrayList;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.employer_row, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Employer employer = employerArrayList.get(position);
holder.txtName.setText(employer.name);
holder.txtAge.setText(String.valueOf("๋์ด : "+employer.age+"์ธ"));
DecimalFormat formatter = new DecimalFormat("#,###");
String strSalary = formatter.format(employer.salary);
holder.txtSalary.setText(String.valueOf("์ฐ๋ด : $"+strSalary));
}
@Override
public int getItemCount() {
return employerArrayList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView txtName;
TextView txtAge;
TextView txtSalary;
ImageView imgDelete;
public ViewHolder(@NonNull View itemView) {
super(itemView);
txtName = itemView.findViewById(R.id.txtName);
txtAge = itemView.findViewById(R.id.txtAge);
txtSalary = itemView.findViewById(R.id.txtSalary);
imgDelete = itemView.findViewById(R.id.imgDelete);
}
}
}
MainActivity.java ํด๋์ค (ํ์ฑํ๊ธฐ)
package com.~.employee;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley;
import com.yujinoh.employee.adapter.EmployerAdapter;
import com.yujinoh.employee.model.Employer;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
Button btnAdd;
ProgressBar progressBar;
EmployerAdapter adapter;
//๋ฆฌ์ฌ์ดํด๋ฌ๋ทฐ๋ ๊ด๋ จ๋ ๋ฉค๋ฒ๋ณ์ 2๊ฐ ๋ ์์ฑํด์ผ ํ๋ค
RecyclerView recyclerView;
ArrayList<Employer> employerArrayList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//๋ค์ ์ฝ๋๋ ์์ผ๋ก ๋ฌด์กฐ๊ฑด ๊ฐ์ด ์์ฑ
recyclerView = findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));
btnAdd = findViewById(R.id.btnAdd);
progressBar = findViewById(R.id.progressBar2);
recyclerView = findViewById(R.id.recyclerView);
btnAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// AddActivity๋ฅผ ๋์ด๋ค
Intent intent = new Intent(MainActivity.this, AddActivity.class);
startActivity(intent);
}
});
// ๋คํธ์ํฌ๋ก๋ถํฐ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์จ๋ค
// Volley ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ด์ฉํ ๋คํธ์ํฌ ํต์
// 1. request queue ๋ฅผ ๋ง๋ ๋ค
RequestQueue queue = Volley.newRequestQueue(MainActivity.this);
// 2. request(์์ฒญ)์ ๋ง๋ ๋ค.
// ๋ฐ์ดํฐ ํ์
์, ์๋ต์ json ํ์์ ๋ณด๊ณ ๊ฒฐ์ ํ๋ค.
JsonObjectRequest request = new JsonObjectRequest(
Request.Method.GET,
"https://block1-image-test.s3.ap-northeast-2.amazonaws.com/employees.json",
null,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
// ํ๋ก๊ทธ๋ ์ค ๋ฐ๋ฅผ ์ ์ ์ ๋์์ ์ฌ๋ผ์ง๊ฒ ํ๋ ์ฝ๋
progressBar.setVisibility(View.GONE);
Log.i("EMPLOYEE MAIN", response.toString());
try {
String status = response.getString("status");
if(status.equals("success") == false){
Toast.makeText(MainActivity.this,
"๋คํธ์ํฌ ์๋ฌ",
Toast.LENGTH_SHORT).show();
return;
}
JSONArray data = response.getJSONArray("data");
for(int i = 0 ; i < data.length() ; i++){
JSONObject row = data.getJSONObject(i);
int id = row.getInt("id");
String name = row.getString("employee_name");
int salary = row.getInt("employee_salary");
int age = row.getInt("employee_age");
Employer employer= new Employer(id, name, salary, age);
employerArrayList.add(employer);
}
// ์ด๋ํฐ๋ฅผ ๋ง๋ค๊ณ
adapter = new EmployerAdapter(MainActivity.this, employerArrayList);
// ๋ฆฌ์ฌ์ดํด๋ฌ๋ทฐ์ ์ด๋ํฐ๋ฅผ ์ ์ฉํ๋ฉด ํ๋ฉด์ ๋์จ๋ค
recyclerView.setAdapter(adapter);
} catch (JSONException e) {
Toast.makeText(MainActivity.this,
"ํ์ฑ ์๋ฌ",
Toast.LENGTH_SHORT).show();
return;
}
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
// ํ๋ก๊ทธ๋ ์ค ๋ฐ๋ฅผ ์ ์ ์ ๋์์ ์ฌ๋ผ์ง๊ฒ ํ๋ ์ฝ๋
progressBar.setVisibility(View.GONE);
Toast.makeText(MainActivity.this,
"๋คํธ์ํฌ ํต์ ์๋ฌ",
Toast.LENGTH_SHORT).show();
Log.i("EMPLOYEE MAIN", error.toString());
}
}
);
// 3. ๋คํธ์ํฌ๋ก ๋ณด๋ธ๋ค.
queue.add(request);
}
}
Employer.java ํด๋์ค
package com.~.employee.model;
public class Employer {
public int id;
public String name;
public int salary;
public int age;
public Employer(){
}
public Employer(int id, String name, int salary, int age) {
this.id = id;
this.name = name;
this.salary = salary;
this.age = age;
}
}