Страница 1 из 1

Кешировать или не кешировать?OutOfMemory

Добавлено: 31 янв 2014, 13:45
Артем Дегтев
Такая ситуация: есть БД, в ней хранятся текстовые данные и картинке в поле БЛОБ.
Есть список, в который выгружается база, потом при прокрутке, когда конец списка, в БД загружается еще 20 записей и они выводятся в список.
Но, если это повторить раз 20, то ошибка OutOfMemory.
Вопрос: ошибка из-за большого размера БД или из-за того, что на экране отображается много картинок?

Если из второго, то их наверное надо кешировать. Есть две функции для кеширования, поместить по ключу и достать по ключу. Как реализовать кеширование для изображение которые не отображаются на экране из списка, а когда фокус на них, дотавать их из Кеша.
Если кто то знает, помогите, очень нужно.

Re: Кешировать или не кешировать?OutOfMemory

Добавлено: 31 янв 2014, 14:16
rezak90
Артем Дегтев писал(а):Вопрос: ошибка из-за большого размера БД или из-за того, что на экране отображается много картинок?
Не то ни другое (во втором вполне уверен, на счёт первого может кто то поправит). Наверное где то не закрываешь потоки, проследи за памятью.
P.S. никогда не понимал зачем в андроиде хранить картинки в бд.

Re: Кешировать или не кешировать?OutOfMemory

Добавлено: 31 янв 2014, 14:27
Foenix
про список не знаю, макс размер базы данных - около 2 гб.
Вот еще список ограничений, кому нужно
http://www.sqlite.org/limits.html

Re: Кешировать или не кешировать?OutOfMemory

Добавлено: 31 янв 2014, 14:44
anber
http://www.youtube.com/watch?v=_CruQY55HOk

Upd. для кеша можно использовать LruCache

Upd2. покажи метод getView в адаптере ListView

Re: Кешировать или не кешировать?OutOfMemory

Добавлено: 31 янв 2014, 15:13
Артем Дегтев
anber писал(а):http://www.youtube.com/watch?v=_CruQY55HOk

Upd. для кеша можно использовать LruCache

Upd2. покажи метод getView в адаптере ListView
Именно так и думал кешировать, с помощью LruCache. Но пишут что не нужно.
Вот метод:

Код: Выделить всё

 public View getView(final int position, View convertView, ViewGroup parent) {
  ViewHolder holder = new ViewHolder();
  SearchResultItem rowItem = getItem(position);
  
  if(convertView == null){
   LayoutInflater mInflater = (LayoutInflater) context
     .getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
   convertView = mInflater.inflate(R.layout.news, null);
   new ViewHolder();
   holder.SmallImageNews = (ImageView) convertView
     .findViewById(R.id.NewsImg);
   holder.NameNews = (TextView) convertView
     .findViewById(R.id.NameNews);
   holder.updateDate = (TextView) convertView
     .findViewById(R.id.updateDate);
;
      
   convertView.setTag(holder);
  } else
   holder = (ViewHolder) convertView.getTag();
  
        holder.NameNews.setText(rowItem.getName());
        holder.updateDate.setText(rowItem.getUpdateDate()t);
        holder.SmallImageNews.setImageDrawable(rowItem.getSmallImageNews());
   
        holder = null;

        return convertView;
 }

Re: Кешировать или не кешировать?OutOfMemory

Добавлено: 31 янв 2014, 15:14
Артем Дегтев
rezak90 писал(а):
Артем Дегтев писал(а):Вопрос: ошибка из-за большого размера БД или из-за того, что на экране отображается много картинок?
Не то ни другое (во втором вполне уверен, на счёт первого может кто то поправит). Наверное где то не закрываешь потоки, проследи за памятью.
P.S. никогда не понимал зачем в андроиде хранить картинки в бд.
Картинки храню в базе для того, что бы когда пользователь запустил приложение без доступа к интернету, картинки новостей, миниатюры, отображались на экране.

Re: Кешировать или не кешировать?OutOfMemory

