XML 및 파일구성
앱기능
MemoApi
package com.leopard4.memoapp.api;
import com.leopard4.memoapp.model.Memo;
import com.leopard4.memoapp.model.MemoList;
import com.leopard4.memoapp.model.Res;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.DELETE;
import retrofit2.http.GET;
import retrofit2.http.Header;
import retrofit2.http.POST;
import retrofit2.http.PUT;
import retrofit2.http.Path;
import retrofit2.http.Query;
public interface MemoApi {
// 내 메모 가져오는 API
@GET("/memos")
Call<MemoList> getMemoList(@Header("Authorization") String token, @Query("offset") int offset, @Query("limit") int limit);
// 메모 생성 API
@POST("/memos")
Call<Res> createMemo(@Body Memo memo, @Header("Authorization") String token);
// 메모 수정 API
@PUT("/memos/{memoId}")
Call<Res> updateMemo(@Path("memoId") int memoId, @Header("Authorization") String token, @Body Memo memo);
// Call<Res>는 응답을 받을 때 사용하는 클래스 Res클래스 안에는 result라는 변수가 있음 PostMan에서 보던 result와 같음
// 메모 삭제 API
@DELETE("/memos/{memoId}")
Call<Res> deleteMemo(@Path("memoId") int memoId, @Header("Authorization") String token);
}
UserApi
package com.leopard4.memoapp.api;
import com.leopard4.memoapp.model.User;
import com.leopard4.memoapp.model.UserRes;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.Header;
import retrofit2.http.POST;
import retrofit2.http.Query;
// 유저 관련 API 들을 모아놓은 인터페이스
public interface UserApi {
// 회원가입 API 함수 작성
@POST("/user/register") // API 명세서에 있는 경로를 작성한다.
Call<UserRes> register(@Body User user); // Body 에 Json 으로 데이터를 보낸다. // Call<UserRes> 는 응답을 받을 클래스를 지정한다.
// 로그인 API 함수 작성
@POST("/user/login")// @의 의미는 레트로핏 라이브러리가 이 함수를 레트로핏 API 로 사용한다는 의미이다.
Call<UserRes> login(@Body User user);
// 로그아웃 API
@POST("/user/logout")
Call<UserRes> logout(@Header("Authorization") String token);
}
Res
package com.leopard4.memoapp.model;
public class Res {
private String result;
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
}
Memo
package com.leopard4.memoapp.model;
import java.io.Serializable;
public class Memo implements Serializable {
private int id;
private String title;
private String datetime;
private String content;
private String createdAt;
private String updatedAt;
public Memo() {
}
public Memo(String title, String datetime, String content) {
this.title = title;
this.datetime = datetime;
this.content = content;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDatetime() {
return datetime;
}
public void setDatetime(String datetime) {
this.datetime = datetime;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getCreatedAt() {
return createdAt;
}
public void setCreatedAt(String createdAt) {
this.createdAt = createdAt;
}
public String getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(String updatedAt) {
this.updatedAt = updatedAt;
}
}
NetworkClient
package com.leopard4.memoapp.api;
import android.content.Context;
import com.leopard4.memoapp.config.Config;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class NetworkClient {
public static Retrofit retrofit;
public static Retrofit getRetrofitClient(Context context){
if(retrofit == null){
// 통신 로그 확인할때 필요한 코드
HttpLoggingInterceptor loggingInterceptor =
new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); // 실배포시는 NONE으로 설정 (해킹문제)
// 네트워크 연결관련 코드
OkHttpClient httpClient = new OkHttpClient.Builder()
.connectTimeout(1, TimeUnit.MINUTES)
.readTimeout(1, TimeUnit.MINUTES)
.writeTimeout(1, TimeUnit.MINUTES)
.addInterceptor(loggingInterceptor)
.build();
// 네트워크로 데이터를 보내고 받는
// 레트로핏 라이브러리 관련 코드
retrofit = new Retrofit.Builder()
.baseUrl(Config.DOMAIN)
.client(httpClient)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
매인액티비티
package com.leopard4.memoapp;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
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.leopard4.memoapp.adapter.MemoAdapter;
import com.leopard4.memoapp.api.MemoApi;
import com.leopard4.memoapp.api.NetworkClient;
import com.leopard4.memoapp.api.UserApi;
import com.leopard4.memoapp.config.Config;
import com.leopard4.memoapp.model.Memo;
import com.leopard4.memoapp.model.MemoList;
import com.leopard4.memoapp.model.Res;
import com.leopard4.memoapp.model.UserRes;
import java.util.ArrayList;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
public class MainActivity extends AppCompatActivity {
Button btnAdd;
ProgressBar progressBar;
String accessToken;
RecyclerView recyclerView;
MemoAdapter adapter;
ArrayList<Memo> memoArrayList = new ArrayList<>();
ProgressDialog dialog;
// 페이징 처리를 위한 변수
int offset = 0;
int limit = 2;
int count = 0;
int secondDeleteIndex;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 억세스토큰이 저장되어있으면,
// 로그인한 유저이므로 메인액티비티를 실행하고,
// 그렇지 않으면, 회원가입 액티비티를 실행하고,
// 메인액티비티는 종료!
SharedPreferences sp = getSharedPreferences(Config.PREFERENCE_NAME, MODE_PRIVATE);
accessToken = sp.getString(Config.ACCESS_TOKEN, "");
Log.i("MEMO_APP",accessToken);
if (accessToken.isEmpty()) {
// 회원가입 액티비티 실행
Intent intent = new Intent(this, RegisterActivity.class);
startActivity(intent);
finish();
return;
}
// 회원가입/로그인 유저면, 메인액티비티 실행
btnAdd = findViewById(R.id.btnAdd);
progressBar = findViewById(R.id.progressBar);
recyclerView = findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
// 스크롤이 끝에 도달했는지 확인
int lastPosition = ((LinearLayoutManager)recyclerView.getLayoutManager()).findLastCompletelyVisibleItemPosition();
int totalCount = recyclerView.getAdapter().getItemCount();
if (lastPosition + 1 == totalCount ) {
// 스크롤이 끝에 도달했을 때, 데이터를 추가로 가져옴
if (count == limit) { // 카운트가 총갯수이므로 총갯수와 같으면 더이상 가져올 데이터가 없음
addNetworkData();
}
}
}
});
// 메모생성버튼
btnAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, MemoAddActivity.class);
startActivity(intent);
}
});
}
private void addNetworkData() {
progressBar.setVisibility(View.VISIBLE);
Retrofit retrofit = NetworkClient.getRetrofitClient(this);
MemoApi api = retrofit.create(MemoApi.class);
Call<MemoList> call = api.getMemoList("Bearer " + accessToken, offset, limit);
call.enqueue(new Callback<MemoList>() {
@Override
public void onResponse(Call<MemoList> call, Response<MemoList> response) {
progressBar.setVisibility(View.GONE);
if (response.isSuccessful()) {
// 성공시, 메모리스트를 어레이리스트에 저장
MemoList memoList = response.body();
memoArrayList.addAll(memoList.getItems());
// 어댑터 갱신
adapter.notifyDataSetChanged();
// 오프셋을 다음 페이지로 변경
count = memoList.getCount();
offset = offset + count;
} else {
// 실패
progressBar.setVisibility(View.GONE);
Toast.makeText(MainActivity.this, "메모를 불러오는데 실패했습니다.", Toast.LENGTH_SHORT).show();
return;
}
}
@Override
public void onFailure(Call<MemoList> call, Throwable t) {
progressBar.setVisibility(View.GONE);
}
});
}
private void getNetworkData() {
progressBar.setVisibility(View.VISIBLE);
Retrofit retrofit = NetworkClient.getRetrofitClient(this);
MemoApi api = retrofit.create(MemoApi.class);
// 오프셋 초기화는, 함수 호출하기 전에!!
offset = 0; // 오프셋 초기화
count = 0; // 카운트 초기화
Call<MemoList> call = api.getMemoList("Bearer " + accessToken, offset, limit);
call.enqueue(new Callback<MemoList>() {
@Override
public void onResponse(Call<MemoList> call, Response<MemoList> response) {
progressBar.setVisibility(View.GONE);
if (response.isSuccessful()) {
// 성공시, 메모리스트를 어레이리스트에 저장
MemoList memoList = response.body();
memoArrayList.clear(); // 기존 배열리스트가 존재하지 않게 초기화
memoArrayList.addAll(memoList.getItems());
// 메모리스트를 어댑터에 연결
adapter = new MemoAdapter(MainActivity.this, memoArrayList);
recyclerView.setAdapter(adapter);
// 오프셋 처리하는 코드
count = memoList.getCount(); // 전체 메모 개수(페이징처리용)
offset = offset + count; // 다음 페이지를 위한 오프셋
} else {
// 실패
progressBar.setVisibility(View.GONE);
Toast.makeText(MainActivity.this, "메모를 불러오는데 실패했습니다.", Toast.LENGTH_SHORT).show();
return;
}
}
@Override
public void onFailure(Call<MemoList> call, Throwable t) {
progressBar.setVisibility(View.GONE);
}
});
}
@Override
public boolean onCreateOptionsMenu(@NonNull Menu menu){
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public boolean onOptionsItemSelected(@NonNull MenuItem item){
int itemId = item.getItemId();
if(itemId == R.id.menuLogout){
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("로그아웃");
builder.setMessage("로그아웃 하시겠습니까?");
builder.setPositiveButton("예", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
showProgress("로그아웃 중입니다.");
Retrofit retrofit = NetworkClient.getRetrofitClient(MainActivity.this);
UserApi api = retrofit.create(UserApi.class);
Call<UserRes> call = api.logout("Bearer " + accessToken);
call.enqueue(new Callback<UserRes>() {
@Override
public void onResponse(Call<UserRes> call, Response<UserRes> response) {
dismissProgress();
if(response.isSuccessful()){
// 쉐어드 프리퍼런스에 저장한 토큰을 초기화!!
SharedPreferences sp = getApplication().getSharedPreferences(Config.PREFERENCE_NAME, MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putString(Config.ACCESS_TOKEN, "");
editor.apply();
// 기획 : 앱종료
// finish();
// 기획 : 로그아웃하면, 로그인 화면을 띄우도록
Intent intent = new Intent(MainActivity.this, LoginActivity.class);
startActivity(intent);
finish();
}else{
// 로그아웃 실패
Toast.makeText(MainActivity.this, "로그아웃에 실패했습니다.", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<UserRes> call, Throwable t) {
dismissProgress();
Toast.makeText(MainActivity.this, "로그아웃에 실패했습니다.", Toast.LENGTH_SHORT).show();
}
});
}
});
builder.setNegativeButton("아니오", null);
builder.show();
}
return super.onOptionsItemSelected(item);
}
void showProgress(String message){
dialog = new ProgressDialog(this);
dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
dialog.setMessage(message);
dialog.show();
}
// 로직처리가 끝나면 화면에서 사라지는 함수
void dismissProgress(){
dialog.dismiss();
}
@Override
protected void onResume() {
super.onResume();
// 네트워크로부터 내 메모를 가져온다.
getNetworkData();
}
public void deleteMemo(int deleteIndex) {
secondDeleteIndex = deleteIndex;
// 네트워크로 메모 삭제하는 코드 작성
Retrofit retrofit = NetworkClient.getRetrofitClient(MainActivity.this);
MemoApi api = retrofit.create(MemoApi.class); // 인터페이스 객체 생성
Memo memo = memoArrayList.get(deleteIndex);
SharedPreferences sp = getApplication().getSharedPreferences(Config.PREFERENCE_NAME, MODE_PRIVATE);
String accessToken = sp.getString(Config.ACCESS_TOKEN, "");
Call<Res> call = api.deleteMemo(memo.getId(), "Bearer " + accessToken);
call.enqueue(new Callback<Res>() {
@Override
public void onResponse(Call<Res> call, Response<Res> response) {
if(response.isSuccessful()){
// 삭제 성공
Toast.makeText(MainActivity.this, "메모를 삭제했습니다.", Toast.LENGTH_SHORT).show();
// 삭제한 메모를 리스트에서 제거
memoArrayList.remove(secondDeleteIndex);
// 어댑터에 변경사항 알림
adapter.notifyDataSetChanged();
}else{
// 삭제 실패
Toast.makeText(MainActivity.this, "메모를 삭제하는데 실패했습니다.", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<Res> call, Throwable t) {
Toast.makeText(MainActivity.this, "메모를 삭제하는데 실패했습니다.", Toast.LENGTH_SHORT).show();
}
}
);
}
}
에딧액티비티
package com.leopard4.memoapp;
import androidx.appcompat.app.AppCompatActivity;
import android.app.DatePickerDialog;
import android.app.ProgressDialog;
import android.app.TimePickerDialog;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.Toast;
import com.leopard4.memoapp.api.MemoApi;
import com.leopard4.memoapp.api.NetworkClient;
import com.leopard4.memoapp.config.Config;
import com.leopard4.memoapp.model.Memo;
import com.leopard4.memoapp.model.Res;
import java.util.Calendar;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
public class MemoEditActivity extends AppCompatActivity {
EditText editTitle;
EditText editContent;
Button btnSave, btnDate, btnTime;
private ProgressDialog dialog;
String datetime;
private String date;
private String time;
int memoId;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_memo_add);
// 액티비티 재실행시 멤버변수가 초기화되는지 확인 // 초기화됨
Log.i("RESET?",date + time);
editTitle = findViewById(R.id.editTitle);
editContent = findViewById(R.id.editContent);
btnSave = findViewById(R.id.btnSave);
btnDate = findViewById(R.id.btnDate);
btnTime = findViewById(R.id.btnTime);
Memo memo = (Memo) getIntent().getSerializableExtra("memo");
memoId = memo.getId();
editTitle.setText(memo.getTitle());
editContent.setText(memo.getContent());
// "2023-08-03T11:30:00"
// "2023-08-03T11:30"
String[] dateArray = memo.getDatetime().substring(0,15+1).split("T");
date = dateArray[0];
time = dateArray[1];
btnDate.setText(date+"");
btnTime.setText(time+"");
// 0. 날짜선택 버튼을 누르면 년,월,일선택
btnDate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 오늘 날짜 가져오기
Calendar current = Calendar.getInstance();
current.get(Calendar.YEAR);
new DatePickerDialog(MemoEditActivity.this, new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker datePicker, int i, int i1, int i2){
Log.i("MEMO_APP", "년도: " + i + ", 월: " + i1 + ", 일: " + i2);
// i: 년도, i1: 월(0~11), i2: 일
int month = i1 + 1;
String monthStr;
if (month < 10) {
monthStr = "0" + month;
} else {
monthStr = "" + month;
}
String dayStr;
if (i2 < 10) {
dayStr = "0" + i2;
} else {
dayStr = "" + i2;
}
date = i + "-" + monthStr + "-" + dayStr;
btnDate.setText(date);
}
},
current.get(Calendar.YEAR),
current.get(Calendar.MONTH),
current.get(Calendar.DAY_OF_MONTH)
).show();
}
});
// 0-1. 시간선택 버튼을 선택하면 시,분 선택
btnTime.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Calendar current = Calendar.getInstance();
new TimePickerDialog(
MemoEditActivity.this,
new TimePickerDialog.OnTimeSetListener() {
@Override
public void onTimeSet(android.widget.TimePicker timePicker, int i, int i1) {
Log.i("MEMO_APP", "시: " + i + ", 분: " + i1);
// i: 시, i1: 분
String hourStr;
if (i < 10) {
hourStr = "0" + i;
} else {
hourStr = "" + i;
}
String minuteStr;
if (i1 < 10) {
minuteStr = "0" + i1;
} else {
minuteStr = "" + i1;
}
time = hourStr + ":" + minuteStr;
btnTime.setText(time);
}
},
current.get(Calendar.HOUR_OF_DAY),
current.get(Calendar.MINUTE),
true
).show();
}
});
btnSave.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 1. 입력한 제목과 내용을 가져온다.
String title = editTitle.getText().toString().trim();
String content = editContent.getText().toString().trim();
if(date == null || time == null){
Toast.makeText(MemoEditActivity.this, "날짜와 시간을 선택해주세요.", Toast.LENGTH_SHORT).show();
return;
}
datetime = date + " " + time;
Log.i("TOTAL_DATE",datetime);
// 2. 제목과 내용이 비어있는지 체크한다.
if (title.length() == 0 || content.length() == 0) {
Toast.makeText(MemoEditActivity.this, "제목과 내용을 입력해주세요.", Toast.LENGTH_SHORT).show();
return;
}
// 네트워크 호출하는 코드
// 로딩 다이얼로그를 보여준다.
showProgress("메모를 수정하고 있습니다.");
Retrofit retrofit = NetworkClient.getRetrofitClient(MemoEditActivity.this);
MemoApi api = retrofit.create(MemoApi.class);
Memo memo = new Memo( title, datetime, content);
// 토큰이 있는지 확인
SharedPreferences sp = getSharedPreferences(Config.PREFERENCE_NAME, MODE_PRIVATE);
String accessToken = sp.getString(Config.ACCESS_TOKEN, "");
Call<Res> call = api.updateMemo(memoId ,"Bearer " + accessToken, memo); // <Res>로 리턴하라
call.enqueue(new Callback<Res>() {
@Override
public void onResponse(Call<Res> call, Response<Res> response) {
// 3-3. 로딩 다이얼로그를 사라지게 한다.
dismissProgress();
if (response.isSuccessful()) { // 응답코드가 200~300 사이인 경우
// 3-4. 메모 목록 화면으로 이동한다.
// 실무에서는 네트워크 절약을위해 back버튼을 누르면 result코드에따라 런처를 이용해서 메인화면으로 이동
finish();
} else {
Toast.makeText(MemoEditActivity.this, "서버와 통신 중 오류가 발생했습니다.", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<Res> call, Throwable t) {
Toast.makeText(MemoEditActivity.this, "서버와 통신 중 오류가 발생했습니다.", Toast.LENGTH_SHORT).show();
dismissProgress();
}
});
}
});
}
void showProgress(String message){
dialog = new ProgressDialog(this);
dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
dialog.setMessage(message);
dialog.show();
}
// 로직처리가 끝나면 화면에서 사라지는 함수
void dismissProgress(){
dialog.dismiss();
}
}
매모어댑터
package com.leopard4.memoapp.adapter;
import static android.content.Context.MODE_PRIVATE;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.cardview.widget.CardView;
import androidx.recyclerview.widget.RecyclerView;
import com.leopard4.memoapp.MainActivity;
import com.leopard4.memoapp.MemoEditActivity;
import com.leopard4.memoapp.R;
import com.leopard4.memoapp.api.MemoApi;
import com.leopard4.memoapp.api.NetworkClient;
import com.leopard4.memoapp.config.Config;
import com.leopard4.memoapp.model.Memo;
import com.leopard4.memoapp.model.Res;
import java.util.ArrayList;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
public class MemoAdapter extends RecyclerView.Adapter<MemoAdapter.ViewHolder>{
Context context;
ArrayList<Memo> memoList;
int deleteIndex;
int id;
private ProgressDialog dialog;
public MemoAdapter(Context context, ArrayList<Memo> memoList) {
this.context = context;
this.memoList = memoList;
}
@NonNull
@Override
public MemoAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.memo_row, parent, false);
return new MemoAdapter.ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull MemoAdapter.ViewHolder holder, int position) {
Memo memo = memoList.get(position);
holder.txtTitle.setText(memo.getTitle());
// "2023-08-03T11:30:00"
// "2023-08-03 11:30:00"
// "2023-08-03 11:30"
String date = memo.getDatetime().replace("T", " ").substring(0, 15+1);
holder.txtDate.setText(date);
holder.txtContent.setText(memo.getContent());
}
@Override
public int getItemCount() {
return memoList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView txtTitle;
TextView txtDate;
TextView txtContent;
ImageView imgDelete;
CardView cardView;
public ViewHolder(@NonNull View itemView) {
super(itemView);
txtTitle = itemView.findViewById(R.id.txtTitle);
txtDate = itemView.findViewById(R.id.txtDate);
txtContent = itemView.findViewById(R.id.txtContent);
imgDelete = itemView.findViewById(R.id.imgDelete);
cardView = itemView.findViewById(R.id.cardView);
cardView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = getAdapterPosition();
Memo memo = memoList.get(position);
Intent intent = new Intent(context, MemoEditActivity.class);
intent.putExtra("memo", memo);
context.startActivity(intent);
}
});
// ok 버튼을 클릭하면 메모 삭제하는 api
imgDelete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.i("DELETE_INDEX", deleteIndex+"" );
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("메모 삭제");
builder.setMessage("메모를 삭제하시겠습니까?");
builder.setPositiveButton("확인", (dialog, which) -> {
deleteIndex = getAdapterPosition();
// 함수로 뺀건 네트워크 데이터를 아끼기위함인듯함
((MainActivity)context).deleteMemo(deleteIndex);
});
builder.setNegativeButton("취소", null);
builder.show();
}
});
}
}
void showProgress(String message){
dialog = new ProgressDialog(context);
dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
dialog.setMessage(message);
dialog.show();
}
// 로직처리가 끝나면 화면에서 사라지는 함수
void dismissProgress(){
dialog.dismiss();
}
}
addActivity
package com.leopard4.memoapp;
import androidx.appcompat.app.AppCompatActivity;
import android.app.DatePickerDialog;
import android.app.TimePickerDialog;
import android.app.ProgressDialog;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.Toast;
import com.leopard4.memoapp.api.MemoApi;
import com.leopard4.memoapp.api.NetworkClient;
import com.leopard4.memoapp.config.Config;
import com.leopard4.memoapp.model.Memo;
import com.leopard4.memoapp.model.Res;
import java.util.Calendar;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
public class MemoAddActivity extends AppCompatActivity {
EditText editTitle;
EditText editContent;
Button btnSave, btnDate, btnTime;
private ProgressDialog dialog;
String datetime;
private String date;
private String time;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_memo_add);
// 액티비티 재실행시 멤버변수가 초기화되는지 확인 // 초기화됨
Log.i("RESET?",date + time);
editTitle = findViewById(R.id.editTitle);
editContent = findViewById(R.id.editContent);
btnSave = findViewById(R.id.btnSave);
btnDate = findViewById(R.id.btnDate);
btnTime = findViewById(R.id.btnTime);
// 0. 날짜선택 버튼을 누르면 년,월,일선택
btnDate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 오늘 날짜 가져오기
Calendar current = Calendar.getInstance();
current.get(Calendar.YEAR);
new DatePickerDialog(MemoAddActivity.this, new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker datePicker, int i, int i1, int i2){
Log.i("MEMO_APP", "년도: " + i + ", 월: " + i1 + ", 일: " + i2);
// i: 년도, i1: 월(0~11), i2: 일
int month = i1 + 1;
String monthStr;
if (month < 10) {
monthStr = "0" + month;
} else {
monthStr = "" + month;
}
String dayStr;
if (i2 < 10) {
dayStr = "0" + i2;
} else {
dayStr = "" + i2;
}
date = i + "-" + monthStr + "-" + dayStr;
btnDate.setText(date);
}
},
current.get(Calendar.YEAR),
current.get(Calendar.MONTH),
current.get(Calendar.DAY_OF_MONTH)
).show();
}
});
// 0-1. 시간선택 버튼을 선택하면 시,분 선택
btnTime.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Calendar current = Calendar.getInstance();
new TimePickerDialog(
MemoAddActivity.this,
new TimePickerDialog.OnTimeSetListener() {
@Override
public void onTimeSet(android.widget.TimePicker timePicker, int i, int i1) {
Log.i("MEMO_APP", "시: " + i + ", 분: " + i1);
// i: 시, i1: 분
String hourStr;
if (i < 10) {
hourStr = "0" + i;
} else {
hourStr = "" + i;
}
String minuteStr;
if (i1 < 10) {
minuteStr = "0" + i1;
} else {
minuteStr = "" + i1;
}
time = hourStr + ":" + minuteStr;
btnTime.setText(time);
}
},
current.get(Calendar.HOUR_OF_DAY),
current.get(Calendar.MINUTE),
true
).show();
}
});
btnSave.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 1. 입력한 제목과 내용을 가져온다.
String title = editTitle.getText().toString().trim();
String content = editContent.getText().toString().trim();
if(date == null || time == null){
Toast.makeText(MemoAddActivity.this, "날짜와 시간을 선택해주세요.", Toast.LENGTH_SHORT).show();
return;
}
datetime = date + " " + time;
Log.i("TOTAL_DATE",datetime);
// 2. 제목과 내용이 비어있는지 체크한다.
if (title.length() == 0 || content.length() == 0) {
Toast.makeText(MemoAddActivity.this, "제목과 내용을 입력해주세요.", Toast.LENGTH_SHORT).show();
return;
}
// 네트워크 호출하는 코드
// 로딩 다이얼로그를 보여준다.
showProgress("메모를 저장하고 있습니다.");
Retrofit retrofit = NetworkClient.getRetrofitClient(MemoAddActivity.this);
MemoApi api = retrofit.create(MemoApi.class);
Memo memo = new Memo( title, datetime, content);
// 토큰을 가져온다.
SharedPreferences sp = getSharedPreferences(Config.PREFERENCE_NAME, MODE_PRIVATE);
String accessToken = sp.getString(Config.ACCESS_TOKEN, "");
Call<Res> call = api.createMemo( memo , "Bearer " + accessToken); // <Res>로 리턴하라
call.enqueue(new Callback<Res>() {
@Override
public void onResponse(Call<Res> call, Response<Res> response) {
// 3-3. 로딩 다이얼로그를 사라지게 한다.
dismissProgress();
if (response.isSuccessful()) { // 응답코드가 200~300 사이인 경우
// 3-4. 메모 목록 화면으로 이동한다.
// 실무에서는 네트워크 절약을위해 back버튼을 누르면 result코드에따라 런처를 이용해서 메인화면으로 이동
finish();
} else {
Toast.makeText(MemoAddActivity.this, "서버와 통신 중 오류가 발생했습니다.", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<Res> call, Throwable t) {
Toast.makeText(MemoAddActivity.this, "서버와 통신 중 오류가 발생했습니다.", Toast.LENGTH_SHORT).show();
dismissProgress();
}
});
}
});
}
void showProgress(String message){
dialog = new ProgressDialog(this);
dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
dialog.setMessage(message);
dialog.show();
}
// 로직처리가 끝나면 화면에서 사라지는 함수
void dismissProgress(){
dialog.dismiss();
}
}
'Android' 카테고리의 다른 글
Android [포스팅앱 1.0] Glide 리사이클뷰 좋아요 mySQL, mySQL S3 포스팅 insert, 카메라 앨범 권한, 로그인 회원가입 자동로그인, ProgressDialog, Retrofit2 restful API (0) | 2023.02.15 |
---|---|
Android [파파고번역앱] 라디오 버튼, Volley (0) | 2023.02.13 |
Android [메모앱] Retrofit2 기본설정, 회원가입, 로그인 (0) | 2023.02.09 |
Android [유튜브API동영상리스트불러오는앱] 페이징처리, url파싱, 카드뷰 선택시 웹브라우저 실행 (0) | 2023.02.08 |
Android 유튜브 API 썸네일 이미지를 안드로이드에서 열어보기 (0) | 2023.02.07 |