java - 内存不足错误: Could not allocate JNI Env

标签 java android multithreading android-volley handler

我正在制作一个跟踪应用程序,用于跟踪公交车位置。我想让它实时,所以我必须每秒调用 api。如果我设置 3 秒的间隔,那么它工作正常,但更改为 1 秒会使应用程序崩溃。我还在 list 中添加了 Largeheap = true ,但在这种情况下不起作用。我还添加了 OutOfMemoryException 的捕获,但它仍然崩溃。我该如何处理这个处理程序?

请求

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)

最佳答案

首先,在正常情况下,您根本不应该捕获 OutOfMemoryError 或任何 Error 子类,看一下在错误javadoc这很好地解释了它:

An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch. Most such errors are abnormal conditions. The ThreadDeath error, though a "normal" condition, is also a subclass of Error because most applications should not try to catch it.

至于你的请求代码,看起来你每次触发请求时都会分配很多东西,特别是Volley.newRequestQueue(getContext());,你可以看一下在官方documentation了解如何重用volley的请求队列以及如何实现基本的缓存。

您可以更进一步,重用 StringRequest 本身,而无需每次都创建一个新的,同时重用 getParamsgetHeader 的值> 无需每次都分配新的。

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

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 来更新公交车位置吗?我的意思是,公共(public)汽车在这三秒钟内是否改变了它的物理位置很多?

关于java - 内存不足错误: Could not allocate JNI Env,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53293805/

相关文章:

java - 使用notifyDataSetChanged()帮助刷新列表

java - Cordova 上的 Android Lollipop 通知图标 setColor

multithreading - 一个套接字连接多个命名空间

java - 运行处理程序时出现问题?

java - 图的连通度

java - 在哪里可以找到 Netbeans RCP maven 项目中的主要 layer.xml 文件?

java - 读取 firebase DB 后如何更改 ListView 上的颜色和字体

java - 当 View 在 ListView 中变为回收时,如何知道何时取消异步任务

android - 显示 windows-1250 字符集 html 的 android webview 出现问题

c - 效率核心是否支持与性能核心相同的指令?