Java OutOfMemoryError:无法分配JNI环境
我正在制作一个跟踪应用程序,跟踪公交车的位置。我想让它实时,所以我必须每秒调用api。如果我设定3秒的间隔,那么它可以正常工作,但更改为1秒会使应用程序崩溃。我还在清单中添加了Java OutOfMemoryError:无法分配JNI环境,java,android,multithreading,android-volley,handler,Java,Android,Multithreading,Android Volley,Handler,我正在制作一个跟踪应用程序,跟踪公交车的位置。我想让它实时,所以我必须每秒调用api。如果我设定3秒的间隔,那么它可以正常工作,但更改为1秒会使应用程序崩溃。我还在清单中添加了largeheap=true,但在这种情况下不起作用。我还为OutOfMemoryException添加了catch,但它仍然崩溃。我如何处理这个处理程序 请求 public void GetChildLocation(){ StringRequest stringRequest = new StringReque
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);
}
}
}
首先,在正常情况下,您不应该捕获任何
OutOfMemoryError
或任何Error
子类,请查看Error
,这很好地解释了这一点:
错误是Throwable的一个子类,它表示一个合理的应用程序不应该试图捕获的严重问题。大多数此类错误都是异常情况。ThreadDeath错误虽然是“正常”情况,但也是错误的一个子类,因为大多数应用程序不应该尝试捕捉它
至于您的请求代码,每次启动请求时,您似乎都在分配大量内容,尤其是Volley.newRequestQueue(getContext())代码>,您可以看看官方网站,了解如何重用volley的请求队列以及如何实现基本缓存
您可以更进一步,也可以重用StringRequest
本身,而无需每次创建新的值,同时重用getParams
和getHeader
的值,而无需每次分配新值
看起来可能是这样的,但同样,整个方法似乎并不正确,重新考虑应用程序的架构可能是个好主意
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);
}
}
classyourclass{
专用静态最终整数请求\延迟\毫秒=1000;
//假设您已经在某个地方初始化了这些
私有最终映射参数;
私有最终地图标题;
私人最终处理人;
私有最终请求队列;
私有最终StringRequest updateLocationRequest=
=新StringRequest(Request.Method.GET,“some url”,new Response.Listener()){
@凌驾
公共void onResponse(最终字符串响应){
//在这里处理你的结果
}
},new Response.ErrorListener(){
@凌驾
公共错误响应(最终截击错误){
//在这里处理错误
}
}) {
@凌驾
受保护的映射getParams()引发AuthFailureError{
返回参数;
}
@凌驾
公共映射getHeaders()引发AuthFailureError{
返回标题;
}
};
//实际上最好在这里提供RequestQueue或使用singleton,
//但为了举例说明,在这里这样做
公共YourClass(@NonNull final Context){
queue=Volley.newRequestQueue(上下文);
//你把各自的参数放在这里
headers=newhashmap();
params=新的HashMap();
}
public void getChildLocation(){
添加(updateLocationRequest);
postDelayed(getChildLocation(),REQUEST_DELAY_MS);
}
}
无论如何,真的有必要每秒钟(或每三秒)调用一次API来更新总线位置吗?我的意思是,总线在这三秒钟内会改变它的物理位置吗?首先,在正常情况下,你不应该捕捉到OutOfMemoryError
或任何Error
子类,看看Error
,这很好地解释了这一点:
错误是Throwable的一个子类,它表示一个合理的应用程序不应该试图捕获的严重问题。大多数此类错误都是异常情况。ThreadDeath错误虽然是“正常”情况,但也是错误的一个子类,因为大多数应用程序不应该尝试捕捉它
至于您的请求代码,每次启动请求时,您似乎都在分配大量内容,尤其是Volley.newRequestQueue(getContext())代码>,您可以看看官方网站,了解如何重用volley的请求队列以及如何实现基本缓存
您可以更进一步,也可以重用StringRequest
本身,而无需每次创建新的值,同时重用getParams
和getHeader
的值,而无需每次分配新值
看起来可能是这样的,但同样,整个方法似乎并不正确,重新考虑应用程序的架构可能是个好主意
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);
}
}
classyourclass{
专用静态最终整数请求\延迟\毫秒=1000;
//假设您已经在某个地方初始化了这些
私有最终映射参数;
私有最终地图标题;
私人最终处理人;
私有最终请求队列;
私有最终StringRequest updateLocationRequest=
=新StringRequest(Request.Method.GET,“some url”,new Response.Listener()){
@凌驾
公共void onResponse(最终字符串响应){
//在这里处理你的结果
}
},new Response.ErrorListener(){
@凌驾
公共错误响应(最终截击错误){
//在这里处理错误
}
}) {
@凌驾
受保护的映射getParams()引发AuthFailureError{
返回参数;
}
@凌驾
公共映射getHeaders()引发AuthFailureError{
返回标题;
}
};
//实际上最好在这里提供RequestQueue或使用singleton,
//但为了举例说明,在这里这样做
公共YourClass(@NonNull final Context){
queue=Volley.newRequestQueue(上下文);
//你把各自的参数放在这里
headers=newhashmap();
params=新的HashMap();
}
public void getChildLocation(){
添加(updateLocationRequest);
postDelayed(getChildLocation(),REQUEST_DELAY_MS);