일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 스택 큐 차이
- 안드로이드 라이선스 종류
- 서비스 쓰레드 차이
- jvm이란
- ar vr 차이
- 안드로이드 os 구조
- 안드로이드 라이선스
- 서비스 vs 쓰레드
- 2022 플러터 안드로이드 스튜디오
- rxjava hot observable
- 안드로이드 레트로핏 crud
- 안드로이드 레트로핏 사용법
- ANR이란
- 객체
- Rxjava Observable
- android ar 개발
- 스택 자바 코드
- 2022 플러터 설치
- 플러터 설치 2022
- jvm 작동 원리
- 안드로이드 유닛테스트란
- 자바 다형성
- 안드로이드 유닛 테스트
- rxjava disposable
- rxjava cold observable
- 멤버변수
- 큐 자바 코드
- 클래스
- android retrofit login
- 안드로이드 유닛 테스트 예시
- Today
- Total
나만을 위한 블로그
[Android] 레트로핏 예제 - 레트로핏으로 앱에서 CRUD하는 방법 < 2 > 본문
1. 레트로핏이란?
2. 레트로핏 예제 - 서버에서 값 가져와 앱에서 보여주기
4. 레트로핏으로 앱에서 CRUD하는 방법 < 2 >
아래에서 설명하는 내용은 모두 개인의 주관이며, 코드 작성법 또한 정석이 아니다. 이런 방식으로도 쓴다는 것을 보여주고 나 혼자 공부하기 위해 기록하는 글이다. 무조건 이 글이 정답은 아닌 것에 주의하자.
이번 포스팅은 레트로핏을 사용한 안드로이드에서 CRUD하는 마지막 포스팅이다.
지난 포스팅에서 INSERT, SELECT 쿼리를 사용했으니 이번 포스팅에선 UPDATE, DELETE 쿼리를 사용해 수정하고 삭제하는 예제를 포스팅하려고 한다.
PHP 파일 코딩은 지난 포스팅에서 모두 끝냈으니 여기선 앱 코딩만 다룬다.
먼저 MainActivity에 메뉴를 만들고 다음 화면 버튼을 누르면 OtherActivity로 이동하도록 한다.
이 때 인텐트에 클릭된 아이템의 id, name, hobby 값들을 담아서 이동시킨다.
public class MainActivity extends AppCompatActivity
{
public static final String TAG = "MainActivity";
EditText edit_name, edit_hobby;
Button add_btn;
String name, hobby;
RecyclerView recyclerView;
PersonAdapter adapter;
PersonAdapter.ItemClickListener itemClickListener;
List<Person> list = new ArrayList<>();
Menu main_menu;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.person_recyclerview);
edit_name = (EditText) findViewById(R.id.edit_name);
edit_hobby = (EditText) findViewById(R.id.edit_hobby);
add_btn = (Button) findViewById(R.id.add_btn);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.addItemDecoration(new DividerItemDecoration(getApplicationContext(), DividerItemDecoration.VERTICAL));
selectPerson();
itemClickListener = new PersonAdapter.ItemClickListener()
{
@Override
public void onItemClick(View view, int position)
{
int id = list.get(position).getId();
String name = list.get(position).getName();
String hobby = list.get(position).getHobby();
Log.e(TAG, "id : " + id + ", name : " + name + ", hobby : " + hobby);
Intent intent = new Intent(MainActivity.this, OtherActivity.class);
intent.putExtra("id", id);
intent.putExtra("name", name);
intent.putExtra("hobby", hobby);
startActivity(intent);
}
};
add_btn.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View view)
{
name = edit_name.getText().toString();
hobby = edit_hobby.getText().toString();
insertPerson(name, hobby);
}
});
}
private void selectPerson()
{
ApiInterface apiInterface = ApiClient.getApiClient().create(ApiInterface.class);
Call<List<Person>> call = apiInterface.getNameHobby();
call.enqueue(new Callback<List<Person>>()
{
@Override
public void onResponse(@NonNull Call<List<Person>> call, @NonNull Response<List<Person>> response)
{
if (response.isSuccessful() && response.body() != null)
{
onGetResult(response.body());
}
}
@Override
public void onFailure(@NonNull Call<List<Person>> call, @NonNull Throwable t)
{
Log.e("selectPerson()", "에러 : " + t.getMessage());
}
});
}
private void onGetResult(List<Person> lists)
{
adapter = new PersonAdapter(this, lists, itemClickListener);
adapter.notifyDataSetChanged();
recyclerView.setAdapter(adapter);
list = lists;
}
private void insertPerson(String name, String hobby)
{
ApiInterface apiInterface = ApiClient.getApiClient().create(ApiInterface.class);
Call<Person> call = apiInterface.insertPerson(name, hobby);
call.enqueue(new Callback<Person>()
{
@Override
public void onResponse(@NonNull Call<Person> call, @NonNull Response<Person> response)
{
if (response.isSuccessful() && response.body() != null)
{
Boolean success = response.body().getSuccess();
if (success)
{
onSuccess(response.body().getMessage());
}
else
{
onError(response.body().getMessage());
}
}
}
@Override
public void onFailure(@NonNull Call<Person> call, @NonNull Throwable t)
{
Log.e("insertPerson()", "에러 : " + t.getMessage());
}
});
}
private void onError(String message)
{
Log.e("insertPerson()", "onResponse() 에러 : " + message);
}
private void onSuccess(String message)
{
Log.e("insertPerson()", "onResponse() 성공 : " + message);
setResult(RESULT_OK);
finish();
}
}
이제 OtherActivity의 XML 코딩부터 시작하자.
MainActivity에서 아이템 클릭 시, 아이템에 들어있는 id와 name, hobby 값들을 인텐트에 담아서 OtherActivity로 옮긴다.
OtherActivity에선 MainActivity에서 넘어온 값들을 각각 알맞은 변수에 담고 TextView에 출력한다. 그리고 수정과 삭제 버튼을 만들어서 수정을 누르면 다른 액티비티로 이동해 내용을 수정하고 MainActivity로 이동하게 한다.
삭제를 누를 경우 DELETE 쿼리를 사용하는 메서드를 통해 DB에서 데이터를 삭제한다.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".OtherActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="100dp"
android:layout_marginStart="30dp"
android:layout_marginEnd="30dp"
android:weightSum="1">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".3"
android:text="이름 : "
android:textSize="20sp"
android:gravity="end"/>
<TextView
android:id="@+id/other_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".7"
android:text="이름"
android:textSize="20sp"
android:gravity="center"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="20dp"
android:layout_marginStart="30dp"
android:layout_marginEnd="30dp"
android:weightSum="1">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".3"
android:text="취미 : "
android:textSize="20sp"
android:gravity="end"/>
<TextView
android:id="@+id/other_hobby"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".7"
android:text="취미"
android:textSize="20sp"
android:gravity="center"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="30dp"
android:gravity="center">
<Button
android:id="@+id/update_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="수 정"
android:textSize="20sp" />
<Button
android:id="@+id/delete_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="50dp"
android:text="삭 제"
android:textSize="20sp" />
</LinearLayout>
</LinearLayout>
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class OtherActivity extends AppCompatActivity
{
public static final String TAG = "OtherActivity";
TextView other_name, other_hobby;
Button update_btn, delete_btn;
int id;
String name, hobby;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_other);
other_name = (TextView) findViewById(R.id.other_name);
other_hobby = (TextView) findViewById(R.id.other_hobby);
update_btn = (Button) findViewById(R.id.update_btn);
delete_btn = (Button) findViewById(R.id.delete_btn);
other_name.setText(name);
other_hobby.setText(hobby);
Intent intent = getIntent();
id = intent.getIntExtra("id", 0);
name = intent.getStringExtra("name");
hobby = intent.getStringExtra("hobby");
Log.e(TAG, "인텐트 id : " + id + ", 인텐트 이름 : " + name + ", 인텐트 취미 : " + hobby);
update_btn.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View view)
{
// 수정 메서드
}
});
delete_btn.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View view)
{
// 삭제 메서드
}
});
}
}
밑준비는 끝났다. 인텐트에서 받아온 값들 중 name, hobby는 각각 텍스트뷰에 set해서 제대로 가져오는지 확인한다.
이제 ApiInterface.java에 수정과 삭제하는 메서드들을 추가해야 한다.
import java.util.List;
import retrofit2.Call;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.POST;
public interface ApiInterface
{
@GET("example_select.php")
Call<List<Person>> getNameHobby();
@FormUrlEncoded
@POST("example_insert.php")
Call<Person> insertPerson(
@Field("name") String name,
@Field("hobby") String hobby
);
@FormUrlEncoded
@POST("example_update.php")
Call<Person> updatePerson(
@Field("id") int id,
@Field("name") String name,
@Field("hobby") String hobby
);
@FormUrlEncoded
@POST("example_delete.php")
Call<Person> deletePerson(
@Field("id") int id
);
}
여기까지 하고 앱이 제대로 작동하는지 확인해보자.
DB에서 값 가져오고 아이템 클릭 시 OtherActivity로 값을 가지고 이동하는 걸 볼 수 있다.
이제 수정하는 메서드부터 만들어보자. 먼저 OtherActivity로 값을 가져오기만 했으니 수정 버튼을 누르면 이 값들을 갖고 UpdateActivity로 이동해서 수정할 수 있게 해야 한다.
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
public class OtherActivity extends AppCompatActivity
{
public static final String TAG = "OtherActivity";
TextView other_name, other_hobby;
Button update_btn, delete_btn;
int id;
String name, hobby;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_other);
other_name = (TextView) findViewById(R.id.other_name);
other_hobby = (TextView) findViewById(R.id.other_hobby);
update_btn = (Button) findViewById(R.id.update_btn);
delete_btn = (Button) findViewById(R.id.delete_btn);
Intent intent = getIntent();
id = intent.getIntExtra("id", 0);
name = intent.getStringExtra("name");
hobby = intent.getStringExtra("hobby");
Log.e(TAG, "인텐트 id : " + id + ", 인텐트 이름 : " + name + ", 인텐트 취미 : " + hobby);
other_name.setText(name);
other_hobby.setText(hobby);
update_btn.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View view)
{
Intent update_intent = new Intent(OtherActivity.this, UpdateActivity.class);
update_intent.putExtra("id", id);
update_intent.putExtra("name", name);
update_intent.putExtra("hobby", hobby);
startActivity(update_intent);
}
});
delete_btn.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View view)
{
// 삭제 메서드
}
});
}
}
UpdateActivity의 XML부터 코딩해보자. 수정해야 하니까 editText가 2개는 있어야 하고, 수정 완료 버튼도 있어서 MainActivity로 돌아갈 수 있어야 한다. 플래그는 설정하지 않는다.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".UpdateActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="100dp"
android:layout_marginStart="30dp"
android:layout_marginEnd="30dp"
android:weightSum="1">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".3"
android:text="이름 : "
android:textSize="20sp"
android:gravity="end"/>
<EditText
android:id="@+id/name_edittext"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".7"
android:hint="수정할 이름 입력"
android:textSize="20sp"
android:gravity="center"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="20dp"
android:layout_marginStart="30dp"
android:layout_marginEnd="30dp"
android:weightSum="1">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".3"
android:text="취미 : "
android:textSize="20sp"
android:gravity="end"/>
<EditText
android:id="@+id/hobby_edittext"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".7"
android:hint="수정할 이름 입력"
android:textSize="20sp"
android:gravity="center"/>
</LinearLayout>
<Button
android:id="@+id/update_done"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="50dp"
android:text="수정 완료"
android:textSize="20sp"/>
</LinearLayout>
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class UpdateActivity extends AppCompatActivity
{
public static final String TAG = "UpdateActivity";
EditText name_edittext, hobby_edittext;
Button update_done;
int id;
String name, hobby;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_update);
name_edittext = (EditText) findViewById(R.id.name_edittext);
hobby_edittext = (EditText) findViewById(R.id.hobby_edittext);
update_done = (Button) findViewById(R.id.update_done);
Intent intent = getIntent();
id = intent.getIntExtra("id", 0);
name = intent.getStringExtra("name");
hobby = intent.getStringExtra("hobby");
Log.e(TAG, "수정 id : " + id + ", 수정 이름 : " + name + ", 수정 취미 : " + hobby);
name_edittext.setText(name);
hobby_edittext.setText(hobby);
update_done.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View view)
{
updatePerson(id, name, hobby);
Toast.makeText(UpdateActivity.this, "수정 성공", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(UpdateActivity.this, MainActivity.class);
startActivity(intent);
}
});
}
private void updatePerson(int id, String name, String hobby)
{
ApiInterface apiInterface = ApiClient.getApiClient().create(ApiInterface.class);
name = name_edittext.getText().toString();
hobby = hobby_edittext.getText().toString();
Call<Person> call = apiInterface.updatePerson(id, name, hobby);
call.enqueue(new Callback<Person>()
{
@Override
public void onResponse(@NonNull Call<Person> call, @NonNull Response<Person> response)
{
//
}
@Override
public void onFailure(@NonNull Call<Person> call, @NonNull Throwable t)
{
Log.e("updatePerson()", "에러 : " + t.getMessage());
}
});
}
}
PHP 파일에서 마지막에 echo로 어떤 메시지도 출력하지 않기 때문에 onResponse()에서도 별다른 처리는 하지 않았다.그런데 여기까지 하고 앱을 빌드하면 "End of input at line 1 column 1 path $"라는 에러가 로그캣에 나온다.
그렇다면 아래의 자바 파일을 하나 만들어준다. New > Java Class를 만든 다음 NullOnEmptyConverterFactory 라는 이름으로 만든다.
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import okhttp3.ResponseBody;
import retrofit2.Converter;
import retrofit2.Retrofit;
public class NullOnEmptyConverterFactory extends Converter.Factory
{
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit)
{
final Converter<ResponseBody, ?> delegate = retrofit.nextResponseBodyConverter(this, type, annotations);
return new Converter<ResponseBody, Object>() {
@Override
public Object convert(ResponseBody body) throws IOException
{
if (body.contentLength() == 0) {
return null;
}
return delegate.convert(body);
}
};
}
}
이렇게 생성했다면 ApiClient.java로 이동해서 한 줄 추가해줘야 한다.
public class ApiClient
{
private static final String BASE_URL = "http://xx.xxx.xxx.xx/";
private static Retrofit retrofit;
public static Retrofit getApiClient()
{
Gson gson = new GsonBuilder()
.setLenient()
.create();
if (retrofit == null)
{
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(new NullOnEmptyConverterFactory()) // <- 이 문장을 추가한다
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
return retrofit;
}
}
이제 앱을 빌드해보자.
read a book이었던 문자열을 'read a'로 변경하자 수정 성공 토스트가 뜨며 MainActivity로 이동되는 걸 볼 수 있다.
앱을 완전히 껐다가 다시 켜도 SELECT 쿼리 결과가 수정 후의 데이터를 가져오는 것도 확인할 수 있다.
이제 마지막으로 DELETE 쿼리를 써서 데이터를 없애보자. 맨 마지막의 이름이 Min인 row를 없앨 것이다.
DELETE 쿼리는 OtherActivity에서 사용되니 이곳으로 이동해서 계속 코딩한다.
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class OtherActivity extends AppCompatActivity
{
public static final String TAG = "OtherActivity";
TextView other_name, other_hobby;
Button update_btn, delete_btn;
int id;
String name, hobby;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_other);
other_name = (TextView) findViewById(R.id.other_name);
other_hobby = (TextView) findViewById(R.id.other_hobby);
update_btn = (Button) findViewById(R.id.update_btn);
delete_btn = (Button) findViewById(R.id.delete_btn);
Intent intent = getIntent();
id = intent.getIntExtra("id", 0);
name = intent.getStringExtra("name");
hobby = intent.getStringExtra("hobby");
Log.e(TAG, "인텐트 id : " + id + ", 인텐트 이름 : " + name + ", 인텐트 취미 : " + hobby);
other_name.setText(name);
other_hobby.setText(hobby);
update_btn.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View view)
{
Intent update_intent = new Intent(OtherActivity.this, UpdateActivity.class);
update_intent.putExtra("id", id);
update_intent.putExtra("name", name);
update_intent.putExtra("hobby", hobby);
startActivity(update_intent);
}
});
delete_btn.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View view)
{
// 삭제 메서드
deletePerson(id);
Intent delete_intent = new Intent(OtherActivity.this, MainActivity.class);
startActivity(delete_intent);
}
});
}
private void deletePerson(int id)
{
ApiInterface apiInterface = ApiClient.getApiClient().create(ApiInterface.class);
Call<Person> call = apiInterface.deletePerson(id);
call.enqueue(new Callback<Person>()
{
@Override
public void onResponse(@NonNull Call<Person> call, @NonNull Response<Person> response)
{
//
}
@Override
public void onFailure(@NonNull Call<Person> call, @NonNull Throwable t)
{
Log.e("deletePerson()", t.getMessage());
}
});
}
private void onError(String message)
{
Log.e("insertPerson()", "onResponse() 에러 : " + message);
}
private void onSuccess(String message)
{
Log.e("insertPerson()", "onResponse() 성공 : " + message);
setResult(RESULT_OK);
finish();
}
}
이제 다시 앱을 빌드해보자.
Min을 삭제하면 MainActivity로 돌아와서 삭제됐는지 아닌지를 확인할 수 있다. 위 움짤을 보다시피 정상적으로 삭제된 걸 확인할 수 있다.
앱을 완전히 끄고 다시 켜도 Min은 삭제된 그대로인 걸 볼 수 있다.
이것으로 안드로이드에서 레트로핏을 사용한 CRUD 포스팅을 끝낸다.
'Android' 카테고리의 다른 글
[Android] AR core 공식 홈페이지 예제 빌드하는 법 (0) | 2020.11.15 |
---|---|
[Android] 카카오 로그인 API 사용 시 AUTHORIZATION FAILED invalid android_key_hash or ios_bundle_id or web_site_url 에러 해결 (0) | 2020.10.31 |
[Android] 레트로핏 예제 - 레트로핏으로 앱에서 CRUD하는 방법 < 1 > (0) | 2020.10.06 |
[Android] 레트로핏 예제 - 서버에서 값 가져와 앱에서 보여주기 (0) | 2020.10.05 |
[Android, PHP, MySQL] Volley로 MySQL에서 COUNT()한 결과를 가져와 텍스트뷰에 set하는 방법 (0) | 2020.10.04 |