3월 17일

오늘 배운 것

  • TODO프로젝트 이용해서 Todo App 만들기 (8)

LocalDate 변환하기

String -> LocalDate 클래스 만들기

public class LocalDateDeserializer implements JsonDeserializer<LocalDate> {

    @Override
    public LocalDate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        LocalDate localDate = LocalDate.parse(json.getAsString(), DateTimeFormatter.ofPattern("yyyyMMdd"));

        return localDate;
    } // deserialize
}

LocalDate -> String 클래스 만들기

    
    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");

    @Override
    public JsonElement serialize(LocalDate src, Type typeOfSrc, JsonSerializationContext context) {
        String strDate = FORMATTER.format(src);
        return new JsonPrimitive(strDate);

Retrofit 생성 시 변환 클래스 추가

    private static Retrofit getInstance() {
        GsonBuilder gsonBuilder = new GsonBuilder();
        gsonBuilder.registerTypeAdapter(LocalDate.class, new LocalDateSerializer());
        gsonBuilder.registerTypeAdapter(LocalDate.class, new LocalDateDeserializer()); // 서버에서 넘어오는 문자열 변환
        Gson gson = gsonBuilder.setPrettyPrinting().create();

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://192.168.219.104:8090") // localhost 사용할 수 없기 때문에 ip주소를 적어준다
                .addConverterFactory(GsonConverterFactory.create(gson))
                .build();

        return retrofit;
    } // getInstance
}

TodoRestServlet 서버에도 변환 메소드 추가

	
 @Override
	public void init(ServletConfig config) throws ServletException {
		System.out.println("TodoRestServlet init() 호출됨");
		GsonBuilder gsonBuilder = new GsonBuilder();
		gsonBuilder.registerTypeAdapter(LocalDate.class, new LocalDateSerializer());
        gsonBuilder.registerTypeAdapter(LocalDate.class, new LocalDateDeserializer());
		gson = gsonBuilder.setPrettyPrinting().create(); // json 줄바꿈 출력
	}

각 item 뷰

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    
    <TextView
        android:id="@+id/tvTodoMeMsg"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="데이터가 없습니다."
        android:textAlignment="center"
        android:textSize="24sp"
        android:textStyle="bold"
        android:visibility="gone" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

새 할 일 추가버튼 만들기, 이름과아이디 알려주기


버튼 클릭 시 loginId 값을 bundle 객체에 넣고 할 일 추가화면으로 이동

        btnTodoAdd.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                MainActivity mainActivity = (MainActivity) getActivity();
                Bundle extraBundle = new Bundle();
                extraBundle.putString("loginId", loginId);

                mainActivity.onFragmentChanged(MainActivity.TODO_ADD, extraBundle);
            }
        });

할 일을 띄움과 동시에 TextView에 이름과 아이디 출력하기

    private void setTodosAndShow(TodoListResult todoListResult) {
        // 응답받은 Result 객체에서 데이터 꺼내기
        User user = todoListResult.getUser();
        String username = user.getFirstName() + " " + user.getLastName() + " (" + user.getUserName() + ")";
        tvUsername.setText(username);

        List<Todo> todoList = user.getTodolist();

        // Todo(할일) 데이터 존재여부 확인
        if (todoList == null || todoList.size() == 0) {
            tvTodoMeMsg.setVisibility(View.VISIBLE);
            return;
        }
        tvTodoMeMsg.setVisibility(View.GONE);
        // Adapter에 데이터 설정하기
//        for (Todo todo : todoList) {
//            adapter.addItem(todo);
//        }
        adapter.setItems(todoList);

        // Adapter에 데이터 갱신 알리기 (recyclerView가 변경된 데이터로 아이템뷰를 다시 화면에 그려줌)
        adapter.notifyDataSetChanged();
    }// setTodosAndShow

새 할 일 추가화면

  • spinner로 진행중, 완료 현재상태 표시하도록 설정하기
  • 날짜 선택 칸 터치 시 날짜 선택 창이 나타나도록 설정하고 입력형식 설정하기
  • 서버연결 지연으로 응답이 늦어질 경우를 대비해서 progressDialog로 처리중임을 나타내기
  • 성공적으로 서버전송 처리 시 progressDialog 닫고 내 할 일 페이지로 이동하기
package com.example.todo.fragment.todo;

