OutOfMemoryError:无法分配JNI Env

时间:2018-11-14 05:38:29

标签: java android multithreading android-volley handler

我正在制作一个跟踪应用程序,可以跟踪公交车的位置。我想使其实时,所以我必须每秒调用一次api。如果我间隔3秒,则工作正常,但更改为1秒会使应用程序崩溃。我还在清单中添加了largeheap = true,但在这种情况下不起作用。我还为OutOfMemoryException添加了catch,但仍然崩溃。我该如何处理该处理程序?

请求

public void GetChildLocation(){
    StringRequest stringRequest = new StringRequest(Request.Method.POST, LAST_COORDINATE_URL, new Response.Listener<String>() {
        @Override
        public void onResponse(String response) {
            try {
                JSONObject jsonObject = new JSONObject(response);
                JSONArray jsonArray = jsonObject.getJSONArray("data");

                JSONObject location = jsonArray.getJSONObject(0);

                LatLng newLatLng = new LatLng(Double.parseDouble(location.getString("latitude")),Double.parseDouble(location.getString("longitude")));
                if (latlng != null) {
                    double PI = 3.14159;
                    //Source
                    double lat1 = latlng.latitude* PI / 180;
                    double lng1 = latlng.longitude* PI / 180;
                    // destination
                    double lat2 = newLatLng.latitude* PI / 180;
                    double lng2 = newLatLng.longitude* PI / 180;
                    double dLon = (lng2 - lng1);
                    double y = Math.sin(dLon) * Math.cos(lat2);
                    double x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLon);
                    double brng = Math.toDegrees((Math.atan2(y, x)));
                    brng = (brng + 360) % 360;

                    mMap.animateCamera(CameraUpdateFactory.newLatLng(newLatLng));
                    animateMarker(mCurrentLocationMarker, newLatLng, (float) brng, false);
                    latlng = newLatLng;
                }

            } catch (JSONException e) {
                e.printStackTrace();
            }

            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    GetChildLocation();
                }
            },1000);
        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {

        }
    }){
        @Override
        protected Map<String, String> getParams() throws AuthFailureError {
            Map<String,String> params = new HashMap<>();
            params.put("track_id",trackId);
            return params;
        }
        @Override
        public Map<String, String> getHeaders() throws AuthFailureError {
            Map<String,String> headers = super.getHeaders();
            if (headers == null || headers.equals(Collections.<String, String>emptyMap())){
                headers = new HashMap<String, String>();
            }
            MyApp.get().addSessionCookie(headers);
            return headers;
        }
    };
    if (getContext() != null) {
        try {
            RequestQueue queue = Volley.newRequestQueue(getContext());
            queue.add(stringRequest);
        }catch (OutOfMemoryError e){
            e.printStackTrace();
            RequestQueue queue1 = Volley.newRequestQueue(getContext());
            queue1.add(stringRequest);
        }
    }
}

错误

E/AndroidRuntime: FATAL EXCEPTION: main
Process: digimkey.example.digimkey_4.dmk_parent_app, PID: 21684
java.lang.OutOfMemoryError: Could not allocate JNI Env
    at java.lang.Thread.nativeCreate(Native Method)
    at java.lang.Thread.start(Thread.java:730)
    at com.android.volley.RequestQueue.start(RequestQueue.java:128)
    at com.android.volley.toolbox.Volley.newRequestQueue(Volley.java:91)
    at com.android.volley.toolbox.Volley.newRequestQueue(Volley.java:67)
    at com.android.volley.toolbox.Volley.newRequestQueue(Volley.java:102)
    at digimkey.example.digimkey_4.dmk_parent_app.TrackMap.GetChildLocation(TrackMap.java:571)
    at digimkey.example.digimkey_4.dmk_parent_app.TrackMap$4$1.run(TrackMap.java:539)
    at android.os.Handler.handleCallback(Handler.java:751)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:154)
    at android.app.ActivityThread.main(ActivityThread.java:6077)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)

1 个答案:

答案 0 :(得分:1)

首先,在正常情况下,您根本不应该捉住OutOfMemoryError或任何Error子类 ,看看Errorjavadoc解释得很好:

  

错误是Throwable的子类,它指示严重的问题,而合理的应用程序不应尝试抓住这些问题。大多数此类错误是异常情况。 ThreadDeath错误虽然是“正常”情况,但它也是Error的子类,因为大多数应用程序都不应尝试捕获它。

对于您的请求代码,每次请求被触发时,您似乎都在分配很多东西,尤其是Volley.newRequestQueue(getContext());,您可以看看官方的documentation,以了解如何重用volley的请求队列以及如何实现基本缓存。

您可以走得更远,也可以重用StringRequest本身,而不必每次都创建一个新值,同时重用getParamsgetHeader的值而不必每次都分配新值。 / p>

可能看起来像这样,但是同样,整个方法似乎并不正确,可能是重新考虑应用程序架构的一个好主意。

class YourClass {

    private static final int REQUEST_DELAY_MS = 1000;

    // Assuming you have initialize those somewhere
    private final Map params;
    private final Map headers;
    private final Handler handler;

    private final RequestQueue queue;

    private final StringRequest updateLocationRequest =  
        = new StringRequest(Request.Method.GET, "some url", new Response.Listener<String>() {
        @Override
        public void onResponse(final String response) {
            // handle your result here
        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(final VolleyError error) {
            // handle error here
        }
    }) {
        @Override
        protected Map<String, String> getParams() throws AuthFailureError {
            return params;
        }

        @Override
        public Map<String, String> getHeaders() throws AuthFailureError {
            return headers;
        }
    };

    // It's actually better to provide a RequestQueue here or use a singleton, 
    // but for sake of example doing it here
    public YourClass(@NonNull final Context context) {
        queue = Volley.newRequestQueue(context);

        // You put the respective params here
        headers = new HashMap<>();
        params = new HashMap<>();
    }

    public void getChildLocation() {
        queue.add(updateLocationRequest);

        handler.postDelayed(getChildLocation(), REQUEST_DELAY_MS);
    }
}

无论如何,是否真的需要每秒(或每三秒一次)调用API以更新公交车位置?我的意思是,这三秒钟内公交车会改变其实际位置吗?