리사이클뷰 어댑터를 이용한 양방향 통신시
context는 현재 호출되고있는 MainActivity 인데
MainActivity 의 디폴트 멤버변수인 launcher가 접근이 안됨
따라서,
어댑터에서 접근할 멤버변수를 public 으로 바꾼뒤
어댑터로 파일에서 ((MainActivity)) 로 캐스팅을 하고
. 을해보면 접근 가능한 멤버변수와 메소드의 리스트를 확인할수있다.
액티비티 별로 액션바를 만드는방법
MainActivity
package com.leopard4.employeeapp;
import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.Toast;
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.google.android.material.floatingactionbutton.FloatingActionButton;
import com.leopard4.employeeapp.adapter.EmployeeAdapter;
import com.leopard4.employeeapp.model.Employee;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
Button btnAdd;
FloatingActionButton fab;
RecyclerView recyclerView;
EmployeeAdapter adapter;
ArrayList<Employee> employeeList = new ArrayList<>();
ProgressBar progressBar;
final String URL = "https://block1-image-test.s3.ap-northeast-2.amazonaws.com";
// 내가 실행한 액티비티로부터, 데이터를 다시 받아오는 경우에 작성하는 코드
public ActivityResultLauncher<Intent> launcher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
// 액티비티를 실행한후, 이 액티비티로
// 돌아왔을때 할 일을 여기에 작성
// AddActivity가 넘겨준
// Employee 객체를 받아서 원상복구 시키고
// 리스트에 넣어주고
// 화면 갱신 해준다.
if (result.getResultCode() == AddActivity.SAVE) {
Employee employee = (Employee) result.getData().getSerializableExtra("employee");
employeeList.add(employee);
adapter.notifyDataSetChanged();
} else if (result.getResultCode() == EditActivity.EDIT) {
Employee employee = (Employee) result.getData().getSerializableExtra("employee");
// 몇번째 데이터를 수정한건지 확인을위한 코드작성
int index = result.getData().getIntExtra("index", -1);
employeeList.set(index, employee);
adapter.notifyDataSetChanged();
}
}
});
@SuppressLint("MissingInflatedId")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 액션바의 타이틀 변경법
getSupportActionBar().setTitle("직원리스트");
progressBar = findViewById(R.id.progressBar);
btnAdd = findViewById(R.id.btnAdd);
fab = findViewById(R.id.fab);
recyclerView = findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
btnAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 새로운 액티비티 띄운다.
Intent intent = new Intent(MainActivity.this, AddActivity.class);
launcher.launch(intent);
}
});
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 새로운 액티비티 띄운다.
Intent intent = new Intent(MainActivity.this, AddActivity.class);
launcher.launch(intent);
}
});
RequestQueue queue = Volley.newRequestQueue(this);
JsonObjectRequest request = new JsonObjectRequest(
Request.Method.GET,
URL+ "/employees.json",
null,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
Log.i("EMPLOYEE_APP", response.toString());
// 객체로 받아온 JSONObject 를 data key로 접근해서 arrayList로 만든다
progressBar.setVisibility(View.GONE);
try {
JSONArray data = response.optJSONArray("data"); // 또는
// JSONArray data = response.getJSONArray("data");
Log.i("EMPLOYEE_APP", data.toString());
for (int i = 0; i < data.length(); i++) {
// JSONArray 에 들어있는 직원 정보를 가져와서,
// Employee 클래스로 만든다.
Employee employee = new Employee(
data.getJSONObject(i).getInt("id"),
data.getJSONObject(i).getString("employee_name"),
data.getJSONObject(i).getInt("employee_salary"),
data.getJSONObject(i).getInt("employee_age"),
data.getJSONObject(i).getString("profile_image")
);
employeeList.add(employee);
adapter = new EmployeeAdapter(MainActivity.this, employeeList);
// 리사이클러뷰에 셋팅
recyclerView.setAdapter(adapter);
}
} catch (Exception e) {
e.printStackTrace();
progressBar.setVisibility(View.GONE);
Toast.makeText(MainActivity.this, "파싱에러!", Toast.LENGTH_SHORT).show();
}
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
}
}
);
progressBar.setVisibility(View.VISIBLE);
queue.add(request);
}
// 액션바의 메뉴는, 전용 함수가 있다.
// 이 함수를 오버라이딩 해야 한다.
@Override
public boolean onCreateOptionsMenu(@NonNull Menu menu) {
// 액션바에 메뉴가 나오도록 설정한다.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
// 액션바의 메뉴를 탭했을때, 실행되는 함수가 있다.
// 이 함수를 오버라이딩 해야 한다.
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
// 메뉴의 아이디를 확인해서, 각각의 메뉴를 구분한다.
int itemId = item.getItemId();
if(itemId == R.id.menuAdd){
// AddActivity 실행하는 코드
Intent intent = new Intent(MainActivity.this, AddActivity.class);
launcher.launch(intent);
} else if(itemId == R.id.menuAbout){
// AboutAcitivity 실행하는 코드
}
return MainActivity.super.onOptionsItemSelected(item);
}
}
EmployeeAdapter
package com.leopard4.employeeapp.adapter;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
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.appcompat.app.AlertDialog;
import androidx.cardview.widget.CardView;
import androidx.recyclerview.widget.RecyclerView;
import com.leopard4.employeeapp.EditActivity;
import com.leopard4.employeeapp.MainActivity;
import com.leopard4.employeeapp.model.Employee;
import com.leopard4.employeeapp.R;
import java.text.DecimalFormat;
import java.util.ArrayList;
public class EmployeeAdapter extends RecyclerView.Adapter<EmployeeAdapter.ViewHolder>{
Context context;
ArrayList<Employee> employeeList;
DecimalFormat dc = new DecimalFormat("###,###,###");
int deleteIndex;
public EmployeeAdapter(Context context, ArrayList<Employee> employeeList) {
this.context = context;
this.employeeList = employeeList;
}
@NonNull
@Override
public EmployeeAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.employee_row, parent, false);
return new EmployeeAdapter.ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull EmployeeAdapter.ViewHolder holder, int position) {
// 뷰에 데이터를 저장한다.
Employee employee = employeeList.get(position);
// todo 데이터 가공해서 셋팅
holder.txtName.setText(employee.name);
holder.txtAge.setText("나이 : " + employee.age + "세");
// txtsalary에 $와 , 를 넣어주기 위해 DecimalFormat을 사용한다
holder.txtSalary.setText("연봉 : $" + dc.format(employee.salary));
}
@Override
public int getItemCount() {
return employeeList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
TextView txtName;
TextView txtAge;
TextView txtSalary;
ImageView imgDelete;
CardView cardView;
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);
cardView = itemView.findViewById(R.id.cardView);
// 클릭 이벤트를 만들어 준다.
cardView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 1) 인텐트에 유저가 어떤 행을 눌렀는지 파악하여
int index = getAdapterPosition(); // 어떤 행을 눌렀는지 인덱스로 알려준다.
Employee employee = employeeList.get(index); // 해당 행의 데이터를 가져온다.
// 2) 수정 액티비티를 띄운다.
// 어떤 액티비티가 어떤 액티비티를 띄운다!! => 인텐트에 있어야 한다.
// (새로운 액티비티에 위의 정보를 넘겨서 실행한다.)
Intent intent = new Intent(context, EditActivity.class);
// 직렬화해서 한번에 넘겨준다
intent.putExtra("employee", employee);
// 몇번째 데이터를 수정한건지 확인을위한 인덱스도 넘겨준다.
intent.putExtra("index", index);
((MainActivity)context).launcher.launch(intent); // 매인액티비티로 캐스팅
// 매인액티비티의 퍼블릭멤버변수만 사용가능
}
});
// 삭제 이벤트를 만들어 준다.
imgDelete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 0) 어느 주소록을 삭제할것인지
// 삭제할 주소록을 가져온다 (어떤 행을 눌렀는지 파악한다.)
deleteIndex = getAdapterPosition();
// 1) 알러트 다이얼로그 나온다.
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("삭제");
builder.setMessage("정말 삭제하시겠습니까?");
// 3) 알러트 다이얼로그에서 No 눌렀을때
// 아무것도 안한다.
builder.setNegativeButton("No", null);
builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// 2) 알러트 다이얼로그에서 Yes 눌렀을때
// 알러트 다이얼로그는 액티비티가 아니므로
// 메인액티비티의 onResume 함수가 실행안된다.
// 따라서 화면 갱신이 안된다.
// 메모리에 저장된 데이터도 삭제한다.
employeeList.remove(deleteIndex);
// 데이터가 변경되었으니, 화면 갱신하라고 어댑터의 함수호출 (상속받은기능)
notifyDataSetChanged();
}
});
builder.show();
}
});
}
}
}
Employee
package com.leopard4.employeeapp.model;
import java.io.Serializable;
public class Employee implements Serializable {
// "id": 3,
// "employee_name": "Ashton Cox",
// "employee_salary": 86000,
// "employee_age": 66,
// "profile_image": "",
public int id;
public String name;
public int salary;
public int age;
public String image;
public Employee() {
}
public Employee(String name, int salary, int age) {
id = -1;
this.name = name;
this.salary = salary;
this.age = age;
}
public Employee(int id, String name, int salary, int age, String image) {
this.id = id;
this.name = name;
this.salary = salary;
this.age = age;
this.image = image;
}
}
AddActivity
package com.leopard4.employeeapp;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.leopard4.employeeapp.data.DatabaseHandler;
import com.leopard4.employeeapp.model.Employee;
public class AddActivity extends AppCompatActivity {
EditText editName;
EditText editAge;
EditText editSalary;
Button btnSave;
public static final int SAVE = 100;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add);
getSupportActionBar().setTitle("직원 추가");
// 아래 코드는 돌아갈수 있는 화살표만 화면에 보여준다. (동작은안된다는것)
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
editName = findViewById(R.id.editName);
editAge = findViewById(R.id.editAge);
editSalary = findViewById(R.id.editSalary);
btnSave = findViewById(R.id.btnSave);
btnSave.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String name = editName.getText().toString().trim();
int age = Integer.parseInt(editAge.getText().toString().trim());
int salary = Integer.parseInt(editSalary.getText().toString().trim());
// 이름, 나이, 급여가 모두 있어야 한다!
if (name.isEmpty() || age == 0 || salary == 0) {
Toast.makeText(AddActivity.this, "모든 정보를 입력해주세요", Toast.LENGTH_SHORT).show();
return;
}
// 묶어서 처리할 Employee 클래스를 하나 만든다.
Employee employee = new Employee(name, salary, age);
// 메인 액티비티로 돌아가야 한다.
// employee 객체를 메인엑티비티에 보내준다.
Intent intent = new Intent();
intent.putExtra("employee", employee);
setResult(SAVE, intent);
// 이 액티비티는 할일 다 했으니, 종료하면 된다.
finish();
}
});
}
// 액션바의 돌아가는 화살표를 눌렀을때의 이벤트를 처리하는
// 함수를 오버라이딩 해야 한다.
@Override
public boolean onSupportNavigateUp() {
// 이 액티비티는 할일 다 했으니, 종료하면 된다.
finish();
return super.onSupportNavigateUp();
}
}
EditActivity
package com.leopard4.employeeapp;
import static com.leopard4.employeeapp.AddActivity.SAVE;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.leopard4.employeeapp.model.Employee;
public class EditActivity extends AppCompatActivity {
EditText editSalary;
EditText editAge;
Button btnSave;
Employee employee;
int index;
// 메인액티비티에서 확인할 용도로 상수를 만든다.
// 수정을한건지 뭐한건지 구분하기 위해서
public static final int EDIT = 101;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit);
getSupportActionBar().setTitle("직원 수정");
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
editSalary = findViewById(R.id.editSalary);
editAge = findViewById(R.id.editAge);
btnSave = findViewById(R.id.btnSave);
employee = (Employee) getIntent().getSerializableExtra("employee");
index = getIntent().getIntExtra("index", -1);
editSalary.setText(employee.salary+"");
editAge.setText(employee.age+"");
btnSave.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String strSalary = editSalary.getText().toString().trim();
String strAge = editAge.getText().toString().trim();
if (strSalary.isEmpty() || strAge.isEmpty()) {
Toast.makeText(EditActivity.this, "모두 입력해주세요", Toast.LENGTH_SHORT).show();
return;
}
// 숫자로 변환
// 위에서 받아온 객체에 셋팅해준다.
int salary = Integer.valueOf(strSalary).intValue();
int age = Integer.valueOf(strAge).intValue();
// 묶어서 처리할 클래스를 하나 만든다.
employee.salary = salary;
employee.age = age;
Intent intent = new Intent();
intent.putExtra("employee", employee);
intent.putExtra("index", index);
setResult(EDIT, intent);
// 유저한테 잘 저장되었다고, 알려주고
Toast.makeText(EditActivity.this, "수정되었습니다", Toast.LENGTH_SHORT).show();
// 액티비티 종료, 메인 액티비티로 돌아간다.(메인액티비티는 뒤에 숨어있었으므로)
finish();
}
});
}
@Override
public boolean onSupportNavigateUp() {
finish();
return super.onSupportNavigateUp();
}
}
network_security_config.xml
<?xml version="1.0" encoding="utf-8"?>
<network-security-config xmlns:tools="http://schemas.android.com/tools">
<domain-config cleartextTrafficPermitted="false">
<domain includeSubdomains="true">*.amazonaws.com</domain>
</domain-config>
</network-security-config>
Github
https://github.com/leopard4/EmployeeApp
GitHub - leopard4/EmployeeApp
Contribute to leopard4/EmployeeApp development by creating an account on GitHub.
github.com