Androidアプリ開発 Volley 処理をJSONで扱う

2016年06月20日(編集2016年06月20日)
このエントリーをはてなブックマークに追加

VolleyはAndroid用のHTTPライブラリです。
この記事は、Volleyでネットワークに接続する方法を記載した記事です。

環境はAndroid 6.0 (API level 23) です。

環境

  • OS X Yosemite
  • Oracle jdk version 1.8.0_72
  • Android Studio 2.1.1
  • Volley 1.0.19
  • Nginx 1.8.1(Server)
  • Golang(API)

難易度

初心者向け

Volley

VolleyはAndroid用のネットワークライブラリです。
通信処理のキューイング、非同期のデータ取得からUIスレッドへの連携、キャッシュ(メモリーキャッシュ・ローカルキャッシュ)、通信失敗時のリトライ機構などの課題を効率的に解決することができます。

Volleyのインストール

build.gradleを開き、volleyのライブラリを設定します。

{project_folder}/app/build.gradle
dependencies {
    +compile 'com.mcxiaoke.volley:library:1.0.19'
}
        

Rebuild Projectでビルドに成功すれば、volleyが利用できます。

実装

コードの実装します。

ローカルマシンの192.168.11.8/apiに接続して、APIを呼び出してjsonを取得するコードを記述します。
サーバーから取得するサンプルのjsonは以下の通りです。

json
{
  "last_updated_at": "yyyy-MM-dd HH:mm:ss",
  "masters": [{
      "id": 1,
      "name": "article",
      "summmey": "article contents"
    }, {
      "id": 2,
      "name": "menu",
      "summmey": "menu contents"
    }
  ]
}
        

Volleyシングルトン実装

まずは、Volleyを扱うシングルトンのクラスを作成します。

{project_folder}/util/VolleyHelper.java
import android.content.Context;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.Volley;

public class VolleyHelper {
    private static VolleyHelper mInstance;
    private RequestQueue mRequestQueue;
    private static Context mCtx;

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

    private VolleyHelper(Context context) {
        mCtx = context;
        mRequestQueue = getRequestQueue();
    }

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

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

}
        

Volleyはシングルトンのクラスで利用することが推奨されています。
なぜなら、アプリの画面遷移時に、前の画面の通信タスクが残ってしまう可能性があるからです。

例えば、高速に6つの画面を遷移して、それぞれの画面で通信が走ると、5(デフォルト)×6で30の通信タスクがメモリに残ることになります。
この時、アクセスしたURLが動画や容量の大きな画像の場合、確実にOutOfMemoryが発生してしまいます。

なので、最初にシングルトンでRequestQueueのインスタンスを1つ作成し、それを使い回す実装がオススメです。

Fragment実装

上記で作成したVolleyのシングルトンクラスを、Fragmentクラスで利用します。

{project_folder}/ui/JsonObjectRequestFragment.java
public class JsonObjectRequestFragment extends Fragment {

    public static final String TAG = "MainFragment";

    private VolleyHelper mInstance;

    private OnListFragmentInteractionListener mListener;

    @SuppressWarnings("unused")
    public static MainFragment newInstance(int columnCount) {
        MainFragment fragment = new MainFragment();
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_main_list, container, false);

