위의 예제에서 작성된 django 서버와 연동하는 예제이다.
Server 쪽의 예제가 필요하면 위의 링크를 참고 하시길.
Retrofit ?
- 서버에 Restful API 에 맞는 요청을 보내기 위해 사용하는 위한 통신 인터페이스이다. AsyncTask 와 HttpUrlConnection 을 사용하여 구현 할 수는 있지만 기본적으로 필요한 요구사항들을 쉽게 처리할 수 있게하는 도구이다.
Retrofit의 github 이다 예제도 잘 나와 있다.
http://devflow.github.io/retrofit-kr/
1. build.gradle 추가하기
현재 2.6.1 이 최신 버전이라 최신버전을 추가 했다.
Module: app
dependencies {
....
implementation 'com.squareup.retrofit2:retrofit:2.6.1'
implementation 'com.squareup.retrofit2:converter-gson:2.6.1'
....
}
2. Manifest Permission 등록
internet을 사용하므로 internet permission 을 추가해준다.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.retrofitexample">
<uses-permission android:name="android.permission.INTERNET"/>
...
</manifest>
3. Data 객체 정의
우리가 server의 model에서 구성했던것과 동일하게 구성해준다.
PostItem.java
package com.example.retrofitexample;
public class PostItem {
private String title;
private String text;
public String getText() {
return text;
}
public String getTitle(){
return title;
}
public void setTitle(String s){
title = s;
}
public void setText(String s){
text = s;
}
}
4. Retrofit Interface 구성
Call 을 통해서 웹서버에 요청을 보낼 수 있다.
1. Http요청을 어노테이션으로 명시
2. URL Parameter와 Query Parameter 사용이 가능하다.
ex) @GET("/group/{id}/users") Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort)
3. 객체는 Body 로 json형태로 전달한다.
url 끝에 / 를 빼먹으면 error 가 발생할 수 있으니 유의바란다.
MyAPI.java
package com.example.retrofitexample;
import java.util.List;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.DELETE;
import retrofit2.http.GET;
import retrofit2.http.PATCH;
import retrofit2.http.POST;
import retrofit2.http.Path;
public interface MyAPI{
@POST("/posts/")
Call<PostItem> post_posts(@Body PostItem post);
@PATCH("/posts/{pk}/")
Call<PostItem> patch_posts(@Path("pk") int pk, @Body PostItem post);
@DELETE("/posts/{pk}/")
Call<PostItem> delete_posts(@Path("pk") int pk);
@GET("/posts/")
Call<List<PostItem>> get_posts();
@GET("/posts/{pk}/")
Call<PostItem> get_post_pk(@Path("pk") int pk);
}
5. 동작 확인을 위한 초기화 및 간단한 동작 구현
단순 동작 확인 을 위하여 MainActivity 에서 모두 구현하였다.
부분 부분 설명 후 전체 코드는 밑에 있다. 하나씩 따라해 보자.
Retrofit 객체를 생성하고 이 객체를 이용해서, API service 를 create 해준다.
private void initMyAPI(String baseUrl){
Log.d(TAG,"initMyAPI : " + baseUrl);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
mMyAPI = retrofit.create(MyAPI.class);
}
내가 정의한 api 중에서 get 동작을 살펴보자.
mMyAPI.get_posts(); 함수를 이용해서 Call 객체를 불러온다.
Call 객체에 Callback을 넣어준다. 응답이 왔을 때에는 onResponse 함수로 가게 되고 응답이 안왔으면 Throwable 객체에 메시지를 담아서 onFailure 가 호출된다.
성공적인 response 가 도착 했다면 response.body() 에 우리가 서버로부터 받아온 데이터가 들어있다.
Call<List<PostItem>> getCall = mMyAPI.get_posts();
getCall.enqueue(new Callback<List<PostItem>>() {
@Override
public void onResponse(Call<List<PostItem>> call, Response<List<PostItem>> response) {
if( response.isSuccessful()){
List<PostItem> mList = response.body();
String result ="";
for( PostItem item : mList){
result += "title : " + item.getTitle() + " text: " + item.getText()+ "\n";
}
mListTv.setText(result);
}else {
Log.d(TAG,"Status Code : " + response.code());
}
}
@Override
public void onFailure(Call<List<PostItem>> call, Throwable t) {
Log.d(TAG,"Fail msg : " + t.getMessage());
}
}
GET Button Listener 를 달아 위의 event를 등록을 하고 GET Button을 누르면 아래와 같은 결과를 볼 수 있다.
나머지 동작은 아래 Code로 첨부하니 동작 확인 해보시길..
모든 동작을 확인 한 후 서버의 상태이다.
MainActivity.java
package com.example.retrofitexample;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private final String TAG = getClass().getSimpleName();
// server의 url을 적어준다
private final String BASE_URL = "http://27ad1bf3.ngrok.io";
private MyAPI mMyAPI;
private TextView mListTv;
private Button mGetButton;
private Button mPostButton;
private Button mPatchButton;
private Button mDeleteButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListTv = findViewById(R.id.result1);
mGetButton = findViewById(R.id.button1);
mGetButton.setOnClickListener(this);
mPostButton = findViewById(R.id.button2);
mPostButton.setOnClickListener(this);
mPatchButton = findViewById(R.id.button3);
mPatchButton.setOnClickListener(this);
mDeleteButton = findViewById(R.id.button4);
mDeleteButton.setOnClickListener(this);
initMyAPI(BASE_URL);
}
private void initMyAPI(String baseUrl){
Log.d(TAG,"initMyAPI : " + baseUrl);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
mMyAPI = retrofit.create(MyAPI.class);
}
@Override
public void onClick(View v) {
if( v == mGetButton){
Log.d(TAG,"GET");
Call<List<PostItem>> getCall = mMyAPI.get_posts();
getCall.enqueue(new Callback<List<PostItem>>() {
@Override
public void onResponse(Call<List<PostItem>> call, Response<List<PostItem>> response) {
if( response.isSuccessful()){
List<PostItem> mList = response.body();
String result ="";
for( PostItem item : mList){
result += "title : " + item.getTitle() + " text: " + item.getText() + "\n";
}
mListTv.setText(result);
}else {
Log.d(TAG,"Status Code : " + response.code());
}
}
@Override
public void onFailure(Call<List<PostItem>> call, Throwable t) {
Log.d(TAG,"Fail msg : " + t.getMessage());
}
});
}else if(v == mPostButton){
Log.d(TAG,"POST");
PostItem item = new PostItem();
item.setTitle("Android title");
item.setText("Android text");
Call<PostItem> postCall = mMyAPI.post_posts(item);
postCall.enqueue(new Callback<PostItem>() {
@Override
public void onResponse(Call<PostItem> call, Response<PostItem> response) {
if(response.isSuccessful()){
Log.d(TAG,"등록 완료");
}else {
Log.d(TAG,"Status Code : " + response.code());
Log.d(TAG,response.errorBody().toString());
Log.d(TAG,call.request().body().toString());
}
}
@Override
public void onFailure(Call<PostItem> call, Throwable t) {
Log.d(TAG,"Fail msg : " + t.getMessage());
}
});
}else if( v == mPatchButton){
Log.d(TAG,"PATCH");
PostItem item = new PostItem();
item.setTitle("android patch title");
item.setText("android patch text");
//pk 값은 임의로 하드코딩하였지만 동적으로 setting 해서 사용가능
Call<PostItem> patchCall = mMyAPI.patch_posts(1,item);
patchCall.enqueue(new Callback<PostItem>() {
@Override
public void onResponse(Call<PostItem> call, Response<PostItem> response) {
if(response.isSuccessful()){
Log.d(TAG,"patch 성공");
}else{
Log.d(TAG,"Status Code : " + response.code());
}
}
@Override
public void onFailure(Call<PostItem> call, Throwable t) {
Log.d(TAG,"Fail msg : " + t.getMessage());
}
});
}else if( v == mDeleteButton){
Log.d(TAG,"DELETE");
// pk 값은 임의로 변경가능
Call<PostItem> deleteCall = mMyAPI.delete_posts(2);
deleteCall.enqueue(new Callback<PostItem>() {
@Override
public void onResponse(Call<PostItem> call, Response<PostItem> response) {
if(response.isSuccessful()){
Log.d(TAG,"삭제 완료");
}else {
Log.d(TAG,"Status Code : " + response.code());
}
}
@Override
public void onFailure(Call<PostItem> call, Throwable t) {
Log.d(TAG,"Fail msg : " + t.getMessage());
}
});
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/result1"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="get"/>
<Button
android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="post"/>
<Button
android:id="@+id/button3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="patch"/>
<Button
android:id="@+id/button4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="delete"/>
</LinearLayout>
'Android' 카테고리의 다른 글
[Android] Retrofit http 400 Error 확인 방법 (0) | 2019.09.25 |
---|