重复齐射调用会导致Android App Memory泄漏

时间:2019-04-25 01:14:17

标签: java android memory-leaks android-volley

我已经看过几乎所有关于凌空和泄漏,处理程序和泄漏,弱引用的堆栈溢出线程,并且几乎陷入了精神瘫痪。我一直在努力将文章中的技术翻译成我的代码。

我本质上是在尝试使用android volley get请求来“ ping”本地片段中的本地服务器,以查看其是否存在。如果是,则加载页面,如果不是,则加载空白页面,并保持“等待连接”微调器向上。

我的问题是,反复打排球会导致大量泄漏。我希望对解决这些问题具有实际经验的人能有所帮助。我确实要求答案在我发布的代码的上下文中。如果这些文章对我来说有意义,我就不会在这里发布。

这里只是我读过的几篇著名文章,但我可能在博客和堆栈溢出中读了100多篇,试图理解这个问题。

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

如果不调用isOnline(),我可以摆脱泄漏,但是很明显,程序不再满足我的需要,所以我知道泄漏与凌空或处理程序有关。 / p>

公共类DeviceFragment扩展了片段{

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

}

更新: 我已经实现了对处理程序和可运行程序的弱引用,而这些似乎并没有改善。

公共类DeviceFragment扩展了片段{

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

}

0 个答案:

没有答案