The application quite often sends and receives requests from the server. I used to do everything with the help of DefaultHttpClient and it worked fine, but I decided to switch to Volley and there is a big problem. After about 30 requests ceases to send and receive them altogether. LogCat is empty. Made singleton for RequestQueue. Used by VolleyPlus.

Initialization of singleton in Application

public void onCreate() { super.onCreate(); //Init Volley requests StringRequest.getInstance(this); ... } 

Class itself

 public class StringRequest { private final String TAG = this.getClass().getSimpleName(); private static StringRequest mInstance; private RequestQueue mRequestQueue; private ProgressListener mProgress; private ResponseListener mResponse; private ErrorListener mError; private List<String> files; private StringRequest(Context context){ mRequestQueue = getRequestQueue(context.getApplicationContext()); } public static synchronized StringRequest getInstance(Context context) { if (null == mInstance) mInstance = new StringRequest(context); return mInstance; } public static synchronized StringRequest getInstance() { if (null == mInstance) { throw new IllegalStateException(StringRequest.class.getSimpleName() + " is not initialized, call getInstance(...) first"); } return mInstance; } public RequestQueue getRequestQueue(Context context) { if (mRequestQueue == null) { mRequestQueue = Volley.newRequestQueue(context, getStack()); } return mRequestQueue; } private HurlStack getStack(){ return new HurlStack() { @Override protected HttpURLConnection createConnection(URL url) throws IOException { HttpsURLConnection httpsURLConnection = (HttpsURLConnection) super.createConnection(url); try { httpsURLConnection.setSSLSocketFactory(getSSLSocketFactory()); httpsURLConnection.setHostnameVerifier(getHostnameVerifier()); } catch (CertificateException | KeyStoreException | KeyManagementException | NoSuchAlgorithmException e) { Log.e(TAG, "getHurlStack ", e); } return httpsURLConnection; } }; } public void createRequest(String tag, String url, Map<String, String> params){ final SimpleMultiPartRequest request = new SimpleMultiPartRequest(Request.Method.POST, url, new Response.Listener<String>() { @Override public void onResponse(String response) { //Log.d(TAG, response); if(mResponse != null) mResponse.onResponse(response); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { //Log.d(TAG, error.getMessage()); if(mError != null) mError.onError(error); } }) { @Override public Map<String, String> getHeaders() throws AuthFailureError { SharedPreferences app_preferences = PreferenceManager.getDefaultSharedPreferences(Application.getInstance()); HashMap<String, String> params = new HashMap<>(); params.put("PARAM1", app_preferences.getString("user", "")); params.put("PARAM2", app_preferences.getString("password", "")); return params; } }; if(getFiles()!=null && getFiles().size()>0) { for(int i=0; i<getFiles().size(); i++) { request.addFile("images", getFiles().get(i)); } } request.setFixedStreamingMode(true); request.setTag(tag); /*request.setRetryPolicy(new DefaultRetryPolicy(20 * 1000, 0, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));*/ request.setRetryPolicy(new DefaultRetryPolicy(20 * 1000, 1, 1.0f)); request.setShouldCache(false); if(params!=null && params.size()>0){ for (Map.Entry<String, String> entry : params.entrySet()) { request.addStringParam(entry.getKey(), entry.getValue()); } } request.setOnProgressListener(new Response.ProgressListener() { int latestPercentDone, percentDone; @Override public void onProgress(long transferredBytes, long totalSize) { latestPercentDone = (int) ((transferredBytes / (float) totalSize) * 100); if (percentDone != latestPercentDone) { percentDone = latestPercentDone; if(mProgress != null) mProgress.onProgress(percentDone); } } }); mRequestQueue.add(request); } private HostnameVerifier getHostnameVerifier() { return new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier(); return hv.verify("mysite.com", session); } }; } private TrustManager[] getWrappedTrustManagers(TrustManager[] trustManagers) { final X509TrustManager originalTrustManager = (X509TrustManager) trustManagers[0]; return new TrustManager[]{ new X509TrustManager() { public X509Certificate[] getAcceptedIssuers() { return originalTrustManager.getAcceptedIssuers(); } public void checkClientTrusted(X509Certificate[] certs, String authType) { try { if (certs != null && certs.length > 0){ certs[0].checkValidity(); } else { originalTrustManager.checkClientTrusted(certs, authType); } } catch (CertificateException e) { Log.w(TAG, e.toString()); } } public void checkServerTrusted(X509Certificate[] certs, String authType) { try { if (certs != null && certs.length > 0){ certs[0].checkValidity(); } else { originalTrustManager.checkServerTrusted(certs, authType); } } catch (CertificateException e) { Log.w(TAG, e.toString()); } } } }; } private SSLSocketFactory getSSLSocketFactory() throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException, KeyManagementException { CertificateFactory cf = CertificateFactory.getInstance("X.509"); InputStream caInput = this.getClass().getClassLoader().getResourceAsStream("res/raw/cert.bks"); //Certificate ca = cf.generateCertificate(caInput); KeyStore keyStore = KeyStore.getInstance("BKS"); keyStore.load(caInput, "password".toCharArray()); //keyStore.setCertificateEntry("ca", ca); caInput.close(); String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm); tmf.init(keyStore); TrustManager[] wrappedTrustManagers = getWrappedTrustManagers(tmf.getTrustManagers()); SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, wrappedTrustManagers, null); return sslContext.getSocketFactory(); } public List<String> getFiles() { return files; } public void setFiles(List<String> files) { this.files = files; } public void setProgressListener(ProgressListener mProgress) { this.mProgress = mProgress; } public void setResponseListener(ResponseListener mResponse) { this.mResponse = mResponse; } public void setErrorListener(ErrorListener mError) { this.mError = mError; } public interface ResponseListener{ void onResponse(String response); } public interface ErrorListener{ void onError(VolleyError error); } public interface ProgressListener{ void onProgress(int percent); } 

}

And then I use it, for example in Activity:

 try{ Map<String, String> mParams = new HashMap<>(); mParams.put("lat", String.valueOf(params[0])); mParams.put("lon", String.valueOf(params[1])); final CountDownLatch countDownLatch = new CountDownLatch(1); final Object[] responseHolder = new Object[1]; StringRequest request = StringRequest.getInstance(); request.setResponseListener(new StringRequest.ResponseListener() { @Override public void onResponse(String response) { responseHolder[0] = response; countDownLatch.countDown(); } }); request.setErrorListener(new StringRequest.ErrorListener() { @Override public void onError(VolleyError error) { responseHolder[0] = error; countDownLatch.countDown(); } }); request.createRequest(TAG, URL, mParams); try { countDownLatch.await(); }catch (InterruptedException e){ throw new RuntimeException(e); } if(responseHolder[0] instanceof VolleyError){ VolleyError volleyError = (VolleyError)responseHolder[0]; Log.e(getClass().getName(), volleyError.toString()); }else{ String response = (String)responseHolder[0]; try { JSONObject mJson = new JSONObject(response); try { if (mJson.getString("status").equals("OK")) { try { User user = AppSettings.getmUser(); user.setHomeLat(Double.parseDouble(String.valueOf(params[0]))); user.setHomeLon(Double.parseDouble(String.valueOf(params[1]))); AppSettings.setmUser(user); Log.i(getClass().getName(), "Get location: " + String.valueOf(params[0]) + ":" + String.valueOf(params[1])); return true; }catch(Exception ex){ Log.e(this.getClass().getSimpleName(), "Double convert Exception", e); } } else if (mJson.getString("status").equals("BAD")) { Log.i(getClass().getName(), "Error " + mJson.getInt("statusCode") + " " + mJson.getString("message")); } } catch (JSONException e) { Log.e(getClass().getName(), "JSON Exception1", e); throw e; } } catch (JSONException e) { e.printStackTrace(); } } }catch(Exception e){ this.e = e; } 

If you stop using singleton, it works fine, but Volley keeps all requests in memory https://stackoverflow.com/questions/25868608/volley-framewok-request-keeps-objects-in-memory and the application hangs after about half a day of intensive work .

  • If it's possible and it's not too late, switch to Retrofit 2. Retrofit 2 is a great library from Square that really helps to create and manage API requests. * Retrofit will make a separate thread itself. * Significantly reduces the length of the code during development * Dynamically builds requests * Automatically converts JSON to objects (via GSON) * Handles errors * Can transfer files * has OkHttp for working directly with the top level of Java sockets. - Andrew Grow
  • If not difficult, you can give a link to examples. I am especially interested in working through SSL using the BKS provider. - pwb
  • No problem. Self retrofit square.imtqy.com/retrofit Working with SSL google.com.ua/… Hope this helps you. Good luck! - Andrew Grow
  • Unfortunately, Retrofit will not suit me. I don’t need to immediately convert the server’s response into objects, and I’ll have to rewrite almost all of the REST on the server, and the code turned out to be quite large for a simple request without parameters. I will try using okHttp. - pwb

0