3월 18일

SJY0000·2022년 3월 20일
0

Android

목록 보기
14/15

오늘 배운 것

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

할 일 수정 및 삭제화면 만들기

기존의 할 일 추가화면을 이용해서 만들기

  • 각 할 일 View를 클릭 시 수정 및 삭제화면으로 이동하게 설정
  • 이동 시 선택한 item의 id값을 bundle객체에 넣고 수정 및 삭제화면으로 이동
            // item 클릭 이벤트 설정
            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                   // 선택된 아이템의 순서정보
                    int position = getAdapterPosition();

                    Todo todo = items.get(position);
                    Log.d(TAG, "선택 아이템 : " + todo.toString());

                    // 할일 수정, 삭제 화면으로 이동하기
                    long todoId = todo.getId();
                    Log.d(TAG, "선택 아이템 : " + todo.getId());

                    Bundle bundle = new Bundle();
                    bundle.putLong("id", todoId);
                    MainActivity mainActivity = (MainActivity) fragment.getActivity();
                    mainActivity.onFragmentChanged(MainActivity.TODO_MODIFY_REMOVE, bundle);
                }
            });
  • 넘어온 id 값을 서버에 전송해 id에 해당하는 데이터 가져와서 각 View 객체에 텍스트 설정

수정 및 삭제버튼은 나중에 각자 알아서 만들어보기....

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.EditText;
import android.widget.Spinner;

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

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

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

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

