重启Android应用程序偶尔会抛出java.lang.IllegalStateException

时间:2017-03-06 22:47:51

标签: android sqlite

当我通过Android工作室重新启动应用程序时,偶尔会出现此异常,我发现解决问题的唯一方法是清除应用程序中存储的数据。

STACK_TRACE=java.lang.RuntimeException: Unable to start activity ComponentInfo{com.camhart.netcountable/com.camhart.netcountable.activities.setup.DeviceTypeActivity}: java.lang.IllegalStateException: Couldn't read row 0, col 0 from CursorWindow.  Make sure the Cursor is initialized correctly before accessing data from it.
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3254)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3350)
at android.app.ActivityThread.access$1100(ActivityThread.java:222)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1795)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:7229)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
Caused by: java.lang.IllegalStateException: Couldn't read row 0, col 0 from CursorWindow.  Make sure the Cursor is initialized correctly before accessing data from it.
at android.database.CursorWindow.nativeGetLong(Native Method)
at android.database.CursorWindow.getLong(CursorWindow.java:524)
at android.database.AbstractWindowedCursor.getLong(AbstractWindowedCursor.java:75)
at com.camhart.netcountable.sqlite.dataaccess.SettingDataAccess.getSettings(SettingDataAccess.java:91)
at com.camhart.netcountable.sqlite.businesslogic.SettingBusinessLogic.getSettingsFromDatabase(SettingBusinessLogic.java:61)
at com.camhart.netcountable.sqlite.businesslogic.SettingBusinessLogic.getSetting(SettingBusinessLogic.java:54)
at com.camhart.netcountable.activities.setup.DeviceTypeActivity.onCreate(DeviceTypeActivity.java:43)
at android.app.Activity.performCreate(Activity.java:6876)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1135)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3207)
... 9 more
java.lang.IllegalStateException: Couldn't read row 0, col 0 from CursorWindow.  Make sure the Cursor is initialized correctly before accessing data from it.
at android.database.CursorWindow.nativeGetLong(Native Method)
at android.database.CursorWindow.getLong(CursorWindow.java:524)
at android.database.AbstractWindowedCursor.getLong(AbstractWindowedCursor.java:75)
at com.camhart.netcountable.sqlite.dataaccess.SettingDataAccess.getSettings(SettingDataAccess.java:91)
at com.camhart.netcountable.sqlite.businesslogic.SettingBusinessLogic.getSettingsFromDatabase(SettingBusinessLogic.java:61)
at com.camhart.netcountable.sqlite.businesslogic.SettingBusinessLogic.getSetting(SettingBusinessLogic.java:54)
at com.camhart.netcountable.activities.setup.DeviceTypeActivity.onCreate(DeviceTypeActivity.java:43)
at android.app.Activity.performCreate(Activity.java:6876)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1135)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3207)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3350)
at android.app.ActivityThread.access$1100(ActivityThread.java:222)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1795)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:7229)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)

