Farhan Ibn Wahid
Farhan Ibn Wahid

Reputation: 1012

How to solve Memory Leaks in Volley Response for a Background Service

I am using this service to send location to a web database using Volley. I have been fighting with Memory Leaks for almost two weeks but still couldn't solve it. I went through all the related questions but could not find working solution.

When the service is running in the background, it sends location using Volley and the Ram usage in the Device keeps increasing with each request sent untill it craches for OutOfMemory or the system kills the process. I tried deleting cache, tried making the service as a remote process so that it may clear process memory when restarts and many things but could not solve it yet and i'm dying here to solve it. If anyone could help me, I really appreciate it. Thanks

So, Here is my code:

ForeGroundService:

public int onStartCommand(final Intent intent, int flags, final int startId) {

    //Log.i(TAG,"onStartCommand");

    sessionManager = new SessionManager(ForeGroundService.this);

    sessionManager.checkLogin();
    if (sessionManager.isDayRunning().equals("1") && serviceStarted == 1)
        if (!mGoogleApiClient.isConnected()) mGoogleApiClient.connect();

    TimerForServiceDelay = new CountDownTimer( 5 * 60 * 1000, 60*1000) {

        @Override
        public void onTick(long l) {
            //Log.i(TAG,"onTick (onStartCommand)");
        }

        @Override
        public void onFinish() {

            //Log.i(TAG,"onFinish (onStartCommand)");

            String Location = "Location :: [" + Co_or[0] + "," + Co_or[1] + "]";

            Intent notificationIntent = new Intent(ForeGroundService.this, MainActivity.class);
            PendingIntent pendingIntent = PendingIntent.getActivity(ForeGroundService.this, 0, notificationIntent, 0);

            Notification notification = new NotificationCompat.Builder(ForeGroundService.this, LOCATION_SENDING_NOTIFICATION_CHANNEL_ID)
                    .setContentTitle("Service")
                    .setContentText(Location)  .setColor(getResources().getColor(R.color.colorPrimary))
                    .setSmallIcon(R.drawable.ic_my_location_black_24dp)
                    .setContentIntent(pendingIntent)
                    .setAutoCancel(true)
                    .build();

            SendCoordinatesToDatabase();

            if (sessionManager.isDayRunning().equals("0")) {
                mGoogleApiClient.disconnect();
                Log.i(TAG, "just before stop self");
                serviceStarted = 0;
                stopSelf();
            } else {
                //Log.i(TAG,"on else condition of stop self");
                ContextCompat.startForegroundService(getApplicationContext(), new Intent(ForeGroundService.this,ForeGroundService.class));
                startForeground(1, notification);
                //stopForeground(true);
            }
            stopSelf();
        }

    }.start();

    return Service.START_STICKY; //This allows to restart the service when get killed automatically (WORKING solution)

}    

SendCoordinatesToDatabase:

public void SendCoordinatesToDatabase() {

    final String URL_LOCATION = getResources().getString(R.string.URL_LOCATION);

    StringRequest stringRequest = new StringRequest(Request.Method.POST, URL_LOCATION, new Response.Listener<String>() {

        @Override
        public void onResponse(String response) {
            Log.i(TAG, "[" + response + "]");
            try {
                JSONObject jsonObject = new JSONObject(response);
                String success = jsonObject.getString("success");
                String message = jsonObject.getString("message");
                //Log.i(TAG, "[" + message + "]");
                if (success.equals("1")) {
                    // TODO: Do something later
                } else {
                    // TODO: Do something later
                }

            } catch (JSONException e) {
                e.printStackTrace();
                Log.i(TAG, "JSON Error : " + e.toString());
            }

        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {

        }
    }) {

        @Override
        public Request<?> setCacheEntry(Cache.Entry entry) {
            return super.setCacheEntry(null);
        }

        @Override
        public Cache.Entry getCacheEntry() {
            return null;
        }

        @Override
        public Request<?> setRequestQueue(RequestQueue requestQueue) {
            requestQueue.getCache().clear();
            return super.setRequestQueue(requestQueue);
        }

        @Override
        protected Map<String, String> getParams(){

            String[] all = collectParameters(row,samityAndBranchDistance);
            final String vendor = getVendor();

            Map<String, String> params = new HashMap<>();
            params.put("email", all[0]);
            params.put("lati", all[1]);
            params.put("longi", all[2]);
            params.put("near_sam_dis",all[3]);
            params.put("branch_dis",all[4]);
            params.put("loc_name",all[5]);
            params.put("vendor",vendor);
            return params;
        }

    };

    RequestQueue requestQueue;
    requestQueue = Volley.newRequestQueue(this);
    requestQueue.getCache().clear();
    requestQueue.add(stringRequest);

}

Upvotes: 0

Views: 228

Answers (1)

Gabe Sechan
Gabe Sechan

Reputation: 93668

Why are you creating new request queues? The request queue should be a per app singleton. If you're creating a new one each request like this you will have horrible performance and tons of unneeded threads lying around. That's likely your problem.

Upvotes: 3

Related Questions