Android приложение виснет при работе с SQLite

167
19 февраля 2018, 02:40

Все отлично работает, если не выполнять никаких операций с базой. Только я начинаю читать из базы что-то, сразу происходит нечто странное: приложение виснет с этой ошибкой, переставая реагировать на что-либо:

    406 E: FATAL EXCEPTION: main
    Process: com.alexchurkin.myapp, PID: 30146
    java.lang.OutOfMemoryError: Failed to allocate a 36920412 byte allocation with 4178160 free bytes and 5MB until OOM
        at java.util.Arrays.copyOf(Arrays.java:3231)
        at java.util.Arrays.copyOf(Arrays.java:3204)
        at java.util.ArrayList.grow(ArrayList.java:249)
        at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:223)
        at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:215)
        at java.util.ArrayList.add(ArrayList.java:441)
        at com.alexchurkin.myapp.time.bells.BellsHelper.getBellsList(BellsHelper.java:43)
        at com.alexchurkin.myapp.time.bells.ActivityBells.onCreate(ActivityBells.java:46)
        at android.app.Activity.performCreate(Activity.java:6679)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2618)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)
        at android.app.ActivityThread.-wrap12(ActivityThread.java)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6119)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)

Вот класс Helper для работы с БД:

    import android.database.Cursor;
    import android.database.sqlite.SQLiteDatabase;
    import android.database.sqlite.SQLiteStatement;
    import com.alexchurkin.myapp.DBHelper;
    import java.util.ArrayList;
    import static com.alexchurkin.myapp.DBHelper.KEY_END;
    import static com.alexchurkin.myapp.DBHelper.KEY_START;
    import static com.alexchurkin.myapp.DBHelper.TABLE_BELLS;
    class BellsHelper {
        private BellsView view;
        private DBHelper dbHelper;
        private SQLiteDatabase database;
        BellsHelper(BellsView view){
            this.view = view;
            this.dbHelper = new DBHelper(view.getViewContext());
            this.database = dbHelper.getWritableDatabase();
        }
        void insertBellsList(ArrayList<Bell> bellsList){
            for(Bell bell: bellsList){
                String command = "INSERT INTO " + TABLE_BELLS + "(" + KEY_START + ", " + KEY_END + ")" + "VALUES(?, ?);";
                database.beginTransaction();
                try{
                    SQLiteStatement statement = database.compileStatement(command);
                    statement.clearBindings();
                    statement.bindLong(1,  bell.getStartMillis());
                    statement.bindLong(2,  bell.getEndMillis());
                    statement.execute();
                    database.setTransactionSuccessful();
                }
                finally{
                    database.endTransaction();
                }
            }
        }
        ArrayList<Bell> getBellsList(){
            ArrayList<Bell> bellsList = new ArrayList<>();
            Cursor cursor = database.query(TABLE_BELLS, null, null, null, null, null, null);
            if(cursor.moveToFirst()){
                while(!cursor.isAfterLast()){
                    long startMillis = cursor.getLong(cursor.getColumnIndex(KEY_START));
                    long endMillis = cursor.getLong(cursor.getColumnIndex(KEY_END));
                    bellsList.add(new Bell(startMillis, endMillis));
                }
            }
            cursor.close();
            return bellsList;
        }
        void close(){
            database.close();
            dbHelper.close();
            view = null;
        }
    }

Класс Bell:

class Bell {

private long startMillis;
private long endMillis;
private String startString;
private String endString;

Bell(long startMillis, long endMillis){
    this.startMillis = startMillis;
    this.endMillis = endMillis;
    startString = Dates.hoursAndMinutesString(startMillis);
    endString = Dates.hoursAndMinutesString(endMillis);
}
void setStartMillis(long startMillis) {
    this.startMillis = startMillis;
    startString = Dates.hoursAndMinutesString(startMillis);
}
long getStartMillis() {
    return startMillis;
}
String getStartString() {
    return startString;
}
void setEndMillis(long endMillis) {
    this.endMillis = endMillis;
    endString = Dates.hoursAndMinutesString(endMillis);
}
long getEndMillis() {
    return endMillis;
}
String getEndString() {
    return endString;
}
}
Answer 1

Дело в том что метод isAfterLast() не переводит курсор на следующую позицию, поэтому получается бесконечный цикл и как следствие OutOfMemory.

Используйте более простую и краткую конструкцию при получении списка данных из курсора

Cursor cursor = ...
while(cursor.moveToNext()) {
}
cursor.close();
READ ALSO
Консольное загрузочное приложение на java

Консольное загрузочное приложение на java

Создать консольное приложение для загрузки файловПрограмма должна скачивать файлы по HTTP протоколу

214
Многопоточность в Spring MVC

Многопоточность в Spring MVC

Как создать параллельный поток в приложении реализованном на Spring MVCЧтобы при загрузке сервера создавался новый поток, который например бы каждую...

230
Table &ldquo;table_name&rdquo; cannot be resolved

Table “table_name” cannot be resolved

Создаю базу данных магазина, использую jpa hibernateЕсть 4 класса-сущности:

269