티스토리 뷰

안드로이드

Retrofit(레트로핏)을 사용해보자 v2.0.2

새로운 도전을 즐기는 모기같은 개발자. 하늘을난모기 2016.08.25 23:03

안드로이드를 조금 하다보면 서버와 통신을 해야하는 일이 필연적으로 생기게 된다.

서버에 요청을 보내고 json 혹은 xml 방식으로 파싱을 하게되는 경우가 많다.

처음에는 AsyncTask 를 사용하여 서버와의 통신을 했다.

하지만 쓰다보니 너무 복잡한 소스와 느린 속도로 인해 다른 방법을 찾아보게 되었다.

그 해결책이 바로 'Retrofit' 이다.


Retrofit에 대한 자세한 설명은 공식 홈페이지를 통해 알아보도록 하자.

http://square.github.io/retrofit/


포스팅 하고자 하는 글은 이 Retrofit을 사용하는 방법이다.

부족한 실력으로 인해 모든것을 다 적을 순 없지만, 직접 프로젝트를 하면서 사용한만큼만 적어보려고 한다.

영어와 프로그래밍 실력이 높은분들은 공식 홈페이지를 참고하는걸 추천한다.


이제부터 Retrofit을 어떻게 사용했는지 포스팅을 시작하겠다.

기본적으로 안드로이드 프로젝트 생성은 알것이라고 생각한다.


우선 app.gradle로 들어간다. 라이브러리 세팅을 위함이다.

dependencies에 다음과 같이 2줄을 추가한다.


dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'

// retrofit
compile 'com.squareup.retrofit2:retrofit:2.0.2'
compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'
}


이 두 줄을 추가하고 sync를 해준다.

다음으로 AndroidManifest에 퍼미션 인터넷을 추가해준다.

<uses-permission android:name="android.permission.INTERNET" />


이제부터 Retrofit을 사용하기 위한 준비가 끝났다.

이게 다야? 라고 할 정도로 라이브러리 추가가 간단하다...


다음은 json 파싱으로 가져올 Repo를 만들어야 한다.

json으로 가져올 형태는 다음과 같다.


주소 : www.dxmnd.com/blog/?name=abcd


{

  • name"abcd",
  • output"abcd님 안녕하세요.",
  • info
    [
    • {
      • name"abcd",
      • output"abcd님 안녕하세요."
      },
    • {
      • name"abcd2",
      • output"abcd님 안녕하세요.2"
      }
    ]

}


단순하게 name을 받으면 위와 같이 json 형식으로 반환해준다.


public class RetrofitRepo {
String name;
String output;
List<Item> info;

public String getName() {
return name;
}

public String getOutput() {
return output;
}

public List<Item> getInfo() {
return info;
}
}

retrofit에서 주의할 점이 이 repo를 설계할 때 가져올 json 형식과 맞춰줘야 한다는 것이다.

즉 변수(이름)을 맞춰줘야 한다.

json으로 가져올 값들을 보면 name, output, info가 있다.

이 때 info는 배열 형식으로 여러 값을 저장할 수 있기에 리스트로 선언하여 준다.


이 때 리스트의 제네릭타입 Item 역시 이름을 맞춰줘야 한다.


public class Item {
String name;
String output;

public String getName() {
return name;
}

public String getOutput() {
return output;
}
}

이렇게 원하는 json형식대로 작업을 마치고 나면 다음으로 할 일은 공식홈페이지에서도 명시되어있는 GitHubService 라는 인터페이스를 만들 것이다.

굳이 인터페이스명을 GitHubService 로 하지 않아도 된다.


그래서 RetrofitService로 명명했다.

(예를 들기 위해 이름을 바꿨을 뿐이지 알기 쉬운 명명 규칙을 사용하길 바란다...)

public interface RetrofitService {
@GET("index.php")
Call<RetrofitRepo> getIndex(
@Query("name") String name
);

@GET("test.php")
Call<RetrofitRepo> getItem(
@QueryMap Map<String, String> option
);

@FormUrlEncoded
@POST("post.php")
Call<RetrofitRepo> getPost(
@Field("name") String name
); }

이 인터페이스에서 이제 어떤식으로 파라미터를 넘겨줄지를 결정하게 된다.

단일 쿼리의 GET 방식과 다수 쿼리의 GET 방식, 그리고 포스트 방식을 설명하겠다.

GET 방식과 POST 방식에 대해 간단하게 설명하자면

GET 방식은 url에 보이는 방식이고, POST는 안보이는 방식이다 라고 생각하면 된다.


GET이든 POST는 사용하기 위해서는 일단 선언을 하고 바뀔 부분의 주소를 입력하자.

쉽게 말하자면

www.dxmnd.com/blog/index.php

