web-dev-qa-db-ja.com

Android Volley-別のクラスでリクエストを分離する方法

こんにちはボレーリクエストをモジュール化して、アクティビティプレゼンテーションコードとボレーリクエストを混在させないようにしたいと思います。私が見たすべてのサンプル、ボレーリクエストは、たとえば、アクティビティボタンからのOnClickイベントに配置されています。

私はこのコードを意味します(diffソースから取得):

// prepare the Request
JsonObjectRequest getRequest = new JsonObjectRequest(Request.Method.GET, url, null,
    new Response.Listener<JSONObject>() 
    {
        @Override
        public void onResponse(JSONObject response) {   
                        // display response     
            Log.d("Response", response.toString());
        }
    }, 
    new Response.ErrorListener() 
    {
         @Override
         public void onErrorResponse(VolleyError error) {            
            Log.d("Error.Response", response);
       }
    }
);

// add it to the RequestQueue   
queue.add(getRequest);

ここでの私のポイントは、このすべての要求コードを別のクラスに取得し、クラスをインスタンス化してmakeRequestを呼び出す方法です。私はすでにこれを試しましたが、失敗します。コンテキストに関連するものかどうかはわかりませんが、失敗します...

これは私がしました:

public void onClick(View v) {
    try{

        Utils varRequest = new Utils(getApplicationContext());
        String url = "https://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=";

        varRequest.makeRequest(url);
        mitexto.setText(varRequest.miError);
    }
    catch(Exception excepcion) {
        System.out.println(excepcion.toString());

        }

    }

...そしてUtilsクラスは:

public class Utils {
    public Context contexto;
    public String miError;
    private RequestQueue queue ;

    public Utils (Context contextoInstancia){
        contexto = contextoInstancia;
        queue = Volley.newRequestQueue(contexto);
    }

    public void makeRequest(String url){

        JsonObjectRequest jsObjRequest = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {

            @Override
            public void onResponse(JSONObject response) {
                // TODO Auto-generated method stub
                miError="Response => "+response.toString();
            }
        }, new Response.ErrorListener() {

            @Override
            public void onErrorResponse(VolleyError error) {
                // TODO Auto-generated method stub
                miError="Response => "+error.networkResponse.toString();
            }
        });

        queue.add(jsObjRequest);
    }
}   

誰かが私が間違っていること、またはコードを構造化する方法を教えてもらえますか?

前もって感謝します。

20
marianolp

一般に、この種のものを分離することをお勧めします。正しいパスにいるので、リクエストを処理するシングルトンクラスを作成することを検討してください-これはです非常に一般的なテンプレートですが、構造がうまくいくはずです:

シングルトンクラスを作成します。これは、アプリケーションが起動したときにインスタンス化します。

public class NetworkManager
{
    private static final String TAG = "NetworkManager";
    private static NetworkManager instance = null;

    private static final String prefixURL = "http://some/url/prefix/";

    //for Volley API
    public RequestQueue requestQueue;

    private NetworkManager(Context context)
    {
        requestQueue = Volley.newRequestQueue(context.getApplicationContext());
        //other stuf if you need
    }

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

    //this is so you don't need to pass context each time
    public static synchronized NetworkManager getInstance()
    {
        if (null == instance)
        {
            throw new IllegalStateException(NetworkManager.class.getSimpleName() +
                    " is not initialized, call getInstance(...) first");
        }
        return instance;
    }

    public void somePostRequestReturningString(Object param1, final SomeCustomListener<String> listener)
    {

        String url = prefixURL + "this/request/suffix";

        Map<String, Object> jsonParams = new HashMap<>();
        jsonParams.put("param1", param1);

        JsonObjectRequest request = new JsonObjectRequest(Request.Method.POST, url, new JSONObject(jsonParams),
                new Response.Listener<JSONObject>()
                {
                    @Override
                    public void onResponse(JSONObject response)
                    {
                         Log.d(TAG + ": ", "somePostRequest Response : " + response.toString());
                         if(null != response.toString())
                           listener.getResult(response.toString());
                    }
                },
                new Response.ErrorListener()
                {
                    @Override
                    public void onErrorResponse(VolleyError error)
                    {
                        if (null != error.networkResponse)
                        {
                            Log.d(TAG + ": ", "Error Response code: " + error.networkResponse.statusCode);
                            listener.getResult(false);
                        }
                    }
                });

        requestQueue.add(request);
    }
}

アプリケーションが起動したとき:

public class MyApplication extends Application
{
  //...

    @Override
    public void onCreate()
    {
        super.onCreate();
        NetworkManager.getInstance(this);
    }

 //...

}

コールバック用の単純なリスナーインターフェイス(別のファイルで十分です):

public interface SomeCustomListener<T>
{
    public void getResult(T object);
}

そして最後に、どこからでも、コンテキストはすでにそこにあります。呼び出すだけです。

public class BlaBla
{
    //.....

        public void someMethod()
        {
            NetworkManager.getInstance().somePostRequestReturningString(someObject, new SomeCustomListener<String>()
            {
                @Override
                public void getResult(String result)
                {
                    if (!result.isEmpty())
                    {
                     //do what you need with the result...
                    }
                }
            });
        }
}

受信する必要があるものに応じて、リスナーで任意のオブジェクトを使用できます。これは、若干の変更を加えたGETリクエストでも機能します(GETの詳細については this SO threadを参照してください )そして、あらゆる場所(onClicksなど)から呼び出すことができます。メソッド間で一致させる必要があることを覚えておいてください。

これが役に立ち、遅すぎないことを願っています!

55
TommySM

これには簡単な解決策を使用します。 リスナーの作成(インターフェースであるため、直接インスタンス化することはできませんが、インターフェースを実装する匿名クラスとしてインスタンス化できます)アクティビティまたはフラグメント内。これらのインスタンスをパラメーターとしてリクエストに渡します。(StringRequest、JsonObjectRequest、またはImageRequest)。

public class MainActivity extends Activity {

private static final String URI_WEATHER = "http://marsweather.ingenology.com/v1/latest/";

private Listener<JSONObject> listenerResponse = new Listener<JSONObject>() {

    @Override
    public void onResponse(JSONObject response) {
        Toast.makeText(MainActivity.this, "Resonse " + response.toString(), Toast.LENGTH_LONG).show();
    }
};

private ErrorListener listenerError = new ErrorListener() {

    @Override
    public void onErrorResponse(VolleyError error) {
        Toast.makeText(MainActivity.this, "Error " + error, Toast.LENGTH_LONG).show();

    }
};

}

次に、リクエストを持つクラスを作成し、このリスナーをこのクラスのリクエストメソッドに渡します。これですべてです。この部分については説明しませんが、これはチュートリアルでリクエストオブジェクトを作成するのと同じですが、このクラスは必要に応じてカスタマイズできます。シングルトンRequestQueueを作成して優先順位を確認するか、body http bodyパラメーターをこのメソッドにパラメーターとして設定できます。

public class NetworkManagerWeather {

public static void getWeatherData(int method, Context context, String url,
        Listener<JSONObject> listenerResponse, ErrorListener listenerError) {
    JsonObjectRequest requestWeather = new JsonObjectRequest(Method.GET, url, null, listenerResponse,
            listenerError);
    Volley.newRequestQueue(context).add(requestWeather);
}

}

最後に、インスタンス化のためにMainActivityからこのメソッドを呼び出します

NetworkManagerWeather.getWeatherData(Method.GET, this, URI_WEATHER, listenerResponse, listenerError);
2
Thracian