3月18日

70417 ワード

きょう習った

  • TODOプロジェクトを使用してTODO Appを作成(9)
  • 「保留中の変更と削除」画面の作成


    「≪既存の保留中の追加|Add Existing Pending|emdw≫」画面を使用して作成
  • [デイリービュー]をクリックして[修正と削除]画面
  • に移動するように設定.
  • が移動すると、選択したアイテムのid値がバンドルされたオブジェクトに挿入され、「修正」画面および「削除」画面
  • に移動します.
                // 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に対応するデータを取得し、ビューオブジェクトごとにテキスト設定
  • を設定する.

    [修正](Modify)ボタンと[削除](Delete)ボタンの後に自分で作成...

    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

    画像ファイルの受信と出力


    画像ファイルを受信するには、サーバ上で操作する必要があります.
    △画像ファイルだけでなく、他のタイプのファイルも送信できると思います.
    DisplayImageServiceletを作成し、
  • イメージファイル転送を担当
    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


    アイテムのテキストを設定すると、画像ファイルも
            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のプロファイル画像の変更

  • apterは要求をハンドラに送信し、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