The Android Developer Challenge is back! Submit your idea before December 2.

RequestQueue 설정

이전 과정에서는 편리한 Volley.newRequestQueue 메서드를 사용하여 RequestQueue를 설정하고 Volley의 기본 동작을 활용하는 방법을 설명했습니다. 이 과정에서는 RequestQueue를 만들어 자체 맞춤 동작을 제공하는 방법을 단계적으로 설명합니다.

이 과정에서는 또한 RequestQueue를 싱글톤으로 만드는 권장되는 방법을 설명합니다. 이렇게 하면 RequestQueue가 앱의 전체 기간 동안 지속됩니다.

네트워크 및 캐시 설정

RequestQueue가 작업을 실행하기 위해서는 요청을 전송하기 위한 네트워크와 캐싱을 처리하기 위한 캐시가 필요합니다. Volley 도구 상자에 다음과 같은 표준 구현이 있습니다. DiskBasedCache는 응답당 캐시 파일 하나를 메모리 내 색인과 함께 제공하고 BasicNetwork는 선호하는 HTTP 클라이언트를 기반으로 한 네트워크 전송 기능을 제공합니다.

BasicNetwork는 Volley의 기본 네트워크 구현입니다. BasicNetwork는 앱에서 네트워크에 연결하는 데 사용하는 HTTP 클라이언트로 초기화해야 합니다. 일반적으로 이 클라이언트는 HttpURLConnection입니다.

다음 스니펫은 RequestQueue를 설정하는 데 포함된 단계를 보여줍니다.

Kotlin

    // Instantiate the cache
    val cache = DiskBasedCache(cacheDir, 1024 * 1024) // 1MB cap

    // Set up the network to use HttpURLConnection as the HTTP client.
    val network = BasicNetwork(HurlStack())

    // Instantiate the RequestQueue with the cache and network. Start the queue.
    val requestQueue = RequestQueue(cache, network).apply {
        start()
    }

    val url = "http://www.example.com"

    // Formulate the request and handle the response.
    val stringRequest = StringRequest(Request.Method.GET, url,
             Response.Listener<String> { response ->
                // Do something with the response
            },
            Response.ErrorListener { error ->
                // Handle error
                textView.text = "ERROR: %s".format(error.toString())
            })

    // Add the request to the RequestQueue.
    requestQueue.add(stringRequest)

    // ...
    

자바

    RequestQueue requestQueue;

    // Instantiate the cache
    Cache cache = new DiskBasedCache(getCacheDir(), 1024 * 1024); // 1MB cap

    // Set up the network to use HttpURLConnection as the HTTP client.
    Network network = new BasicNetwork(new HurlStack());

    // Instantiate the RequestQueue with the cache and network.
    requestQueue = new RequestQueue(cache, network);

    // Start the queue
    requestQueue.start();

    String url ="http://www.example.com";

    // Formulate the request and handle the response.
    StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
            new Response.Listener<String>() {
        @Override
        public void onResponse(String response) {
            // Do something with the response
        }
    },
        new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                // Handle error
        }
    });

    // Add the request to the RequestQueue.
    requestQueue.add(stringRequest);

    // ...
    

한 번만 요청하면 되고 스레드 풀을 남겨두고 싶지 않은 경우에는 필요할 때마다 RequestQueue를 만들고 응답 또는 오류가 반환된 후 간단한 요청 보내기에 설명된 Volley.newRequestQueue() 메서드를 사용하여 RequestQueue에서 stop()을 호출하면 됩니다. 하지만 가장 일반적인 사용 사례는 다음 섹션에 설명된 대로 RequestQueue를 싱글톤으로 만들어 앱의 전체 기간 동안 계속 실행하는 것입니다.

싱글톤 패턴 사용