        // Set the adapter
        if (view instanceof RecyclerView) {
            Context context = view.getContext();
            RecyclerView recyclerView = (RecyclerView) view;
            recyclerView.setLayoutManager(new LinearLayoutManager(context));
            recyclerView.setAdapter(new MainRecyclerViewAdapter(MainHelper.all(getActivity().getApplicationContext()), mListener));
        }
        return view;
    }

    public void onStart() {
        super.onStart();
        // Instantiate the RequestQueue from VolleySingleton
        mInstance = VolleyHelper.getInstance(getActivity().getApplicationContext());
        // API
        connectApi();
    }

    @Override
    public void onStop () {
        super.onStop();
        if (mInstance.getRequestQueue() != null) {
            mInstance.getRequestQueue().cancelAll(TAG);
        }
    }

    private void connectApi() {
        String url = "http://192.168.11.8/api";
        JsonObjectRequest jsObjRequest = new JsonObjectRequest
                (Request.Method.GET, url, new Response.Listener<JSONObject>() {

                    @Override
                    public void onResponse(JSONObject response) {
                        // get json
                        try {
                            String last_updated_at = response.getString("last_updated_at");
                            JSONArray jSONArray = response.getJSONArray("masters");
                            Log.d("str : ", last_updated_at);
                            Log.d("jSONArray: ", jSONArray.toString());
                        } catch(Exception e) {
                            Log.d("exception: ", e.getMessage());
                        }
                    }
                }, new Response.ErrorListener() {

                    @Override
                    public void onErrorResponse(VolleyError error) {
                        Log.d("str: ", error.getMessage());
                    }
                });

        Log.d("connectApi: ", url);

        // Set the tag on the request.
        jsObjRequest.setTag(TAG);

        if (mInstance != null) {
            // Add a request to your RequestQueue.
            mInstance.addToRequestQueue(jsObjRequest);
            // Start the queue
            mInstance.getRequestQueue().start();
        }
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        Log.d("onAttach _a ", activity.getClass().getName());
        Log.d("Build.VERSION.SDK_INT ", String.valueOf(Build.VERSION.SDK_INT));
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) return;
        if (activity instanceof OnListFragmentInteractionListener) {
            mListener = (OnListFragmentInteractionListener) activity;
        } else {
            throw new RuntimeException(activity.toString()
                    + " must implement OnListFragmentInteractionListener");
        }
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        Log.d("onAttach _c ", context.getClass().getName());

        if (context instanceof OnListFragmentInteractionListener) {
            mListener = (OnListFragmentInteractionListener) context;
        } else {
            throw new RuntimeException(context.toString()
                    + " must implement OnListFragmentInteractionListener");
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mListener = null;
    }

    public interface OnListFragmentInteractionListener {
        void onListFragmentInteraction(Main item);
    }
}
        

■ 実装の解説

1. RequestQueueの取得

// Instantiate the RequestQueue from VolleySingleton
mInstance = VolleyHelper.getInstance(getActivity().getApplicationContext());
        

シングルトンのVolleyHelperクラスからインスタンスを取得して、RequestQueueを利用できるようにします。

2. JsonObjectRequestでjsonを扱う

        String url = "http://192.168.11.8/api";
        JsonObjectRequest jsObjRequest = new JsonObjectRequest
                (Request.Method.GET, url, new Response.Listener<JSONObject>() {

                    @Override
                    public void onResponse(JSONObject response) {

                        try {
                            String last_updated_at = response.getString("last_updated_at");
                            JSONArray jSONArray = response.getJSONArray("masters");
                            Log.d("str : ", last_updated_at);
                            Log.d("jSONArray: ", jSONArray.toString());
                        } catch(Exception e) {
                            Log.d("exception: ", e.getMessage());
                        }

                    }
                }, new Response.ErrorListener() {

                    @Override
                    public void onErrorResponse(VolleyError error) {
                        Log.d("str: ", error.getMessage());
                    }
                });
        

データをjsonで扱えるように、JsonObjectRequestを実体化しています。
urlにGETメソッドで送信してます。new Response.Listenerは成功時の匿名クラス、Response.ErrorListenerが失敗時の匿名クラスの実体化です。

また、jsonの配列データは、getJSONArrayで取得できます。

3. リクエストの追加とネットワーク接続

if (mInstance != null) {
    // Add a request to your RequestQueue.
    mInstance.addToRequestQueue(jsObjRequest);
    // Start the queue
    mInstance.getRequestQueue().start();
}
        

RequestQueueにJsonObjectRequestの情報を渡し、RequestQueue#start()メソッドでネットワーク通信を実行します。

ビルドして実行

実装を終えたら、ビルドしてアプリを実行します。

console
str :: yyyy-MM-dd HH:mm:ss
jSONArray:: [{"id":"1","name":"article","summmey":"article contents"},{"id":"2","name":"menu","summmey":"menu contents"}]
        

onResponseメソッドでjsonが取得できました。

まとめ

Volleyは非常に優れたネットワーク接続ツールです。
ただ、クセが強いので実装には慣れが必要です。

また、jsonの処理はgsonを利用しても良いと思います。

関連記事

タグ検索で調べてみよう

Android6.0 ライブラリ