웹 서버에 요청하고 응답을 받을 때는 HttpURLConnection 객체를 사용할 수 있지만 요청과 응답에 필요한 코드의 양이 많다. 그리고 스레드를 사용하면서 넣어야 하는 코드의 양도 많다.
이런 문제를 해결하기 위한 라이브러리들이 있는데, 그 중 하나가 Volley다.
Volley 라이브러리는 웹 요청과 응답을 단순화하기 위해 만들어진 라이브러리다.
Volley를 사용하려면 먼저 요청(Request) 객체를 만들고 이 객체를 요청 큐(RequestQueue)라는 곳에 넣어주기만 하면 된다.
그러면 요청 큐가 알아서 웹 서버에 요청하고 응답까지 받아준다. 응답을 받을 수 있도록 지정된 메소드를 만들어두기만 하면 응답이 왔을 때 그 메소드가 자동으로 호출된다.
Volley 라이브러리이 가장 큰 장점은 스레드를 신경쓰지 않아도 된다는 점이다.
요청 큐가 내부에서 스레드를 만들어 웹 서버에 요청하고 응답하는 과정을 진행하는데, 응답을 처리할 수 있는 메소드를 호출할 때는 메인 스레드에서 처리할 수 있도록 만들기 때문이다.
따라서 스레드를 사용할 필요도 없고, 화면에 결과를 표시할 때 핸들러를 사용할 필요도 없다.
Volley는 외부 라이브러리이므로 build.gradle 파일에 라이브러리 정보를 추가한다
dependencies {
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.6.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation 'com.android.volley:volley:1.2.0'
}
AndroidManifest.xml 파일에 INTERNET 권한을 추가하고
application 태그에 usesCleartextTraffic 속성을 추가한다.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.techtown.request">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:usesCleartextTraffic="true"
activity_main.xml 레이아웃에 입력상자와 버튼, 스크롤뷰와 그 안에 텍스트뷰를 추가하였다.
MainActivity.java 파일에 코드를 작성하였다.
public class MainActivity extends AppCompatActivity {
EditText editText;
TextView textView;
static RequestQueue requestQueue;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText = findViewById(R.id.editText);
textView = findViewById(R.id.textView);
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
makeRequest();
}
});
if(requestQueue == null){
requestQueue = Volley.newRequestQueue(getApplicationContext());
}
}
public void makeRequest() {
String url = editText.getText().toString();
StringRequest request = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
@Override
public void onResponse(String response) {
println("응답 -> " + response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
println("에러 -> " + error.getMessage());
}
}) {
@Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
return params;
}
};
request.setShouldCache(false);
requestQueue.add(request);
println("요청 보냄");
}
public void println(String data) {
textView.append(data + "\n");
}
}
요청 큐를 선언하고 객체를 생성하였다.
public class MainActivity extends AppCompatActivity {
...
static RequestQueue requestQueue;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
if(requestQueue == null){
requestQueue = Volley.newRequestQueue(getApplicationContext());
}
}
요청 큐는 한 번만 만들어 계속 사용할 수 있기 때문에 static 키워드로 클래스 변수를 선언한 후 할당하였다.
요청 큐를 만들 때는 Volley.newRequestQueue 메소드를 사용하였다.
텍스트뷰에 문자를 출력하는 메소드 println을 정의하였다.
public void println(String data) {
textView.append(data + "\n");
}
이번에는 스레드를 사용하지 않으므로 핸들러로 정의할 필요가 없었다.
웹 서버에 요청을 보내고 결과를 받는 메소드 request를 정의하였다.
public void makeRequest() {
String url = editText.getText().toString();
StringRequest request = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
@Override
public void onResponse(String response) {
println("응답 -> " + response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
println("에러 -> " + error.getMessage());
}
}) {
@Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
return params;
}
};
request.setShouldCache(false);
requestQueue.add(request);
println("요청 보냄");
}
요청 객체를 StringRequest 클래스로 만들었다.
StringRequest request = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
@Override
public void onResponse(String response) {
println("응답 -> " + response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
println("에러 -> " + error.getMessage());
}
}) {
@Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
return params;
}
};
요청 객체를 new 연산자로 만들 때 네 개의 파라미터를 전달하였다.
첫 번째 파라미터로는 GET 또는 POST 메소드를 전달하여 요청 방식을 지정한다.
두 번째 파라미터로는 웹 사이트 주소를 전달한다.
세 번째 파라미터로는 응답받을 리스너 객체를 전달한다. 이 리스너의 onResponse 메소드는 응답을 받았을 때 자동으로 호출된다.
네 번째 파라미터로는 에러가 발생했을 때 호출될 리스너 객체를 전달한다.
여기서는 전달 방식으로 GET 방식을 사용했지만 POST 방식을 사용하면서 요청 파라미터를 전달하고자 한다면 getParams 메소드에서 반환하는 HashMap 객체에 파라미터 값들을 넣어주면 된다.
요청 객체를 만들었다면 이 객체를 요청 큐에 넣어준다.
request.setShouldCache(false);
requestQueue.add(request);
println("요청 보냄");
요청 큐의 add 메소드로 요청 객체를 넣으면 요청 큐가 자동으로 요청과 응답 과정을 진행한다.
요청 객체는 cache 메커니즘을 지원하는데 이전 응답 결과를 사용하지 않겠다면 setShouldCache 메소드를 사용해 cache를 사용하지 않도록 설정할 수 있다.
버튼을 누르면 정의한 요청 메소드가 실행되도록 하였다.
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
makeRequest();
}
});