Добавлено: 31 янв 2014, 15:19
Артем Дегтев
rezak90 писал(а):
Артем Дегтев писал(а):Вопрос: ошибка из-за большого размера БД или из-за того, что на экране отображается много картинок?
Не то ни другое (во втором вполне уверен, на счёт первого может кто то поправит). Наверное где то не закрываешь потоки, проследи за памятью.
P.S. никогда не понимал зачем в андроиде хранить картинки в бд.
В смысле последить за памятью? Как это сделать?

Re: Кешировать или не кешировать?OutOfMemory

Добавлено: 31 янв 2014, 15:30
anber
Артем Дегтев писал(а):
rezak90 писал(а):
Артем Дегтев писал(а):Вопрос: ошибка из-за большого размера БД или из-за того, что на экране отображается много картинок?
Не то ни другое (во втором вполне уверен, на счёт первого может кто то поправит). Наверное где то не закрываешь потоки, проследи за памятью.
P.S. никогда не понимал зачем в андроиде хранить картинки в бд.
В смысле последить за памятью? Как это сделать?
я ссылку кидал на видео - http://www.youtube.com/watch?v=_CruQY55HOk

UPD. У меня было приложение где картинки хранились в БД, размер которой приблизительно 200Мб, и отображались в ListView, и приложение не падало с OOME, так что проблема где-то в логике.

Re: Кешировать или не кешировать?OutOfMemory

Добавлено: 31 янв 2014, 15:42
anber
Собственно если влом разбираться с MAT можно заюзать следующий метод:

Код: Выделить всё

  public static void memoryUsegeLog(Context context, String tag) {
    logToFile("MyMemoryInfo", "=============================begin=============================");
    logToFile("MyMemoryInfo", "ActivityName: " + context.getClass().getSimpleName());
    logToFile("MyMemoryInfo", "TAG: " + tag);
    Runtime rt = Runtime.getRuntime();
    long maxMemory = rt.maxMemory();
    logToFile("MyMemoryInfo", "maxMemory:" + Long.toString(maxMemory / 1024) + "K");


    long freeMemory = rt.freeMemory();
    long totalMemory = rt.totalMemory();
    logToFile("MyMemoryInfo", "freeMemory:" + Long.toString(freeMemory / 1024) + "K");
    logToFile("MyMemoryInfo", "totalMemory:" + Long.toString((totalMemory) / 1024) + "K");
    logToFile("MyMemoryInfo", "usedMemory:" + Long.toString((totalMemory - freeMemory) / 1024) + "K");
    double frePers = (double) freeMemory / totalMemory * 100;
    logToFile("MyMemoryInfo", "freeMemoryPersent:" + Double.toString(frePers));

    logToFile("MyMemoryInfo", "NativeHeapAllocatedSize:" + Long.toString(Debug.getNativeHeapAllocatedSize() / 1024) + "K");
    logToFile("MyMemoryInfo", "NativeHeapFreeSize:" + Long.toString(Debug.getNativeHeapFreeSize() / 1024) + "K");
    logToFile("MyMemoryInfo", "NativeHeapSize:" + Long.toString(Debug.getNativeHeapSize() / 1024) + "K");

    ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    int memoryClass = am.getMemoryClass();
    logToFile("MyMemoryInfo", "memoryClass:" + Integer.toString(memoryClass));

    ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
    am.getMemoryInfo(memoryInfo);
    logToFile("MyMemoryInfo", "availMem " + Long.toString(memoryInfo.availMem / 1024) + "K");
    logToFile("MyMemoryInfo", "lowMemory " + memoryInfo.lowMemory);
    logToFile("MyMemoryInfo", "threshold " + Long.toString(memoryInfo.threshold / 1024) + "K");

    logToFile("MyMemoryInfo", "==============================end==============================");
  }

  public static void logToFile(String tag, final String stringToFile) {
    File myFile = new File("/sdcard/mylog.txt");
    try {
      myFile.createNewFile();
      FileOutputStream fOut = new FileOutputStream(myFile, true);
      OutputStreamWriter myOutWriter = new OutputStreamWriter(fOut);
      myOutWriter.append(stringToFile);
      myOutWriter.append("\r\n");
      myOutWriter.close();
      fOut.close();
    } catch (IOException e) {
      Log.e("MyMemoryInfo", e.toString());
    }
    Log.i(tag, stringToFile);
  }
