web-dev-qa-db-fra.com

Android Volley - Comment isoler les requêtes dans une autre classe

Bonjour, je voudrais modulariser les demandes de volley-ball afin de ne pas mélanger le code de présentation d'activité avec les demandes de volley-ball. Tous les échantillons que j'ai vus, la demande de volée sont placés - par exemple - sur l'événement OnClick à partir d'un bouton d'activité.

Je veux dire ce code (tiré de la source 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);

Mon point ici est de savoir comment obtenir tout ce code de demande dans une autre classe et simplement l'instance de la classe et appeler le makeRequest. J'ai déjà essayé mais ça échoue. Je ne sais pas si c'est quelque chose de lié au contexte mais ça échoue ...

J'ai fait ça:

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

        }

    }

... et la classe Utils est:

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

Quelqu'un peut-il me dire ce que je fais mal ou comment structurer le code?

Merci d'avance.

20
marianolp

en général, c'est une bonne pratique de séparer ce genre de choses, donc vous êtes sur la bonne voie, pensez à créer une classe singelton qui gère vos demandes - c'est un modèle très général , mais devrait faire fonctionner votre structure:

créer une classe singleton, que vous installez lorsque votre application arrive:

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

lorsque votre candidature arrive:

public class MyApplication extends Application
{
  //...

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

 //...

}

une interface d'écoute simple pour votre rappel (un fichier séparé ferait du bien):

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

et enfin, où que vous vouliez, le contexte est déjà là, appelez simplement:

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

vous pouvez utiliser n'importe quel objet avec l'écouteur, en fonction de ce que vous devez recevoir, cela fonctionne également pour les requêtes GET avec quelques modifications mineures, (voir this SO thread pour plus d'informations sur GET) ) et vous pouvez appeler cela de partout (onClicks, etc.), rappelez-vous juste qu'ils doivent correspondre entre les méthodes.

J'espère que cela aide et pas trop tard!

55
TommySM

J'utilise une solution simple pour cela. Créer des écouteurs (car ce sont des interfaces, ils ne peuvent pas être instanciés directement mais ils peuvent être instanciés en tant que classes anonymes qui implémentent l'interface) à l'intérieur de l'activité ou du fragment. Passez ces instances en tant que paramètres à la demande (StringRequest, JsonObjectRequest ou 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();

    }
};

}

Ensuite, créez une classe qui a une demande et passez ces écouteurs à la méthode de demande de cette classe, c'est tout. Je n'explique pas cette partie, c'est la même chose que la création d'un objet de demande dans les tutoriels, mais vous pouvez personnaliser cette classe comme vous le souhaitez. Vous pouvez créer un singleton RequestQueue pour vérifier la priorité ou définir des paramètres de corps http body pour ces méthodes en tant que paramètres.

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

}

Enfin, appelez cette méthode à partir de MainActivity pour instatnce

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