public class TodoModifyRemoveFragment extends Fragment {
    private static final String TAG = "TodoModifyRemoveFragment";
    private long todoId;
    private EditText txtTitle, txtDescription, txtTargetDate;
    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_modify_remove, container, false);

        //Bundle 객체 참조가져오기
        Bundle bundle = getArguments();
        todoId = bundle.getLong("id");
        Log.d(TAG, "todoId : " + todoId);

        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[] {"진행중", "완료"} // index는 0 , 1
        );
        // 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 띄우기기
                    if (datePickerDialog != null) {
                        datePickerDialog.show();
                    }
                }
                return false;
            }
        });

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

        requestGetTodoByTodoId(todoId);



        return view;
    } // onCreateView
    private void requestGetTodoByTodoId(long todoId) {
        TodoService todoService = RetrofitClient.getTodoService();

        Call<TodoOneResult> call= todoService.getTodoById("one", todoId);

        call.enqueue(new Callback<TodoOneResult>() {
            @Override
            public void onResponse(Call<TodoOneResult> call, Response<TodoOneResult> response) {
                if (!response.isSuccessful()) {
                    Log.d(TAG,"onResponse : " + response.message());
                    return;
                }
                TodoOneResult todoOneResult = response.body();
                if (todoOneResult.isHasResult()) {
                    Todo todo = todoOneResult.getTodo();
                    setTodoAndShow(todo);
                }

            }

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

    private void setTodoAndShow(Todo todo) {
        txtTitle.setText(todo.getTitle());
        txtDescription.setText(todo.getDescription());

        if (todo.isStatus()) { // true이면 완료
            spinnerStatus.setSelection(1);
        } else { // false이면 진행중
            spinnerStatus.setSelection(0);
        }

        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String strDate = dateTimeFormatter.format(todo.getTargetDate());
        txtTargetDate.setText(strDate);

        progressDialog.dismiss();

    }// setTodoAndShow

}// class TodoModifyRemoveFragment


이미지 파일 전송받아 출력하기

이미지파일을 전송받으려면 서버에서 작업이 필요함
(이미지파일 뿐만 아니라 다른 종류의 파일들도 보낼 수 있지 않을까 싶음)

  • 이미지파일 전송을 담당할 DisplayImageServlet을 생성
package todoApp.rest.todo;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(urlPatterns = "/displayImage", loadOnStartup = 1)
public class DisplayImageServlet extends HttpServlet {

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// (경로가 포함된) 이미지 파일명을 파라미터로 가져오기
		String filename = request.getParameter("filename"); // leaf.png
		//  파일 경로에 / 나 \\ 사용해야 잘못 인식하지 않는다.
		File file = new File("C:/java502/Image", filename); // C:\java502\Image/leaf.png
		
		if (!file.exists()) { // file 없으면
			System.out.println("요청한 이미지 파일이 해당 경로에 존재하지 않습니다.");
			return;
		}
		
		// 이미지 파일을 전송할것이기 때문에 image/png , image/gif 등 파일의 이미지 확장자가 출력됨
		String contentType = Files.probeContentType(file.toPath());
		
		response.setContentType(contentType);
		
		// 입력스트림 객체 준비
		BufferedInputStream is = new BufferedInputStream(new FileInputStream(file));
		// 출력스트림 객체 준비
		BufferedOutputStream os = new BufferedOutputStream(response.getOutputStream());
		
		int data;
		while ((data = is.read()) != -1) { // -1이면 데이터 있음, 아니면 없음
			os.write(data);
		}// while
		os.flush(); // 출력버퍼 비우기, 객체를 닫을 꺼면 없어도 됨
		
		// 스트림 객체 닫기
		is.close();
		os.close();
		
		
	} // doGet
}

TodoMeAdapter

아이템의 text설정 시 이미지파일도 같이 설정되게함

        public void setItem(Todo item) {
            if (item == null) {
                return;
            }
            // 날짜 변환
            LocalDate localDate = item.getTargetDate();
            String strDate = localDate.format(DateTimeFormatter.ofPattern("yyyy년 MM월 dd일"));

            tvTitle.setText(item.getTitle());
            tvDescription.setText(item.getDescription());
            tvtvTagetDate.setText(strDate);
            tvtvDone.setText(item.isStatus() ? "완료" : "진행중");

            // Todo 객체 안에 이미지 파일명을 가져왔다고 가정
            // ex) String filename = item.getImageFileName();
            String filename = "leaf.jpg";
            // 서버에 filename 이미지 요청하기
            requestImage(filename);


        }// setItem

이미지 요청 메소드

private void requestImage(String filename) {
        TodoService todoService = RetrofitClient.getTodoService();

        Call<ResponseBody> call = todoService.downloadImage(filename);

        call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                if (!response.isSuccessful()) {
                    Log.d(TAG, "onResponse : " + response.message());
                    return;
                }
                InputStream is = response.body().byteStream();
                // 작업스레드에서 네트워크 스트림으로 이미지 읽어서 Bitmap객체 준비
                // 네트워크 처리는 Thread 처리를 해서 병렬처리를 해야함
                new Thread(() -> {
                    // 이미지 용량 줄이는 방법 1: 일정 배수로 이미지 용량 줄이기
                    // 읽어 올 때 용량을 줄여서 읽어옴
                    BitmapFactory.Options options = new BitmapFactory.Options();
                    options.inSampleSize = 4; // 이미지 크기를 4분의 1로 줄여서 읽어오도록 설정
                    // InputStream의 바이너리정보를 이미지객체로 변환
                    Bitmap bitmap = BitmapFactory.decodeStream(is,null, options);
                    // 이미지 용량 줄이는 방법 2 : 이미지뷰 크기로 이미지 용량 줄이기
                    // pixel 값으로 기기마다 다름
                    int width = img1.getWidth();
                    int height = img1.getHeight();

                    // 이미지용량이 클 경우 강제적으로 이미지 용량을 줄여야함
                    Bitmap resizedBitmap = Bitmap.createScaledBitmap(bitmap, width, height, true);

                    handler.post(() -> {
                        // UI 메인스레드에서 뷰에 접근함
                        // 이미지뷰에 사진 설정
                        img1.setImageBitmap(resizedBitmap);
                    });
                }).start();
            }

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

drawer의 프로필이미지도 변경

  • apater에서는 handler로 요청보내고 MainActivity에서는 runOnUiThread로 요청하는 것을 제외하면 동일한 메소드
 private void requestImage() {
        Log.d(TAG, "requestImage 호출됨");
        TodoService todoService = RetrofitClient.getTodoService();

        Call<ResponseBody> call = todoService.downloadImage(filename);

        call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                if (!response.isSuccessful()) {
                    Log.d(TAG, "onResponse : " + response.message());
                    return;
                }
                InputStream is = response.body().byteStream();
                // 작업스레드에서 네트워크 스트림으로 이미지 읽어서 Bitmap객체 준비
                // 네트워크 처리는 Thread 처리를 해서 병렬처리를 해야함
                new Thread(() -> {
                    // 이미지 용량 줄이는 방법 1: 일정 배수로 이미지 용량 줄이기
                    // 읽어 올 때 용량을 줄여서 읽어옴
                    BitmapFactory.Options options = new BitmapFactory.Options();
                    options.inSampleSize = 4; // 이미지 크기를 4분의 1로 줄여서 읽어오도록 설정
                    // InputStream의 바이너리정보를 이미지객체로 변환
                    Bitmap bitmap = BitmapFactory.decodeStream(is,null, options);
                    // 이미지 용량 줄이는 방법 2 : 이미지뷰 크기로 이미지 용량 줄이기
                    // pixel 값으로 기기마다 다름
                    int width = imageProfile.getWidth();
                    int height =imageProfile.getHeight();
//
//                    // 이미지용량이 클 경우 강제적으로 이미지 용량을 줄여야함
                    Bitmap resizedBitmap = Bitmap.createScaledBitmap(bitmap, width, height, true);

                    runOnUiThread(()->imageProfile.setImageBitmap(resizedBitmap));
                    readyImgProfile = true;

                }).start();
            }

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

0개의 댓글

관련 채용 정보