В принципе удобно если приложение падает у клиента с OOME неизвестно почему - пишет в файл на сд карту, и в лог с тегом "MyMemoryInfo", потом у клиента можно просто попросить файлик mylog.txt.
Как использовать - напихать во всех подозрительных местах вызовы типа:
memoryUsegeLog(context, "begin getView method");
...
memoryUsegeLog(context, "end getView method");

и таким нехитрым способом найти место на котором тратится память.

Re: Кешировать или не кешировать?OutOfMemory

Добавлено: 31 янв 2014, 17:53
Артем Дегтев
anber писал(а):Собственно если влом разбираться с MAT можно заюзать следующий метод:

Код: Выделить всё

  public static void memoryUsegeLog(Context context, String tag) {
    logToFile("MyMemoryInfo", "=============================begin=============================");
    logToFile("MyMemoryInfo", "ActivityName: " + context.getClass().getSimpleName());
    logToFile("MyMemoryInfo", "TAG: " + tag);
    Runtime rt = Runtime.getRuntime();
    long maxMemory = rt.maxMemory();
    logToFile("MyMemoryInfo", "maxMemory:" + Long.toString(maxMemory / 1024) + "K");


    long freeMemory = rt.freeMemory();
    long totalMemory = rt.totalMemory();
    logToFile("MyMemoryInfo", "freeMemory:" + Long.toString(freeMemory / 1024) + "K");
    logToFile("MyMemoryInfo", "totalMemory:" + Long.toString((totalMemory) / 1024) + "K");
    logToFile("MyMemoryInfo", "usedMemory:" + Long.toString((totalMemory - freeMemory) / 1024) + "K");
    double frePers = (double) freeMemory / totalMemory * 100;
    logToFile("MyMemoryInfo", "freeMemoryPersent:" + Double.toString(frePers));

    logToFile("MyMemoryInfo", "NativeHeapAllocatedSize:" + Long.toString(Debug.getNativeHeapAllocatedSize() / 1024) + "K");
    logToFile("MyMemoryInfo", "NativeHeapFreeSize:" + Long.toString(Debug.getNativeHeapFreeSize() / 1024) + "K");
    logToFile("MyMemoryInfo", "NativeHeapSize:" + Long.toString(Debug.getNativeHeapSize() / 1024) + "K");

    ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    int memoryClass = am.getMemoryClass();
    logToFile("MyMemoryInfo", "memoryClass:" + Integer.toString(memoryClass));

    ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
    am.getMemoryInfo(memoryInfo);
    logToFile("MyMemoryInfo", "availMem " + Long.toString(memoryInfo.availMem / 1024) + "K");
    logToFile("MyMemoryInfo", "lowMemory " + memoryInfo.lowMemory);
    logToFile("MyMemoryInfo", "threshold " + Long.toString(memoryInfo.threshold / 1024) + "K");

    logToFile("MyMemoryInfo", "==============================end==============================");
  }

  public static void logToFile(String tag, final String stringToFile) {
    File myFile = new File("/sdcard/mylog.txt");
    try {
      myFile.createNewFile();
      FileOutputStream fOut = new FileOutputStream(myFile, true);
      OutputStreamWriter myOutWriter = new OutputStreamWriter(fOut);
      myOutWriter.append(stringToFile);
      myOutWriter.append("\r\n");
      myOutWriter.close();
      fOut.close();
    } catch (IOException e) {
      Log.e("MyMemoryInfo", e.toString());
    }
    Log.i(tag, stringToFile);
  }
В принципе удобно если приложение падает у клиента с OOME неизвестно почему - пишет в файл на сд карту, и в лог с тегом "MyMemoryInfo", потом у клиента можно просто попросить файлик mylog.txt.
Как использовать - напихать во всех подозрительных местах вызовы типа:
memoryUsegeLog(context, "begin getView method");
...
memoryUsegeLog(context, "end getView method");

и таким нехитрым способом найти место на котором тратится память.
Спасибо, нашел ошибку. Теперь пытаюсь решить.