【问题标题】:SQliteOpenHelper Database indexoutofbounds when called from fragment's OnResume从片段的 OnResume 调用 SQliteOpenHelper 数据库 indexoutofbounds
【发布时间】:2020-01-29 03:21:26
【问题描述】:

我的 SQliteDatabase/OpenHelper/AssetHelper 存在一个难以修复的问题,因为我无法复制我的许多应用程序用户在我的设备或任何 android studio 模拟设备上遇到的错误,所以我要编写这段代码向你展示对我有用,但不是其他一些,我不知道为什么。

当我的应用从数据库(资产文件夹中)填充的 List 中获取值时,我的用户有时会收到 indexoutofboundsexception(我相信)。所以看起来数据库没有正确加载。问题可能与我在 Fragment 的 OnResume 生命周期回调中获取 DatabaseAccess 类 DBProgressAccess 的实例时传递的上下文有关。

我没有尝试太多来解决这个问题,只是因为崩溃很少发生(在我的 android 6.0 手机上只有一次),但我从 google 收到关于其他 android 设备频繁崩溃的报告(最多并包括安卓 6.0)。 我对崩溃的堆栈跟踪来自谷歌开发者控制台。

我有一个在应用启动时加载的片段。在从 onResume() 调用的 showSets12() 方法中(我看到 indexoutofbounds 错误),我访问了一个用户得分数据库:

    private void showSets12()
    {
        DBProgressAccess dbProgressAccess = DBProgressAccess.getInstance(getActivity());
        dbProgressAccess.openUserProgressDb();
        dbProgressAccess.getDayValues();
        int scoreToday = dbProgressAccess.getScores().get(0); <--I think the error comes from this
        ...
        dbProgressAccess.closeUserProgressDb();

    }

在我拥有的公共 DBProgressAccess 类中:

public class DBProgressAccess {

    private SQLiteOpenHelper openHelper;
    private SQLiteDatabase database;
    private static DBProgressAccess instance;

    private List<String> dates;
    private List<Integer> scores;
    private List<String> times;

    public static final String TABLE_NAME = "UserProgress";

    public List<Integer> getScores() {return scores;}


    private DBProgressAccess(Context context) {
        this.openHelper = new DBProgressHandler(context);
    }

    public static DBProgressAccess getInstance(Context context)
    {
        Log.d(TAG, "getInstance");
        if(instance == null) {
            instance = new DBProgressAccess(context);
        }
        return instance;
    }


    /**
     * Open the database connection.
     */
    public void openUserProgressDb() {
        Log.d(TAG, "openUserProgress");
        this.database = openHelper.getWritableDatabase();
    }


    /**
     * Is todays date included in the database? If not, create it and search the database to populate lists for times and scores
     */
    public void getDayValues()
    {
        if (checkIfDateExists()) {
            Cursor cursor = searchDayProgress();
            searchDatabase(cursor);
        }
        else
        {
            createDayEntry();
            Cursor cursor = searchDayProgress();
            searchDatabase(cursor);
        }
    }

    /**
     * Check to see if there is a record in the database for today 
     */
    public boolean checkIfDateExists()
    {
        Cursor cursor = searchDayProgress();
        if(cursor.getCount() <= 0)
        {
            cursor.close();
            return false;
        }
        cursor.close();
        return true;
    }


    /**
     * Insert todays date into the database
     */
    private void createDayEntry()
    {
        Date today = Calendar.getInstance().getTime();
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        String todayString = formatter.format(today);
        int score = 0;
        String time = "0:00:0";

        ContentValues cv = new ContentValues();
        cv.put("date", todayString);
        cv.put("score", score);
        cv.put("time", time);

        database.insert(TABLE_NAME, null, cv);
    }


    /**
     * Find the database record for today
     */
    private Cursor searchDayProgress() {
        String whereQuery = "SELECT * FROM UserProgress WHERE date = date('now')";
        Log.d(TAG, "searchWeekProgress " + whereQuery);
        return database.rawQuery(whereQuery, null);
    }

