본문 바로가기
Android

Android [회사직원관리앱] 양방향통신 launcher가 안될때/ 액션바 메뉴/ fab / 네트워크 프로그래스바

by leopard4 2023. 2. 6.

 

리사이클뷰 어댑터를 이용한 양방향 통신시 

context는 현재 호출되고있는 MainActivity 인데 

MainActivity 의 디폴트 멤버변수인 launcher가 접근이 안됨 

 

따라서, 

MainActivity 의 멤버변수

어댑터에서 접근할 멤버변수를 public 으로 바꾼뒤

어댑터로 파일에서 ((MainActivity)) 로 캐스팅을 하고

. 을해보면 접근 가능한 멤버변수와 메소드의 리스트를 확인할수있다.

 

액션바 디렉토리를 생성하는모습
액션바 아이디 설정

액티비티 별로 액션바를 만드는방법

액티비티 별로 액션바를 만드는방법

 

add액티비티용 액션바 메뉴
add액티비티용 액션바 메뉴

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