Делаю приложение, одним из составляющих которого является список, получающий данные для отображения из базы данных. Элемент списка состоит из маленького изображения и текста. В бд хранится текст и uri для получения определенного изображения из папки drawable. При нажатии на элемент списка открывается активити, где, в том числе, показывается то самое определенное изображение. Также имеются ещё пару активити со списками и изображениями и текстовыми данными (всё берется из бд).
Проблема в следующем: по мере открытия новых активити, прокручивании списков, возврата к старым активити постоянно возрастает объём занимаемой приложением ОЗУ, и по достижении определенного момента приложение вылетает, выдавая OutOfMemoryError.
Пробовал получать Cursor через AsyncTask, но на данной ситуации это никак не отразилось. Судя по Java Heap происходит утечка памяти, но не совсем понимаю с чем она связана. Может кто знает как исправить? Заранее благодарю
Далее прилагаю код одного из активити со списком, логи и скрин Java Heap
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.support.v4.widget.SimpleCursorAdapter;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
public class MyActivity extends AppCompatActivity {
MyDBHelper myDBHelper;
SQLiteDatabase sqLiteDatabase;
Cursor cursor;
ListView listView;
SimpleCursorAdapter simpleCursorAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_of__vyzi_activity);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
listView = (ListView) findViewById(R.id.list_of_vyzi);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView parent, View view, int position, long id) {
Intent intent = new Intent(getApplicationContext(), UniversityMainActivity.class);
intent.putExtra("_id", id);
startActivity(intent);
}
});
// открываем подключение
myDBHelper = new MyDBHelper(getApplicationContext());
sqLiteDatabase = myDBHelper.open();
//получаем данные из бд в виде курсора
cursor = sqLiteDatabase.query(TablesNames.UNIVERSITIES,
new String[] {UniMainInfoConsts.ID,
UniMainInfoConsts.IMG_SRC, MyDBHelper.COLUMN_UNI,
MyDBHelper.COLUMN_BRI}, null, null,null,null,null);
// определяем, какие столбцы из курсора будут выводиться в ListView
cursor.moveToFirst();
String[] headers = new String[] {UniMainInfoConsts.IMG_SRC, MyDBHelper.COLUMN_UNI, MyDBHelper.COLUMN_BRI};
// создаем адаптер, передаем в него курсор
simpleCursorAdapter = new SimpleCursorAdapter(this, R.layout.layout_for_list,
cursor, headers, new int[]{R.id.imageView, R.id.main_text, R.id.sub_text}, 0);
listView.setAdapter(simpleCursorAdapter);
}
@Override
public void onDestroy(){
super.onDestroy();
// Закрываем подключение и курсор
sqLiteDatabase.close();
cursor.close();
myDBHelper.close();
Log.d("Destr", "List destr");
}
public void openAddComment (View v){
Intent intent = new Intent(this, Add_comment_activity.class);
startActivity(intent);
}
}
Java Heap
04-28 22:22:35.744 5511-5511/ru.abityrienty.vyzi I/Choreographer: Skipped 30 frames! The application may be doing too much work on its main thread.
04-28 22:22:37.365 5511-5511/ru.abityrienty.vyzi I/PersonaManager: getPersonaService() name persona_policy
04-28 22:22:37.445 5511-5511/ru.abityrienty.vyzi D/AbsListView: Get MotionRecognitionManager
04-28 22:22:38.877 5511-5511/ru.abityrienty.vyzi D/DESTROY: InstPage has destroyed
04-28 22:22:38.877 5511-5511/ru.abityrienty.vyzi D/AbsListView: onDetachedFromWindow
04-28 22:22:39.558 5511-5511/ru.abityrienty.vyzi D/AbsListView: Get MotionRecognitionManager
04-28 22:22:39.598 5511-5511/ru.abityrienty.vyzi I/PersonaManager: getPersonaService() name persona_policy
04-28 22:22:40.218 5511-5511/ru.abityrienty.vyzi D/DESTROY: InstPage has destroyed
04-28 22:22:40.228 5511-5511/ru.abityrienty.vyzi D/AbsListView: onDetachedFromWindow
04-28 22:22:41.249 5511-5511/ru.abityrienty.vyzi D/dalvikvm: GC_FOR_ALLOC freed 17393K, 23% free 60720K/78840K, paused 22ms, total 26ms
04-28 22:22:41.370 5511-5511/ru.abityrienty.vyzi D/dalvikvm: GC_FOR_ALLOC freed 7174K, 31% free 55185K/78840K, paused 20ms, total 20ms
04-28 22:22:41.530 5511-5511/ru.abityrienty.vyzi I/dalvikvm-heap: Grow heap (frag case) to 74.282MB for 18662416-byte allocation
freed 17393K, 23% free 60720K/78840K, paused 22ms, total 26ms
04-28 22:22:41.370 5511-5511/ru.abityrienty.vyzi D/dalvikvm: GC_FOR_ALLOC freed 7174K, 31% free 55185K/78840K, paused 20ms, total 20ms
04-28 22:22:41.530 5511-5511/ru.abityrienty.vyzi I/dalvikvm-heap: Grow heap (frag case) to 74.282MB for 18662416-byte allocation
04-28 22:22:42.791 5511-5511/ru.abityrienty.vyzi D/dalvikvm: GC_FOR_ALLOC freed 25168K, 23% free 61188K/78828K, paused 38ms, total 38ms
04-28 22:22:42.811 5511-5511/ru.abityrienty.vyzi I/dalvikvm-heap: Grow heap (frag case) to 69.961MB for 7985680-byte allocation
04-28 22:22:42.951 5511-5511/ru.abityrienty.vyzi D/dalvikvm: GC_FOR_ALLOC freed 3595K, 23% free 66797K/86628K, paused 19ms, total 19ms
04-28 22:22:44.683 5511-5511/ru.abityrienty.vyzi I/dalvikvm-heap: Forcing collection of SoftReferences for 18662416-byte allocation
04-28 22:22:44.723 5511-5511/ru.abityrienty.vyzi D/dalvikvm: GC_BEFORE_OOM freed 23183K, 26% free 54168K/73080K, paused 37ms, total 38ms
04-28 22:22:46.105 5511-5511/ru.abityrienty.vyzi D/AbsListView: Get MotionRecognitionManager
04-28 22:22:46.135 5511-5511/ru.abityrienty.vyzi I/PersonaManager: getPersonaService() name persona_policy
04-28 22:22:47.516 5511-5511/ru.abityrienty.vyzi D/DESTROY: InstPage has destroyed
04-28 22:22:47.516 5511-5511/ru.abityrienty.vyzi D/AbsListView: onDetachedFromWindow
04-28 22:22:48.597 5511-5511/ru.abityrienty.vyzi D/dalvikvm: GC_FOR_ALLOC freed 19896K, 9% free 66731K/73080K, paused 25ms, total 26ms
04-28 22:22:48.617 5511-5511/ru.abityrienty.vyzi I/dalvikvm-heap: Grow heap (frag case) to 75.380MB for 7985680-byte allocation
04-28 22:22:48.687 5511-5511/ru.abityrienty.vyzi D/dalvikvm: GC_FOR_ALLOC freed 1165K, 8% free 74770K/80880K, paused 19ms, total 19ms
04-28 22:22:49.518 5511-5511/ru.abityrienty.vyzi I/dalvikvm-heap: Forcing collection of SoftReferences for 18662416-byte allocation
04-28 22:22:49.548 5511-5511/ru.abityrienty.vyzi D/dalvikvm: GC_BEFORE_OOM freed 25070K, 32% free 59775K/87240K, paused 24ms, total 25ms
04-28 22:22:49.548 5511-5511/ru.abityrienty.vyzi E/dalvikvm-heap: Out of memory on a 18662416-byte allocation.
04-28 22:22:49.548 5511-5511/ru.abityrienty.vyzi I/dalvikvm: "main" prio=5 tid=1 RUNNABLE
04-28 22:22:49.548 5511-5511/ru.abityrienty.vyzi I/dalvikvm: | group="main" sCount=0 dsCount=0 obj=0x41855ea0 self=0x4174b050
04-28 22:22:49.548 5511-5511/ru.abityrienty.vyzi I/dalvikvm: | sysTid=5511 nice=0 sched=0/0 cgrp=apps handle=1073848660
04-28 22:22:49.548 5511-5511/ru.abityrienty.vyzi I/dalvikvm: | state=R schedstat=( 0 0 0 ) utm=532 stm=230 core=0
04-28 22:22:49.548 5511-5511/ru.abityrienty.vyzi I/dalvikvm: at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
04-28 22:22:49.548 5511-5511/ru.abityrienty.vyzi I/dalvikvm: at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:693)
04-28 22:22:49.548 5511-5511/ru.abityrienty.vyzi I/dalvikvm: at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:518)
04-28 22:22:49.548 5511-5511/ru.abityrienty.vyzi I/dalvikvm: at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:889)
04-28 22:22:49.548 5511-5511/ru.abityrienty.vyzi I/dalvikvm: at android.content.res.Resources.loadDrawable(Resources.java:3457)
04-28 22:22:49.548 5511-5511/ru.abityrienty.vyzi I/dalvikvm: at android.content.res.Resources.getDrawable(Resources.java:1921)
04-28 22:22:49.558 5511-5511/ru.abityrienty.vyzi I/dalvikvm: at android.widget.ImageView.resolveUri(ImageView.java:666)
04-28 22:22:49.558 5511-5511/ru.abityrienty.vyzi I/dalvikvm: at android.widget.ImageView.setImageURI(ImageView.java:409)
04-28 22:22:49.558 5511-5511/ru.abityrienty.vyzi I/dalvikvm: at android.support.v4.widget.SimpleCursorAdapter.setViewImage(SimpleCursorAdapter.java:201)
04-28 22:22:49.558 5511-5511/ru.abityrienty.vyzi I/dalvikvm: at android.support.v4.widget.SimpleCursorAdapter.bindView(SimpleCursorAdapter.java:147)
04-28 22:22:49.558 5511-5511/ru.abityrienty.vyzi I/dalvikvm: at android.support.v4.widget.CursorAdapter.getView(CursorAdapter.java:273)
04-28 22:22:49.558 5511-5511/ru.abityrienty.vyzi I/dalvikvm: at android.widget.AbsListView.obtainView(AbsListView.java:2713)
04-28 22:22:49.558 5511-5511/ru.abityrienty.vyzi I/dalvikvm: at android.widget.ListView.makeAndAddView(ListView.java:1811)
04-28 22:22:49.558 5511-5511/ru.abityrienty.vyzi I/dalvikvm: at android.widget.ListView.fillDown(ListView.java:697)
04-28 22:22:49.558 5511-5511/ru.abityrienty.vyzi I/dalvikvm: at android.widget.ListView.fillGap(ListView.java:661)
04-28 22:22:49.558 5511-5511/ru.abityrienty.vyzi I/dalvikvm: at android.widget.AbsListView.trackMotionScroll(AbsListView.java:6693)
04-28 22:22:49.558 5511-5511/ru.abityrienty.vyzi I/dalvikvm: at android.widget.AbsListView$FlingRunnable.run(AbsListView.java:5692)
04-28 22:22:49.568 5511-5511/ru.abityrienty.vyzi I/dalvikvm: at android.view.Choreographer$CallbackRecord.run(Choreographer.java:813)
04-28 22:22:49.568 5511-5511/ru.abityrienty.vyzi I/dalvikvm: at android.view.Choreographer.doCallbacks(Choreographer.java:613)
04-28 22:22:49.568 5511-5511/ru.abityrienty.vyzi I/dalvikvm: at android.view.Choreographer.doFrame(Choreographer.java:582)
04-28 22:22:49.568 5511-5511/ru.abityrienty.vyzi I/dalvikvm: at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:799)
04-28 22:22:49.568 5511-5511/ru.abityrienty.vyzi I/dalvikvm: at android.os.Handler.handleCallback(Handler.java:733)
04-28 22:22:49.568 5511-5511/ru.abityrienty.vyzi I/dalvikvm: at android.os.Handler.dispatchMessage(Handler.java:95)
04-28 22:22:49.568 5511-5511/ru.abityrienty.vyzi I/dalvikvm: at android.os.Looper.loop(Looper.java:146)
04-28 22:22:49.568 5511-5511/ru.abityrienty.vyzi I/dalvikvm: at android.app.ActivityThread.main(ActivityThread.java:5593)
04-28 22:22:49.568 5511-5511/ru.abityrienty.vyzi I/dalvikvm: at java.lang.reflect.Method.invokeNative(Native Method)
04-28 22:22:49.568 5511-5511/ru.abityrienty.vyzi I/dalvikvm: at java.lang.reflect.Method.invoke(Method.java:515)
04-28 22:22:49.568 5511-5511/ru.abityrienty.vyzi I/dalvikvm: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
04-28 22:22:49.568 5511-5511/ru.abityrienty.vyzi I/dalvikvm: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
04-28 22:22:49.568 5511-5511/ru.abityrienty.vyzi I/dalvikvm: at dalvik.system.NativeStart.main(Native Method)
04-28 22:22:49.568 5511-5511/ru.abityrienty.vyzi D/skia: --- allocation failed for scaled bitmap
04-28 22:22:49.568 5511-5511/ru.abityrienty.vyzi D/AndroidRuntime: Shutting down VM
04-28 22:22:49.568 5511-5511/ru.abityrienty.vyzi W/dalvikvm: threadid=1: thread exiting with uncaught exception (group=0x41854da0)
04-28 22:22:49.578 5511-5511/ru.abityrienty.vyzi E/AndroidRuntime: FATAL EXCEPTION: main
Process: ru.abityrienty.vyzi, PID: 5511
java.lang.OutOfMemoryError
at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:693)
at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:518)
at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:889)
at android.content.res.Resources.loadDrawable(Resources.java:3457)
at android.content.res.Resources.getDrawable(Resources.java:1921)
at android.widget.ImageView.resolveUri(ImageView.java:666)
at android.widget.ImageView.setImageURI(ImageView.java:409)
at android.support.v4.widget.SimpleCursorAdapter.setViewImage(SimpleCursorAdapter.java:201)
at android.support.v4.widget.SimpleCursorAdapter.bindView(SimpleCursorAdapter.java:147)
at android.support.v4.widget.CursorAdapter.getView(CursorAdapter.java:273)
at android.widget.AbsListView.obtainView(AbsListView.java:2713)
at android.widget.ListView.makeAndAddView(ListView.java:1811)
at android.widget.ListView.fillDown(ListView.java:697)
at android.widget.ListView.fillGap(ListView.java:661)
at android.widget.AbsListView.trackMotionScroll(AbsListView.java:6693)
at android.widget.AbsListView$FlingRunnable.run(AbsListView.java:5692)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:813)
at android.view.Choreographer.doCallbacks(Choreographer.java:613)
at android.view.Choreographer.doFrame(Choreographer.java:582)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:799)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:146)
at android.app.ActivityThread.main(ActivityThread.java:5593)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
at dalvik.system.NativeStart.main(Native Method)
Натыкался вот на такое, но не совсем понял как воплотить в жизнь:
The real solution involves:
Ensuring that you have profiled your app's allocations and are not leaking memory
Ensuring that you have profiled your app's allocations and are not
leaking memory
You are not holding references to Bitmaps via a hidden or
non-displayed Fragment, View, etc.. in such a way that they can not be collected and released
You are using a Bitmap cache (i.e. LruCache) to manage how many
Bitmaps are been held in memory at any give time
That the Bitmaps that are actually being held in memory are sized
appropriately for the device's resolution, i.e.:
Resizing content on the device on the fly and file caching the
results
Dynamically via the web service that you are requesting them from
Переделанный адаптер для получения BLOB
import android.content.Context;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.support.v4.widget.SimpleCursorAdapter;
import android.widget.ImageView;
public class ListOfVyziAdapter extends SimpleCursorAdapter {
/**
* It's important to place column where you store images on the first place
* of the @from array
*/
Context ctx;
// String [] columns = {0="img_src",1="for main_text", 2="for sub_text"}
String [] columns;
public ListOfVyziAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags) {
super(context, layout, c, from, to, flags);
ctx = context;
columns = from;
}
@Override
public void setViewImage(ImageView v, String value) {
v.setImageDrawable(imageForList(getCursor()));
}
private Drawable imageForList(Cursor cur){
byte [] blob = cur.getBlob(cur.getColumnIndex(columns[0]));
Bitmap bitmap = BitmapFactory.decodeByteArray(blob, 0, blob.length);
return new BitmapDrawable(Resources.getSystem(), bitmap);
}
}
Ответ
Для того чтоб бороться с OOM вначале вам необходимо создать такую возможность.
Определите свой адаптер, иначе вам очень сложно(невозможно) контролировать процесс биндинга(bind) Blob из Sql в ImageView, а так у вас появится возможность контролировать размер изображения, применить компрессию, сделать кеширование, и самое главное учесть возможность выделения памяти для разных устройств. Для простоты можно использовать готовые решения, которые уже зарекомендовали себя например Glide там будет проще сделать, в Picasso не поддерживается load для byte[] или Bitmap, только Drawable и Url.
Комментариев нет:
Отправить комментарий