我正在制作一个跟踪应用程序,可以跟踪公交车的位置。我想使其实时,所以我必须每秒调用一次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)
答案 0 :(得分:1)
首先,在正常情况下,您根本不应该捉住OutOfMemoryError
或任何Error
子类 ,看看Error
的javadoc解释得很好:
错误是Throwable的子类,它指示严重的问题,而合理的应用程序不应尝试抓住这些问题。大多数此类错误是异常情况。 ThreadDeath错误虽然是“正常”情况,但它也是Error的子类,因为大多数应用程序都不应尝试捕获它。
对于您的请求代码,每次请求被触发时,您似乎都在分配很多东西,尤其是Volley.newRequestQueue(getContext());
,您可以看看官方的documentation,以了解如何重用volley的请求队列以及如何实现基本缓存。
您可以走得更远,也可以重用StringRequest
本身,而不必每次都创建一个新值,同时重用getParams
和getHeader
的值而不必每次都分配新值。 / 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以更新公交车位置?我的意思是,这三秒钟内公交车会改变其实际位置吗?