我认为这是因为应用程序在我的sqlite数据库的事务中被杀死。

  1. 我的假设是否正确?
  2. 有没有办法阻止这种情况发生?
  3. 如果我的应用程序在前台运行服务并且为了更新应用程序而被杀死可能会发生这种情况吗?
  4. 编辑:

    package com.camhart.netcountable.sqlite.dataaccess;
    
    import android.content.ContentValues;
    import android.content.Context;
    import android.database.Cursor;
    
    import com.camhart.netcountable.sqlite.models.Setting;
    import com.camhart.netcountable.sqlite.tabledata.SettingTableData;
    
    import net.openid.appauth.AuthState;
    
    import org.json.JSONException;
    
    public class SettingDataAccess extends DataAccess {
    
        \\...
    
        private static String[] columnsToGrab = new String[]{
                SettingTableData._ID,
                SettingTableData.COLUMN_NAME_USERNAME,
                SettingTableData.COLUMN_NAME_ACCOUNTID,
                SettingTableData.COLUMN_NAME_IDENTITYID,
                SettingTableData.COLUMN_NAME_WIFIONLY,
                SettingTableData.COLUMN_NAME_EMAIL,
                SettingTableData.COLUMN_NAME_ADMINDEVICE,
                SettingTableData.COLUMN_NAME_PREMIUM,
                SettingTableData.COLUMN_NAME_PUBLICKEY,
                SettingTableData.COLUMN_NAME_TAKENAPSHOTS,
                SettingTableData.COLUMN_NAME_AUTHSTATEJSON
        };
    
        public Setting getSettings() {
            Setting setting = new Setting();
    
            Cursor c = db.query(SettingTableData.TABLE_NAME,
                    columnsToGrab,
                    null,
                    new String[]{},
                    null,
                    null,
                    null,
                    null);
    
            if(c.moveToFirst()) {
                setting.setId(c.getLong(c.getColumnIndex(SettingTableData._ID)));   //#line 91
                setting.setAccountId(c.getString(c.getColumnIndex(SettingTableData.COLUMN_NAME_ACCOUNTID)));
                setting.setIdentityId(c.getString(c.getColumnIndex(SettingTableData.COLUMN_NAME_IDENTITYID)));
                setting.setDisplayName(c.getString(c.getColumnIndex(SettingTableData.COLUMN_NAME_USERNAME)));
                setting.setWifiOnlyUpload(c.getInt(c.getColumnIndex(SettingTableData.COLUMN_NAME_WIFIONLY)) == 1);
                setting.setEmail(c.getString(c.getColumnIndex(SettingTableData.COLUMN_NAME_EMAIL)));
    
                setting.setAdminDevice(c.getInt(c.getColumnIndex(SettingTableData.COLUMN_NAME_ADMINDEVICE)) == 1);
                setting.setPremium(c.getInt(c.getColumnIndex(SettingTableData.COLUMN_NAME_PREMIUM)) == 1);
                setting.setPublicKey(c.getString(c.getColumnIndex(SettingTableData.COLUMN_NAME_PUBLICKEY)));
                setting.setTakeSnapshots(c.getInt(c.getColumnIndex(SettingTableData.COLUMN_NAME_TAKENAPSHOTS)) == 1);
                String jsonAuthState = c.getString(c.getColumnIndex(SettingTableData.COLUMN_NAME_AUTHSTATEJSON));
    
                if(jsonAuthState != null) {
                    try {
                        setting.setAuthState(AuthState.jsonDeserialize(jsonAuthState));
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
                c.close();
    
                return setting;
            }
            c.close();
    
            return null;
        }
    }
    

    SettingDataAccess.java

    public class SettingTableData implements BaseColumns {
        public static final String TABLE_NAME = "settings";
        public static final String COLUMN_NAME_WIFIONLY = "wifiOnlyUpload";
        public static final String COLUMN_NAME_USERNAME = "username";
        public static final String COLUMN_NAME_ACCOUNTID = "accountId";
        public static final String COLUMN_NAME_IDENTITYID = "identityId";
        public static final String COLUMN_NAME_EMAIL = "email";
        public static final String COLUMN_NAME_PREMIUM = "premium";
        public static final String COLUMN_NAME_LASTREFRESH = "lastRefresh";
    //    public static final String COLUMN_NAME_PRIVATEKEY = "privateKey";
        public static final String COLUMN_NAME_ADMINDEVICE = "admin";
        public static final String COLUMN_NAME_PUBLICKEY = "publicKey";
        public static final String COLUMN_NAME_TAKENAPSHOTS = "takeSnapshots";
        public static final String COLUMN_NAME_AUTHSTATEJSON = "jsonAuthState";
    }
    

    SettingTableData.java

    public class Setting {
    
        private boolean wifiOnlyUpload;
        private String displayName;
        private String accountId;
        private String identityId;
        private long id;
        private String email;
        private boolean premium;
        private boolean adminDevice;
        private String publicKey;
        private boolean takeSnapshots;
        private AuthState authState;
    
        public String getIdentityId() {
            return identityId;
        }
    
        public void setIdentityId(String identityId) {
            this.identityId = identityId;
        }
    
        public String getAccountId() {
            return accountId;
        }
    
        public void setAccountId(String accountId) {
            this.accountId = accountId;
        }
    
        public boolean isWifiOnlyUpload() {
            return wifiOnlyUpload;
        }
    
        public void setWifiOnlyUpload(boolean wifiOnlyUpload) {
            this.wifiOnlyUpload = wifiOnlyUpload;
        }
    
        public String getDisplayName() {
            return displayName;
        }
    
        public void setDisplayName(String username) {
            this.displayName = username;
        }
    
        public long getId() {
            return id;
        }
    
        public void setId(long id) {
            this.id = id;
        }
    
        public void setEmail(String email) {
            this.email = email;
        }
    
        public String getEmail() {
            return email;
        }
    
        public boolean isPremium() {
            return premium;
        }
    
        public void setPremium(boolean premium) {
            this.premium = premium;
        }
    
        public boolean isAdminDevice() {
            return adminDevice;
        }
    
        public void setAdminDevice(boolean adminDevice) {
            this.adminDevice = adminDevice;
        }
    
        public void setPublicKey(String publicToken) {
            this.publicKey = publicToken;
        }
    
        public String getPublicKey() {
            return this.publicKey;
        }
    
        public boolean takesSnapshots() {
            //TODO: Make it so admins can take screenies too (for couples)
            return isTakeSnapshots() && isPremium();
        }
    
        public void setTakeSnapshots(boolean takeSnapshots) {
            this.takeSnapshots = takeSnapshots;
        }
    
        public boolean isTakeSnapshots() {
            return takeSnapshots;
        }
    
        public AuthState getAuthState() {
            return authState;
        }
    
        public void setAuthState(AuthState jsonAuthState) {
            this.authState = jsonAuthState;
        }
    
        //TODO:  update this to save the device type, then just have this check for isOwnerDevice instead of
        // having to check the auth state too.
        public boolean isOwner() {
            return getAuthState() != null && isAdminDevice();
        }
    
        public String getReversedIdentityId() {
            return new StringBuilder(getIdentityId()).reverse().toString();
        }
    }
    

    Setting.java

    public class DataAccess {
        protected SQLiteDatabase db;
        private static DbHelper dbHandler;
    
        protected static synchronized DbHelper getDbHelper(Context context) {
            if(dbHandler == null) {
                dbHandler = new DbHelper(context);
            }
            return dbHandler;
        }
    
        public DataAccess(Context context) {
            if(dbHandler == null) {
                dbHandler = getDbHelper(context);
            }
        }
    
        public void open() throws SQLException {
            db = dbHandler.getWritableDatabase();
        }
    
        public void close() {
            db.close();
            db = null;
        }
    }
    

    DataAccess.java

    <style label="disable_continue" arg:timeout="3" mode="after" name="survey.respview.footer" with="q1, q2" wrap="ready">
      <![CDATA[ var b=$ ("#btn_continue, #btn_finish");
      b.disable();
      setTimeout(function() {
        b.enable();
        postIt();
      }
      
      , $(timeout)*1000);
      ]]>
    </style>

1 个答案:

答案 0 :(得分:0)

看起来正在发生的事情是我的身份验证状态json字符串比我预期的要长得多。我把它移到了SharedPreference位置,一段时间后,每当我尝试加载OOM时,我都会开始获取OOM。我想这可能是在Sqlite中发生的事情。