import android.app.DatePickerDialog;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.Spinner;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import com.example.todo.MainActivity;
import com.example.todo.R;
import com.example.todo.domain.Todo;
import com.example.todo.domain.TodoResult;
import com.example.todo.retrofit.RetrofitClient;
import com.example.todo.retrofit.TodoService;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class TodoAddFragment extends Fragment {
    public static final String TAG = "TodoAddFragment";
    private EditText txtTitle, txtDescription, txtTargetDate;
    private String loginId;
    private Spinner spinnerStatus;
    private DatePickerDialog datePickerDialog;
    private ProgressDialog progressDialog; // 비동기 방식으로 동작함

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_todo_add,container, false );

        // Bundle 객체 참조 가져오기
        Bundle bundle = getArguments();
        loginId = bundle.getString("loginId");

        txtTitle = view.findViewById(R.id.txtTitle);
        txtDescription = view.findViewById(R.id.txtDescription);
        txtTargetDate = view.findViewById(R.id.txtTargetDate);
        spinnerStatus = view.findViewById(R.id.spinnerStatus);

        // spinner 전용 Adapter라고 생각하면 됨
        // android.R.layout.simple_spinner_item은 처음 보여지는 item
        // android.R.layout.simple_spinner_dropdown_item 밑에 보여지는 item
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(
                getContext(),
                android.R.layout.simple_spinner_item,
                new String[] {"진행중", "완료"}
        );
        // Spinner 클릭 시 펼쳐질 layout 설정
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        // Spinner에 Adapter 설정
        spinnerStatus.setAdapter(adapter);
        // 날짜 선택 EditText에 Touch 이벤트 연결
        txtTargetDate.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
                    // DatePickerDialog 띄우기기
                    datePickerDialog.show();
               }
                return false;
            }
        });

        // 현재 년,월,일 값구하기
        Calendar calendar = Calendar.getInstance();
        int nowYear = calendar.get(Calendar.YEAR);
        int nowMonth = calendar.get(Calendar.MONTH); // 영미권은 0~11, 출력할 때는 +1을 해줘야함 (ex 1월 = 0, 2월 = 1)
        int nowDay = calendar.get(Calendar.DAY_OF_MONTH);

        //날짜선택 대화상자 준비하기
        datePickerDialog = new DatePickerDialog(getContext(), new DatePickerDialog.OnDateSetListener() {
            @Override // 최종 결정할 때 호출됨
            public void onDateSet(DatePicker datePicker, int year, int month, int day) {
                String strDate = "";
                strDate += year;
                strDate += "-" + String.format("%02d", month + 1); // 2자리 숫자로 만드는데 한자리면 앞에 0을 붙임
                strDate += "-" + String.format("%02d", day);

                txtTargetDate.setText(strDate);
            }// onDateSet
        },nowYear, nowMonth, nowDay);

        // progressDialog 설정하기
        progressDialog = new ProgressDialog(getContext());
        progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        progressDialog.setMessage("처리 중 입니다....");

        // 할 일 저장 버튼 클릭 이벤트 연결
        Button btnTodoSave = view.findViewById(R.id.btnTodoSave);
        btnTodoSave.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                btnTodoSave.setEnabled(false); // 버튼 비활성화
                progressDialog.show(); // 로딩 중
                requestAddTodo(); // 서버에 새 Todo 등록

            }
        });

        return view;
    } // onCreateView
    private void requestAddTodo() {

        String title = txtTitle.getText().toString().trim();
        String description = txtDescription.getText().toString().trim();
        String strStatus = (String) spinnerStatus.getSelectedItem();
        String strDate = txtTargetDate.getText().toString().trim();


        // localDate 변환
        LocalDate localDate = LocalDate.parse(strDate, DateTimeFormatter.ofPattern("yyyy-MM-dd"));

        // 추가할 Todo 객체 준비
        Todo todo = new Todo();
        todo.setUsername(loginId);
        todo.setTitle(title);
        todo.setDescription(description);
        todo.setStatus(strStatus.equals("완료")? true : false);
        todo.setTargetDate(localDate);

        Log.d(TAG, "todo : " + todo.toString());

        TodoService todoService = RetrofitClient.getTodoService();

        Call<TodoResult> call = todoService.addTodo(todo);

        call.enqueue(new Callback<TodoResult>() {
            @Override
            public void onResponse(Call<TodoResult> call, Response<TodoResult> response) {
                if (!response.isSuccessful()) {
                    Log.d(TAG,"onResponse : " + response.message());
                    return;
                }
                TodoResult todoResult = response.body();

                if (todoResult.isSuccess()) {
                    onResponseSuccess();
                }
            }

            @Override
            public void onFailure(Call<TodoResult> call, Throwable t) {
                Log.d(TAG, "onFailure : " + t.getMessage());
            }
        });

    }// requestAddTodo

    private void onResponseSuccess() {
        progressDialog.dismiss(); // progressDialog 닫기

        Bundle bundle = new Bundle();
        bundle.putString("loginId", loginId);

        MainActivity mainActivity = (MainActivity) getActivity();
        mainActivity.onFragmentChanged(MainActivity.TODO_ME, bundle);
    }// onResponseSuccess

}


좋은 웹페이지 즐겨찾기