www.dxmnd.com/blog/test.php

www.dxmnd.com/blog/post.php

이 세 링크를 보면 www.dxmnd.com/blog/ 까지는 동일하다.

이 고정된 주소는 나중에 따로 명시하게 되니 바뀌는 부분만 입력하자.


GET방식을 사용하면 @Query와 @QueryMap을 사용할 수 있다.

@Query는 단일 파라미터일 경우 사용한다.

위의 링크는 단지 name 값만 보내주면 되기 때문에 @Query("name") 으로 지정하면 된다.

이때 Query 안의 name은 보낼 파라미터 값을 의미한다.

이 주소로 생기는 결과는

www.dxmnd.com/blog/index.php?name=??? 가 된다.


만약 단일 쿼리가 아닌 여러개의 쿼리일 경우 QueryMap을 사용한다.

사용법은 실제 retrofit을 사용할 때 작성하도록 하겠다.


POST 방식을 사용하기 위해선 @FormUrlEncoded를 사용해야한다.

그리고 POST로 선언하고 마찬가지로 바뀔 부분의 주소를 입력한다.

POST는 Field를 사용하며 GET 방식과 마찬가지로 파라미터의 변수를 입력해둔다.


다수 쿼리 POST 방식을 사용하는 방식은 get방식과 마찬가지로 사용하되

@FieldMap 으로 하면 된다.


이제 http 요청을 보내고 json 파싱을 하는 방법을 작성하겠다.


URL을 적을 때 유의점은 뒤에 / 를 잊지 말아야 한다.

static final String URL = "http://www.dxmnd.com/blog/";


1. 단일 쿼리 GET 방식

public void index() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(URL)
.addConverterFactory(GsonConverterFactory.create())
.build();

RetrofitService retrofitService = retrofit.create(RetrofitService.class);
Call<RetrofitRepo> call = retrofitService.getIndex("mos");
call.enqueue(new Callback<RetrofitRepo>() {
@Override
public void onResponse(Call<RetrofitRepo> call, Response<RetrofitRepo> response) {
RetrofitRepo repo = response.body();
textViewIndex.setText(repo.getName());
}

@Override
public void onFailure(Call<RetrofitRepo> call, Throwable t) {

}
});
}

이 소스는 단일 쿼리일 경우 사용방법이다.


AsyncTask에 비하면 굉장히 단순한 소스이다.

단일 쿼리일 경우 RetrofitService 에서 name 파라미터로 지정을 해주었기 때문에 바로 보낼 값을 입력하면 된다.

name에 들어갈 값으로 mos라고 지정했다.

Call을 생성할 때는 가져올 json 값의 형식인 Repo를 타입으로 하여 가져온다.

call.enque를 하고 자동완성을 하게 되면 onResponse와 onFailure가 생성되고

onResponse에는 성공했을 때에 대한 실행 명령을 작성하면 된다.

response.body() 메서드를 통해 결과 값을 가져올 수 있다.



2. 다중 쿼리 GET 방식

public void map() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(URL)
.addConverterFactory(GsonConverterFactory.create())
.build();

Map map = new HashMap();
map.put("name","map");

RetrofitService retrofitService = retrofit.create(RetrofitService.class);
Call<RetrofitRepo> call = retrofitService.getItem(map);
call.enqueue(new Callback<RetrofitRepo>() {
@Override
public void onResponse(Call<RetrofitRepo> call, Response<RetrofitRepo> response) {
RetrofitRepo repo = response.body();
String a = "";
for(int i=0;i<repo.getInfo().size();i++) {
a += repo.getInfo().get(i).getName() + "\n";
a += repo.getInfo().get(i).getOutput();
}
textViewMap.setText(a);
}

@Override
public void onFailure(Call<RetrofitRepo> call, Throwable t) {

}
});
}

다중 쿼리 GET 방식의 경우 단일 쿼리와 크게 달라지는 점은 Map으로 선언하여 값을 지정하는것 뿐이다.

Map map = new HashMap();

map.put("key","value");


이 두줄이 핵심이라고 볼 수 있다.

이렇게 여러 쿼리를 map에 담아 getItem의 map으로 보낸다.


3. POST 방식

public void post() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(URL)
.addConverterFactory(GsonConverterFactory.create())
.build();

RetrofitService retrofitService = retrofit.create(RetrofitService.class);
Call<RetrofitRepo> call = retrofitService.getPost("post");
call.enqueue(new Callback<RetrofitRepo>() {
@Override
public void onResponse(Call<RetrofitRepo> call, Response<RetrofitRepo> response) {
RetrofitRepo repo = response.body();
textViewPost.setText(repo.getOutput());
}

@Override
public void onFailure(Call<RetrofitRepo> call, Throwable t) {

}
});
}

