Google は、黒人コミュニティに対する人種平等の促進に取り組んでいます。取り組みを見る

RequestQueue をセットアップする

前のレッスンでは、コンビニエンス メソッド Volley.newRequestQueue を使用することによって、Volley のデフォルト動作を活用して RequestQueue をセットアップする方法について説明しました。このレッスンでは、独自のカスタム動作を指定できるように RequestQueue を作成する手順を詳細に説明します。

また、このレッスンでは、RequestQueue をシングルトンとして作成し、アプリのライフタイムを通じて RequestQueue が存続するようにセットアップする際のおすすめの方法についても説明します。

ネットワークとキャッシュをセットアップする

RequestQueue がその役目を果たすには、ネットワークによるリクエストの転送と、キャッシュによる処理という 2 つの機能が必要です。Volley ツールボックスには、この 2 つの機能の標準実装が用意されています。メモリ内インデックスを備えた 1 レスポンスあたり 1 ファイルのキャッシュを提供する DiskBasedCache と、優先 HTTP クライアントに基づいてネットワーク転送を実現する BasicNetwork です。

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)

    // ...
    

Java

    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);

    // ...
    

ワンタイム リクエストを作成する必要があるだけで、スレッドプールを残したくない場合は、Volley.newRequestQueue() メソッドを使用して(シンプルなリクエストを送信するを参照)、必要になるたびに RequestQueue を作成し、レスポンスまたはエラーが返ってきたら、その RequestQueue に対して stop() を呼び出します。ただし、ユースケースとしては、RequestQueue をシングルトンとして作成し、アプリのライフタイムを通じて稼働させる方が一般的です。その方法について、次のセクションで説明します。

シングルトン パターンを使用する

アプリがネットワークを常時使用する場合、通常は、RequestQueue の単一のインスタンスをセットアップして、アプリのライフタイムを通じて存続させるのが最も効率的になります。このセットアップは、さまざまな方法で実現できます。その中でも、シングルトン クラスを実装し、RequestQueue と他の Volley 機能をカプセル化する方法をおすすめします。ほかにも、Application をサブクラス化して、Application.onCreate() 内に RequestQueue をセットアップする方法があります。ただし、この方法はおすすめしません。静的シングルトンの方が、モジュール化をさらに進めた方法で同じ機能を提供できます。

重要なのは、RequestQueueActivity コンテキストではなく Application コンテキストでインスタンス化する必要があるという点です。これにより、RequestQueue が必ずアプリのライフタイムを通じて存続するようになります。そのため、アクティビティが再作成されるたびに(たとえば、ユーザーがデバイスを回転させるたびに)、インスタンスを再作成する必要がなくなります。

RequestQueue 機能と ImageLoader 機能を提供するシングルトン クラスの例を以下に示します。

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)
        }
    }
    

Java

    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)
    

Java

    // 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);