0

I've looked at just about every stack overflow thread on volley & leaks, handlers & leaks, weak references and have just about become mentally paralyzed. My struggle has been translating the techniques in the articles to my code.

I'm essentially trying to "ping" a local server within a fragment in an android app to see if it is there or not using a basic volley get request. If it is, I load the page and if it isn't, I load a blank page and keep the "waiting for connection" spinner up.

My issue is that I'm getting significant leaks with the repeated calls to volley. I'm hoping someone with some real world experience fighting these issues could help. I do request that the answers be in the context of my posted code. If the articles were making sense to me, I wouldn't be posting here.

Here are just a few notable articles I've read, but there are probably 100 more that I've gone through in blogs and stack overflow trying to understand the issue.

Activity leak while using volley listeners

https://www.smashingmagazine.com/2017/03/simplify-android-networking-volley-http-library/

http://blog.nimbledroid.com/2016/09/06/stop-memory-leaks.html

I can get rid of the leak if I don't call isOnline(), but obviously the program no longer does what I need it to, so I know the leak has something to do with either volley or the handler.

public class DeviceFragment extends Fragment {

Handler handler;
boolean online;
boolean online_prev;
WebView webView;
private static final String TAG = "DeviceFragment";
ProgressBar spinner;
TextView spinnertext;
int toastCount;
boolean onlineBoolean;
boolean isDestroyed;
RequestQueue queue;     

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

    View view = inflater.inflate(R.layout.fragment_device, container, false);

    queue = Volley.newRequestQueue(getActivity());  // moved to help with leaks

    spinner = view.findViewById(R.id.progressBar1);
    spinnertext = view.findViewById(R.id.progressBar1text);

    online = false;
    online_prev = false;
    toastCount = 1;
    handler = new Handler();
    isDestroyed = false;

    spinner.setVisibility(View.VISIBLE);
    spinnertext.setVisibility(View.VISIBLE);

    webView = view.findViewById(R.id.webview);

    webView.getSettings().setJavaScriptEnabled(true);
    webView.setWebViewClient(new myWebClient() {
        @Override
        public void onReceivedError(WebView view, int errorCode,
                                    String description, String failingUrl) {

            view.loadUrl("about:blank");
            Toast.makeText(getActivity().getApplicationContext(), "Waiting For Connection", Toast.LENGTH_LONG).show();
        }

    });

    // New method to get to WiFi settings menu
    Button wifisettings = view.findViewById(R.id.WiFiSettings);
    wifisettings.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            startActivity(new Intent(android.provider.Settings.ACTION_WIFI_SETTINGS));
        }
    });

    Button connect = view.findViewById(R.id.connect);

    connect.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            webView.loadUrl("http://10.123.40.2");

        }
    });

    handler.postDelayed(runnableCode, 1000);

    return view;
}

@Override
public void onResume() {
    super.onResume();

        getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}

@Override
public void onPause() {
    super.onPause();

        getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}

private Runnable runnableCode = new Runnable() {
    @Override
    public void run() {

        online = onlineBoolean;
        if(isDestroyed == false){
            isOnline();
        }

        if (online == true && online_prev == false) {
            webView.loadUrl("http://10.123.40.2");
            spinner.setVisibility(View.GONE);
            spinnertext.setVisibility(View.GONE);
            toastCount = 0;

        } else if (online == true && online_prev == true) {
            // do nothing
        } else if (online == false && online_prev == true) {
            // do nothing
        } else {
            webView.loadUrl("about:blank");
            spinner.setVisibility(View.VISIBLE);
            spinnertext.setVisibility(View.VISIBLE);
            if (toastCount == 0) {
                Toast.makeText(getActivity().getApplicationContext(), "Wi-Fi Connection Lost - Please Check Wi-Fi Settings", Toast.LENGTH_LONG).show();
                toastCount = 1;
            }
        }

        online_prev = online;

        //handler = new Handler();  // leaks?  
        handler.removeCallbacksAndMessages(null);  //  Not sure if this helps with leaks?
       handler.postDelayed(this, 5000);
    }
};


public class myWebClient extends WebViewClient {

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        view.loadUrl(url);
        return true;
    }

}

public void isOnline() {

    //RequestQueue queue = Volley.newRequestQueue(getActivity());  // Causes huge leak.  Move to public

    String url = "http://10.123.40.2";

    StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
            new Response.Listener<String>() {
                @Override
                public void onResponse(String response) {
                    onlineBoolean = true;
                }
            }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            onlineBoolean = false;
        }
    });

    queue.add(stringRequest);
}


public void onDestroy () {
    handler.removeCallbacks(runnableCode);
    isDestroyed = true;
    super.onDestroy ();
}

}

UPDATE: I've implemented weak referenced for the handler and runnable and these didn't seem to improve things.

public class DeviceFragment extends Fragment {

private final NimbleHandler nimblehander = new NimbleHandler(this);

private static class NimbleHandler extends Handler{

    private WeakReference<DeviceFragment> weakReference;
    public NimbleHandler(DeviceFragment activity) {
        weakReference = new WeakReference<>(activity);
    }

    @Override public void handleMessage(Message message){
        super.handleMessage(message);
    }

}

private static class NimbleRunnable implements Runnable {

    private WeakReference<DeviceFragment> weakReference;
    public NimbleRunnable(DeviceFragment activity) {
        weakReference = new WeakReference<>(activity);
    }

    @Override public void run(){
        while(true);
    }
}

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

    View view = inflater.inflate(R.layout.fragment_device, container, false);

    queue = Volley.newRequestQueue(getActivity());

    spinner = view.findViewById(R.id.progressBar1);
    spinnertext = view.findViewById(R.id.progressBar1text);

    online = false;
    online_prev = false;
    toastCount = 1;

    isDestroyed = false;

    spinner.setVisibility(View.VISIBLE);
    spinnertext.setVisibility(View.VISIBLE);

    webView = view.findViewById(R.id.webview);

    webView.getSettings().setJavaScriptEnabled(true);
    webView.setWebViewClient(new myWebClient() {
        @Override
        public void onReceivedError(WebView view, int errorCode,
                                    String description, String failingUrl) {

            view.loadUrl("about:blank");
            Toast.makeText(getActivity().getApplicationContext(), "Waiting For Connection", Toast.LENGTH_LONG).show();
        }

    });

    nimblehander.post(runnableCode);

    return view;
}


private final Runnable runnableCode = new NimbleRunnable(this) {
    @Override
    public void run() {

        online = onlineBoolean;
        if(isDestroyed == false){
            isOnline();
        }

        // omitted rest of code to keep short

        nimblehander.postDelayed(this, 5000);
    }
};

}

A P
  • 171
  • 1
  • 7
  • Make your question quickly readable for others. – Athira Apr 25 '19 at 03:48
  • @Athira I tried to shorten the question up. I also added some changes per some of the articles on weak references, however they didn't improve things. – A P Apr 25 '19 at 11:22

0 Answers0