애플리케이션에서 네트워크를 지속적으로 사용하는 경우 아마도 앱의 전체 기간 동안 지속되는 RequestQueue의 단일 인스턴스를 설정하는 것이 가장 효율적입니다. 다양한 방법으로 단일 인스턴스를 설정할 수 있습니다. 권장되는 방법은 RequestQueue 및 기타 Volley 기능을 캡슐화하는 싱글톤 클래스를 구현하는 것입니다. 다른 방법은 Application의 서브클래스를 만들고 Application.onCreate()에서 RequestQueue를 설정하는 것입니다. 하지만 이 방법은 권장되지 않습니다. 정적 싱글톤이 더 모듈화된 방식으로 같은 기능을 제공할 수 있습니다.

핵심 개념은 Activity 컨텍스트가 아니라 Application 컨텍스트로 RequestQueue를 인스턴스화해야 한다는 것입니다. 이렇게 하면 활동이 다시 만들어질(예: 사용자가 기기를 회전할) 때마다 RequestQueue가 다시 만들어지는 대신 앱의 전체 기간 동안 지속됩니다.

다음은 RequestQueueImageLoader 기능을 제공하는 싱글톤 클래스의 예입니다.

Kotlin

    class MySingleton constructor(context: Context) {
        companion object {
            @Volatile
            private var INSTANCE: MySingleton? = null
            fun getInstance(context: Context) =
                INSTANCE ?: synchronized(this) {
                    INSTANCE ?: MySingleton(context).also {
                        INSTANCE = it
                    }
                }
        }
        val imageLoader: ImageLoader by lazy {
            ImageLoader(requestQueue,
                    object : ImageLoader.ImageCache {
                        private val cache = LruCache<String, Bitmap>(20)
                        override fun getBitmap(url: String): Bitmap {
                            return cache.get(url)
                        }
                        override fun putBitmap(url: String, bitmap: Bitmap) {
                            cache.put(url, bitmap)
                        }
                    })
        }
        val requestQueue: RequestQueue by lazy {
            // applicationContext is key, it keeps you from leaking the
            // Activity or BroadcastReceiver if someone passes one in.
            Volley.newRequestQueue(context.applicationContext)
        }
        fun <T> addToRequestQueue(req: Request<T>) {
            requestQueue.add(req)
        }
    }
    

자바

    public class MySingleton {
        private static MySingleton instance;
        private RequestQueue requestQueue;
        private ImageLoader imageLoader;
        private static Context ctx;

        private MySingleton(Context context) {
            ctx = context;
            requestQueue = getRequestQueue();

            imageLoader = new ImageLoader(requestQueue,
                    new ImageLoader.ImageCache() {
                private final LruCache<String, Bitmap>
                        cache = new LruCache<String, Bitmap>(20);

                @Override
                public Bitmap getBitmap(String url) {
                    return cache.get(url);
                }

                @Override
                public void putBitmap(String url, Bitmap bitmap) {
                    cache.put(url, bitmap);
                }
            });
        }

        public static synchronized MySingleton getInstance(Context context) {
            if (instance == null) {
                instance = new MySingleton(context);
            }
            return instance;
        }

        public RequestQueue getRequestQueue() {
            if (requestQueue == null) {
                // getApplicationContext() is key, it keeps you from leaking the
                // Activity or BroadcastReceiver if someone passes one in.
                requestQueue = Volley.newRequestQueue(ctx.getApplicationContext());
            }
            return requestQueue;
        }

        public <T> void addToRequestQueue(Request<T> req) {
            getRequestQueue().add(req);
        }

        public ImageLoader getImageLoader() {
            return imageLoader;
        }
    }
    

다음은 싱글톤 클래스를 사용하여 RequestQueue 작업을 실행하는 예입니다.

Kotlin

    // Get a RequestQueue
    val queue = MySingleton.getInstance(this.applicationContext).requestQueue

    // ...

    // Add a request (in this example, called stringRequest) to your RequestQueue.
    MySingleton.getInstance(this).addToRequestQueue(stringRequest)
    

자바

    // Get a RequestQueue
    RequestQueue queue = MySingleton.getInstance(this.getApplicationContext()).
        getRequestQueue();

    // ...

    // Add a request (in this example, called stringRequest) to your RequestQueue.
    MySingleton.getInstance(this).addToRequestQueue(stringRequest);