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

Кто-нибудь может сказать мне, что я делаю неправильно, или как структурировать код?

Спасибо заранее.

Ответы

Ответ 1

в целом, это хорошая практика, чтобы разделить такие вещи, так что вы на правильном пути, подумайте над тем, чтобы создать класс singelton, который обрабатывает ваши запросы - это очень общий шаблон, но должен получите структуру:

создайте одноэлементный класс, который вы устанавливаете при появлении приложения:

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 с некоторыми незначительными изменениями (см. этот поток SO для получения дополнительной информации о GET), и вы можете называть это извне (onClicks и т.д.), просто помните, что они должны совпадать между методами.

Надеюсь, что это поможет и не слишком поздно!

Ответ 2

Я использую для этого простое решение. Создать Listeners (поскольку они являются интерфейсом, они не могут быть созданы напрямую, но могут быть созданы как анонимные классы, реализующие интерфейс) внутри действия или фрагмента. Передайте эти экземпляры в качестве параметров для запроса. (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();

    }
};

}

Затем создайте класс, у которого есть запрос, и передайте этим слушателям метод запроса этого класса, что все. Я не объясняю эту часть, это так же, как создание объекта запроса в любом учебнике. Но вы можете настроить этот класс по своему усмотрению. Вы можете создать singleton RequestQueue, чтобы проверить приоритет, или задать параметры тела тела тела этим методам в качестве пареметров.

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 для instatnce

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