    /**
     * Populate lists of time, date and progress taken from the database
     */
    public void searchDatabase(Cursor cursor)
    {
        List<String> listDate = new ArrayList<>();
        List<Integer> listUserProgress = new ArrayList<>();
        List<String> listTime = new ArrayList<>();

        cursor.moveToFirst();
        while (!cursor.isAfterLast()) {
            listDate.add(cursor.getString(cursor.getColumnIndex("date")));
            listUserProgress.add(cursor.getInt(cursor.getColumnIndex("score")));
            listTime.add(cursor.getString(cursor.getColumnIndex("time")));
            cursor.moveToNext();
        }
        cursor.close();

        setDates(listDate);
        setScores(listUserProgress);
        setTimes(listTime);
    }

    private void setDates(List<String> dates) {this.dates = dates;}
    private void setScores(List<Integer> scores) {this.scores = scores;}
    private void setTimes(List<String> times) {this.times = times;}

}


我相信 List&lt;string&gt; 变量是空的。

我希望我可以输入更具体的代码,但谷歌开发控制台堆栈跟踪不清楚。

我得到的错误来自谷歌开发者控制台,而不是 android studio,因为我无法在我的设备或任何模拟设备上复制该问题。

java.lang.RuntimeException: 
  at android.app.ActivityThread.performResumeActivity (ActivityThread.java:3573)
   at android.app.ActivityThread.handleResumeActivity (ActivityThread.java:3613)
   at android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:2862)
   at android.app.ActivityThread.-wrap12 (ActivityThread.java)
   at android.app.ActivityThread$H.handleMessage (ActivityThread.java:1574)
   at android.os.Handler.dispatchMessage (Handler.java:110)
   at android.os.Looper.loop (Looper.java:203)
   at android.app.ActivityThread.main (ActivityThread.java:6364)
   at java.lang.reflect.Method.invoke (Method.java)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:1076)
   at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:937)

Caused by: java.lang.IndexOutOfBoundsException: 
  at java.util.ArrayList.get (ArrayList.java:411)
  at org.ieltstutors.academicwordlist.AcademicWordListFragment.showSets12 (AcademicWordListFragment.java)
  at org.ieltstutors.academicwordlist.AcademicWordListFragment.access$000 (AcademicWordListFragment.java)
  or                     .access$200 (AcademicWordListFragment.java)
  or                     .drawCircularLockedProgress (AcademicWordListFragment.java)
  or                     .onCreateView (AcademicWordListFragment.java)
  or                     .openCloseSet (AcademicWordListFragment.java)
  or                     .showCircularScores (AcademicWordListFragment.java)
  or                     .showScores (AcademicWordListFragment.java)
  or                     .updateScores (AcademicWordListFragment.java)
  at org.ieltstutors.academicwordlist.AcademicWordListFragment.onResume (AcademicWordListFragment.java)

不幸的是,这就是我所掌握的关于错误的所有信息。

所以 IndexOutOfBoundsException 来自 showSets12。 错误可能是因为对getInstance 使用了错误的上下文吗?或者可能来自getWriteableDatabase? 为什么有时可以正确访问数据库,但有时不能正确访问数据库?我记得当应用程序启动时,当应用程序在我的手机上崩溃时,我立即尝试在我朋友的手机上打开该应用程序,但它也崩溃了,以前从未崩溃过。巧合?

非常感谢任何帮助。谢谢!

【问题讨论】:

  • 看起来getScores() 正在返回一个空列表。准备好让您的查询不匹配任何行。
  • 感谢您的留言@laalto。如果当前日期在数据库中尚不存在,则查询应始终找到某些内容,因为为当前日期添加了一条记录。这适用于我的手机和我尝试过的所有模拟器(有许多 android 版本),所以我想知道为什么我的一些用户会发生崩溃。

标签: android database sqlite indexoutofboundsexception


【解决方案1】:

只有在调用Activity onResume() 或onPause() 时才会调用片段onResume() 或onPause()。它们与 Activity 紧密耦合。如果您想在片段添加到活动时做某事,您可以使用 OnAttach() 或其他片段生命周期

阅读本文以了解片段Lifecycle

【讨论】:

  • 您好,Arsalan。感谢您的输入。这些是我的确切想法,所以我测试了一个版本,其中上下文 getActivity() 在 OnAttach() 期间存储在一个变量中。某些用户仍然报告崩溃。我还没有尝试从 OnAttach() 调用 showSets12()。问题是我必须等待 2 天,然后谷歌控制台才开始向我提供更新代码的崩溃报告。
  • 我应该补充一点,该方法被正确调用,但我相信数据库没有(偶尔)按应有的方式加载。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-11
  • 2018-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多