포스트 방식은 RetrofitService에서의 구조만 다를뿐 get방식과 동일하다.


실행 화면


사진이 무지 크게 나와버리넹 ;ㅂ;


이렇게 하면 retrofit을 사용할 수 있다.

포스팅 끝!


전체 소스

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.HashMap;
import java.util.Map;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import sungkyul.ac.kr.customframework.R;
import sungkyul.ac.kr.customframework.retrofit.RetrofitRepo;
import sungkyul.ac.kr.customframework.retrofit.RetrofitService;

public class RetrofitFragment extends Fragment {
View mView;
TextView textViewIndex, textViewPost, textViewMap;
static final String URL = "http://www.dxmnd.com/blog/";

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mView = inflater.inflate(R.layout.fragment_retrofit, container, false);

textViewIndex = (TextView)mView.findViewById(R.id.txtRetrofitTest);
textViewPost = (TextView)mView.findViewById(R.id.txtRetrofitPost);
textViewMap = (TextView)mView.findViewById(R.id.txtRetrofitMap);

index();
post();
map();

return mView;
}


public void index() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(URL)
.addConverterFactory(GsonConverterFactory.create())
.build();

RetrofitService retrofitService = retrofit.create(RetrofitService.class);
Call<RetrofitRepo> call = retrofitService.getIndex("mos");
call.enqueue(new Callback<RetrofitRepo>() {
@Override
public void onResponse(Call<RetrofitRepo> call, Response<RetrofitRepo> response) {
RetrofitRepo repo = response.body();
textViewIndex.setText(repo.getName());
}

@Override
public void onFailure(Call<RetrofitRepo> call, Throwable t) {

}
});
}

public void post() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(URL)
.addConverterFactory(GsonConverterFactory.create())
.build();

RetrofitService retrofitService = retrofit.create(RetrofitService.class);
Call<RetrofitRepo> call = retrofitService.getPost("post");
call.enqueue(new Callback<RetrofitRepo>() {
@Override
public void onResponse(Call<RetrofitRepo> call, Response<RetrofitRepo> response) {
RetrofitRepo repo = response.body();
textViewPost.setText(repo.getOutput());
}

@Override
public void onFailure(Call<RetrofitRepo> call, Throwable t) {

}
});
}

public void map() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(URL)
.addConverterFactory(GsonConverterFactory.create())
.build();

Map map = new HashMap();
map.put("name","map");

RetrofitService retrofitService = retrofit.create(RetrofitService.class);
Call<RetrofitRepo> call = retrofitService.getItem(map);
call.enqueue(new Callback<RetrofitRepo>() {
@Override
public void onResponse(Call<RetrofitRepo> call, Response<RetrofitRepo> response) {
RetrofitRepo repo = response.body();
String a = "";
for(int i=0;i<repo.getInfo().size();i++) {
a += repo.getInfo().get(i).getName() + "\n";
a += repo.getInfo().get(i).getOutput();
}
textViewMap.setText(a);
}

@Override
public void onFailure(Call<RetrofitRepo> call, Throwable t) {

}
});
}
}


많은 사람들에게 도움이 되길 바라며 포스팅 정말 끝!!

(글 정말 못쓴다...ㅠ.ㅠ)


댓글
  • 프로필사진 지나가다 도움많이 되었습니다.
    문의드릴 사항이 있는데요.
    json data를 post 로 전달하는 부분에 대한 도움을 받고 싶은데요.

    예) http://abcde.net/2/3
    혹시
    http://abcde/aaaa/1
    json Body
    {
    aaa : "ok",
    bbb : 1123
    }

    로 전달하고 json 데이터를 받아오는 부분입니다.

    혹시 도움을 받을수 있을까요?
    2016.10.21 14:15 신고
  • 프로필사진 새로운 도전을 즐기는 모기같은 개발자. 하늘을난모기 어떤 부분에 문제가 있으신가요? 제가 아는 선에서는 도와드릴 수 있어요 2016.10.21 14:58 신고
  • 프로필사진 헤이메어 https://accounts.google.com/o/oauth2/v2/auth?
    scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.metadata.readonly&
    access_type=offline&
    include_granted_scopes=true&
    state=state_parameter_passthrough_value&
    redirect_uri=http%3A%2F%2Foauth2.example.com%2Fcallback&
    response_type=code&
    client_id=client_id

    이게 구글시트에 대한 권한 요청하는부분인데 이걸 레트로핏으로 만들려면 어떻게 해야할까요? 제가 이글을 봐도 잘 이해가 안돼요,, 초보라
    2017.11.16 19:33 신고
  • 프로필사진 코린이 글에서 정성이 느껴집니다 감사합니다. 2018.11.19 10:17 신고
댓글쓰기 폼