Как избежать OutOfMemory при попытке вызвать мой сервер и анализировать данные каждый раз, когда я перехожу на карту
У меня есть MyMapActivity с закрытым классом, расширяющим AsyncTask с целью выполнения запроса на сервере каждый раз, когда изменяется раздел карты (метод onMove()). Ответ от сервера - строка данных JSON, которая может быть около 1-3 МБ. Поэтому мне нужно избегать многократных обращений к серверу, когда пользователь перемещает карту, чтобы избежать OutOfMemory. По этой причине я пытаюсь проверить, отменяется ли мой собственный AsyncTask (при каждом запуске onMove()), и если нет (полагаю, это указывает на выполнение метода doInBackground()), я пытаюсь отменить его. Но независимо от этого у меня все еще есть
01-19 20:45:05.660: ОШИБКА /MapActivity(2482): не удалось получить клиент фабрики соединений 01-19 20:45:40.600: ОШИБКА / Модем (96): активный iface (usb0) сообщается как добавленный, игнорируя 01-19 20:47:15.260: ОШИБКА /dalvikvm-heap(2482): Недостаточно памяти при выделении 11908 байт. 01-19 20: 47: 15.270: ОШИБКА /dalvikvm(2482): Недостаточно памяти: Размер кучи =24519 КБ, Выделено =23091 КБ, Размер растрового изображения =101 КБ 01-19 20: 47: 15.410: ОШИБКА /dalvikvm-heap(2482): Недостаточно памяти на 7690-байтовом выделении. 01-19 20: 47: 15.420: ОШИБКА /dalvikvm(2482): Недостаточно памяти: Размер кучи =24519 КБ, Выделено =23088 КБ, Размер растрового изображения =101 КБ 01-19 20: 47: 15.570: ОШИБКА /dalvikvm-heap(2482): Недостаточно памяти при выделении 7656 байт. 01-19 20: 47: 15.590: ОШИБКА /dalvikvm(2482): Недостаточно памяти: Размер кучи =24519 КБ, Выделено =23090 КБ, Размер растрового изображения =101 КБ 01-19 20:47:15.730: ОШИБКА /dalvikvm-heap(2482): Недостаточно памяти при выделении 9098 байт. 01-19 20: 47: 15.740: ОШИБКА /dalvikvm(2482): Недостаточно памяти: Размер кучи =24519 КБ, Выделено =23097 КБ, Размер растрового изображения =101 КБ 01-19 20: 48: 01.850: ОШИБКА /dalvikvm-heap(2482): Недостаточно памяти при выделении 8176 байт. 01-19 20: 48: 01.850: ОШИБКА /dalvikvm(2482): Недостаточно памяти: Размер кучи =24519 КБ, Выделено =22767 КБ, Размер растрового изображения =101 КБ 01-19 20: 48: 01.970: ОШИБКА /dalvikvm-heap(2482): Недостаточно памяти при выделении 12022 байта. 01-19 20: 48: 01.980: ОШИБКА /dalvikvm(2482): Недостаточно памяти: Размер кучи =24519 КБ, Выделено =22768 КБ, Размер растрового изображения =101 КБ 01-19 20: 48: 02.110: ОШИБКА /dalvikvm-heap(2482): Недостаточно памяти при выделении 8936 байт. 01-19 20: 48: 02.119: ОШИБКА /dalvikvm(2482): Недостаточно памяти: Размер кучи =24519 КБ, Выделено =22769 КБ, Размер растрового изображения =101 КБ 01-19 20:48:07.220: WARN/dalvikvm(2482): threadid=20: выход из потока с необработанным исключением (группа =0x400259f8) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): ИСКЛЮЧИТЕЛЬНОЕ ИСКЛЮЧЕНИЕ: AsyncTask #9 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): java.lang.RuntimeException: произошла ошибка при выполнении doInBackground() 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): на android.os.AsyncTask$3.done(AsyncTask.java:200) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): на java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): на java.util.concurrent.FutureTask.setException(FutureTask.java:124) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): на java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): на java.util.concurrent.FutureTask.run(FutureTask.java:137) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): по адресу java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): в java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): на java.lang.Thread.run(Thread.java:1102) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): вызвано: java.lang.OutOfMemoryError 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): на java.lang.String.(String.java:468) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): на java.lang.AbstractStringBuilder.toString(AbstractStringBuilder.java:659) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): на java.lang.StringBuilder.toString(StringBuilder.java:664) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): на com.google.gson.stream.JsonReader.nextString(JsonReader.java:995) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): на com.google.gson.stream.JsonReader.nextValue(JsonReader.java:810) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): на com.google.gson.stream.JsonReader.objectValue(JsonReader.java:790) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): на com.google.gson.stream.JsonReader.quickPeek(JsonReader.java:385) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): на com.google.gson.stream.JsonReader.peek(JsonReader.java:348) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): на com.google.gson.internal.bind.TypeAdapters$12.read(TypeAdapters.java:322) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): на com.google.gson.internal.bind.TypeAdapters$12.read(TypeAdapters.java:334) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): на com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:86) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): в com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:170) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): в com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:38) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): на com.google.gson.internal.bind.ArrayTypeAdapter.read(ArrayTypeAdapter.java:71) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): на com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:86) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): в com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:170) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): на com.google.gson.Gson.fromJson(Gson.java:720) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): на com.google.gson.Gson.fromJson(Gson.java:660) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): по адресу net.amagumo.realestate.MyMapActivity$MyTask.getHttpContent(MyMapActivity.java:444) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): в net.amagumo.realestate.MyMapActivity$MyTask.doInBackground(MyMapActivity.java:393) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): at net.amagumo.realestate.MyMapActivity$MyTask.doInBackground(MyMapActivity.java:1) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): на android.os.AsyncTask$2.call(AsyncTask.java:185) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): на java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) 01-19 20:48:07.350: ОШИБКА /AndroidRuntime(2482): ... еще 4 01-19 20:48:07.450: WARN/ActivityManager(96): принудительное завершение деятельности net.amagumo.realestate/.MyMapActivity 01-19 20:48:21.290: WARN/TimeThread(294): ошибка преобразования времени 01-19 20:48:42.899: WARN/TimeThread(294): ошибка преобразования времени
Вот мой класс деятельности:
public class MyMapActivity extends MapActivity implements LocationListener, OnTouchListener, OnMoveListener, MyMapItemClickedListener, DefaultActivity { MyMapView mv; MapController mc; LocationManager lm; MyItemizedOverlay myOverlay; DatabaseAdapter db; AdvertResult advertResult; String callerActivityString; MyTask mytask; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d(Constants.DEBUG_TAG, "MAP - create"); setContentView(R.layout.map); db = new DatabaseAdapter(getApplicationContext()).open(); mv = (MyMapView)this.findViewById(R.id.mapView); mc = mv.getController(); lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE); mv.setOnTouchListener(this); mv.setmOnMoveListener(this); mv.setSatellite(true); Drawable marker=getResources().getDrawable(R.drawable.ic_maps_indicator_startpoint_list); int markerWidth = marker.getIntrinsicWidth(); int markerHeight = marker.getIntrinsicHeight(); marker.setBounds(0, markerHeight, markerWidth, 0); myOverlay = new MyItemizedOverlay(marker); myOverlay.setMyMapItemClickedListener(this); mv.getOverlays().add(myOverlay); advertResult = new AdvertResult(); mytask = new MyTask(); } public void completeMap(){ Log.d(Constants.DEBUG_TAG_MAPS, "completing map - START"); for(AdvertSimple is : advertResult.getAdvertSimpleList()){ if(is.getAdress().getLat()!=null && is.getAdress().getLon()!=null){ GeoPoint gp = new GeoPoint(is.getAdress().getLat(), is.getAdress().getLon()); myOverlay.addItem(gp, "Advert", "snippet"); } } Log.d(Constants.DEBUG_TAG_MAPS, "completing map - END"); } @Override protected boolean isRouteDisplayed() { return false; } public void onLocationChanged(Location loc) { } public void onProviderDisabled(String provider) { } public void onProviderEnabled(String provider) { } public void onStatusChanged(String provider, int status, Bundle extras) { } public boolean onTouch(View v, MotionEvent event) { return false; } public void onMove(MapView mapView, GeoPoint center, boolean stopped) { if(!mytask.isCancelled()){ Log.d(Constants.DEBUG_TAG_MAPS, "async task is cancelling - ATTEMPT"); mytask.cancel(true); System.gc(); } if(stopped){ Log.d(Constants.DEBUG_TAG_MAPS, "finished move/zoom action"); Integer latspan = mv.getLatitudeSpan(); Integer lonspan = mv.getLongitudeSpan(); Integer maxlat = center.getLatitudeE6() + (latspan/2); Integer maxlon = center.getLongitudeE6() + (lonspan/2); Integer minlat = center.getLatitudeE6() - (latspan/2); Integer minlon = center.getLongitudeE6() - (lonspan/2); mytask = new MyTask(); mytask.execute(this, null, new ResultComposite()); } } public MapRectangle getRectangle(){ GeoPoint center = mv.getMapCenter(); Integer latspan = mv.getLatitudeSpan(); Integer lonspan = mv.getLongitudeSpan(); Integer maxlat = center.getLatitudeE6() + (latspan/2); Integer maxlon = center.getLongitudeE6() + (lonspan/2); Integer minlat = center.getLatitudeE6() - (latspan/2); Integer minlon = center.getLongitudeE6() - (lonspan/2); return new MapRectangle(maxlat, maxlon, minlat, minlon); } @Override public void completeAction(ResultComposite result) { Log.d(Constants.DEBUG_TAG_MAPS, "async tasc is going to complete in caller activity - OK"); if(result!=null){ advertResult.setAdvertSimpleList(result.getAdvertSimpleList()); completeMap(); } } @Override public RequestParams getRequestParams() { RequestParams params = new RequestParams(); params.setDb(db); params.setRectangle(getRectangle()); return params; } private class MyTask extends AsyncTask{ public MyMapActivity ma; public HttpClient httpclient; @Override protected ResultComposite doInBackground(Object... params) { Log.d(Constants.DEBUG_TAG_MAPS, "async tasc do in backgrounf - START"); ma = (MyMapActivity) params[0]; ResultComposite rc = new ResultComposite(); RequestParams rp = ma.getRequestParams(); MapRectangle rectangle = rp.getRectangle(); RequestJSONObject ro = new RequestJSONObject(rectangle.getMinlat(), rectangle.getMinlon(), rectangle.getMaxlat(), rectangle.getMaxlon()); Gson gson = new Gson(); String json = gson.toJson(ro); ResponseJSONObject responseJSONObject = getHttpContent(json, Constants.HTTP_REQUEST_MAP); AdvertSimpleJSON[] AdvertSimpleJSONarray = responseJSONObject.getAdvertySimple(); List simples = DataHelper.convertAdvertSimpleJSONArray2AdvertSimpleList(rp.getDb(), AdvertSimpleJSONarray); rc.setAdvertSimpleList(simples); return rc; } @Override protected void onPostExecute(ResultComposite result) { super.onPostExecute(result); Log.d(Constants.DEBUG_TAG_MAPS, "async tasc is going to complete in caller activity - ATTEMPT"); ma.completeAction(result); } @Override protected void onCancelled() { super.onCancelled(); Log.d(Constants.DEBUG_TAG_MAPS, "async task is cancelling - OK"); } private ResponseJSONObject getHttpContent(String json, String requestType){ ResponseJSONObject responseJSONObject = null; HttpPost post = new HttpPost(Constants.SERVER_MAP_URL); try { Log.d(Constants.DEBUG_TAG_MAPS, "try"); HttpEntity entity = new StringEntity(json); post.setEntity(entity); HttpParams httpParameters = new BasicHttpParams(); HttpConnectionParams.setConnectionTimeout(httpParameters, 15000); HttpConnectionParams.setSoTimeout(httpParameters, 150000); httpclient = new DefaultHttpClient(httpParameters); BasicHttpResponse response = (BasicHttpResponse ) httpclient.execute(post); if(response.getStatusLine().getStatusCode() == 200){ Log.d(Constants.DEBUG_TAG, "response 200"); HttpEntity responseEntity = response.getEntity(); Gson g = new Gson(); BufferedReader reader = new BufferedReader ( new InputStreamReader ( responseEntity.getContent()) ); responseJSONObject = g.fromJson(reader, ResponseJSONObject.class); reader.close(); System.gc(); } } catch (Exception e) { e.printStackTrace(); } Log.d(Constants.DEBUG_TAG_MAPS, "returning http results"); return responseJSONObject; } } }
Что еще я должен сделать? Я пытался выполнить потреблять http сущности.
Правильна ли моя логика работы с AsynTask?