title: Initial data in android database
body: <p>I have an application with database and content provider. I was following tutorials but despite that, I get errors and cannot get rid of them. Especially when I try to add initial (demo) data to the database. Here are the errors that I get and the code that I use.</p>
  
  <p><strong>Errors</strong></p>
  
  <ul>
  <li><p>When I install the app (without demo data), I get the following info:</p>
  
  <blockquote>
    <p>Skipped 96 frames!  The application may be doing too much work on its main thread.
    At least, the application runs.</p>
  </blockquote></li>
  <li><p>Whenever I try to add demo data, the app shows the same info at the beginning. When I come to the screen with the list of items read from the database, it crashes. Here is the log:</p>
  
  <pre><code>06-25 12:08:54.358: E/AndroidRuntime(4971): FATAL EXCEPTION: main
  06-25 12:08:54.358: E/AndroidRuntime(4971): java.lang.RuntimeException: Unable to start activity ComponentInfo{….ItemListActivity}: java.lang.IllegalStateException: getDatabase called recursively
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2059)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at android.app.ActivityThread.access$600(ActivityThread.java:130)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at android.os.Handler.dispatchMessage(Handler.java:99)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at android.os.Looper.loop(Looper.java:137)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at android.app.ActivityThread.main(ActivityThread.java:4745)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at java.lang.reflect.Method.invokeNative(Native Method)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at java.lang.reflect.Method.invoke(Method.java:511)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at dalvik.system.NativeStart.main(Native Method)
  06-25 12:08:54.358: E/AndroidRuntime(4971): Caused by: java.lang.IllegalStateException: getDatabase called recursively
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:204)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:164)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at ….MyContentProvider.insert(MyContentProvider.java:83)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at android.content.ContentProvider$Transport.insert(ContentProvider.java:201)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at android.content.ContentResolver.insert(ContentResolver.java:864)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at ….DatabaseHelper.addItem(DatabaseHelper.java:78)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at ….DatabaseHelper.onCreate(DatabaseHelper.java:61)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:252)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at android.database.sqlite.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:188)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at ….MyContentProvider.query(MyContentProvider.java:68)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at android.content.ContentProvider.query(ContentProvider.java:652)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at android.content.ContentProvider$Transport.query(ContentProvider.java:189)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at android.content.ContentResolver.query(ContentResolver.java:370)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at android.content.ContentResolver.query(ContentResolver.java:313)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at ….DatabaseHelper.getAllItems(DatabaseHelper.java:89)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at ….Items.getAllItems(Items.java:27)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at ….ItemListFragment.onCreate(ItemListFragment.java:26)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:796)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1035)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at android.app.BackStackRecord.run(BackStackRecord.java:635)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1397)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at android.app.Activity.performStart(Activity.java:5017)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2032)
  06-25 12:08:54.358: E/AndroidRuntime(4971):     ... 11 more
  </code></pre></li>
  </ul>
  
  <p><strong>Code</strong></p>
  
  <p>I have a list activity with quite standard list adapter which I don't post, as I find it irrelevant.</p>
  
  <p>The <code>Items</code> class requests the items from the database.</p>
  
  <pre><code>public class Items {
  
  public static ArrayList&lt;Item&gt; getAllItems() {
      return new DatabaseHelper().getAllItems();
  }
  …
  }
  </code></pre>
  
  <p>The database helper class:</p>
  
  <pre><code>public class DatabaseHelper extends SQLiteOpenHelper {
  
  private ContentResolver contentResolver;
  …
  
  public DatabaseHelper(Context context) {
      super(context, DATABASE_NAME, null, DATABASE_VERSION);
      this.contentResolver = context.getContentResolver();
  }
  
  public DatabaseHelper() {
      this(MyApplication.getContext());
  }
  
  @Override
  public void onCreate(SQLiteDatabase database) {
      database.execSQL(SQL_CREATE_TABLE_ITEMS);
      //addItem(Items.getDemoItem());
  }
  
  @Override
  public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
      db.execSQL(SQL_DELETE_TABLE_ITEMS);
      onCreate(db);
  }
  
  public void addItem(Item item)
  {
      ContentValues values = new ContentValues();
      values.put(…);
      contentResolver.insert(MyContentProvider.CONTENT_URI, values);
  }
  
  public ArrayList&lt;Item&gt; getAllItems() 
  {
      ...
      Cursor cursor = contentResolver.query(MyContentProvider.CONTENT_URI, 
              projection, null, null, null);
  
      ArrayList&lt;Item&gt; items = new ArrayList&lt;Item&gt;();
      while (cursor.moveToFirst()) 
      {
          cursor.moveToFirst();
          …
          items.add(item);
      }
  
      cursor.close();
      return items;
  }
  }
  </code></pre>
  
  <p>Here is the content provider that I am using:</p>
  
  <pre><code>public class MyContentProvider extends ContentProvider {
  
  private DatabaseHelper dbHelper;
  
  // Variables used for content URI
  private static final String AUTHORITY = MyContentProvider.class.getCanonicalName();
  public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + DatabaseHelper.TABLE_ITEMS);
  private static final int SINGLE_ITEM = 1;
  private static final int ALL_ITEMS = 2;
  private static final UriMatcher URI_MATCHER;
  
  static 
  {
      URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
      URI_MATCHER.addURI(AUTHORITY, DatabaseHelper.TABLE_ITEMS, ALL_ITEMS);
      URI_MATCHER.addURI(AUTHORITY, DatabaseHelper.TABLE_ITEMS + "/#", SINGLE_ITEM);
  }
  
  @Override
  public boolean onCreate() 
  {
      dbHelper = new DatabaseHelper(getContext());
      return true;
  }
  
  @Override
  public Cursor query(Uri uri, String[] projection, String selection, 
          String[] selectionArgs, String sortOrder) 
  {   
      SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
      queryBuilder.setTables(DatabaseHelper.TABLE_ITEMS);
  
      switch (URI_MATCHER.match(uri)) {
          case ALL_ITEMS:
              break;
          case SINGLE_ITEM:
              queryBuilder.appendWhere(DatabaseHelper.ITEM_ID + "=" + uri.getLastPathSegment());
              break;
          default:
              throw new IllegalArgumentException("Unknown URI " + uri);
      }
  
      Cursor cursor = queryBuilder.query(dbHelper.getReadableDatabase(), projection, selection, 
              selectionArgs, null, null, sortOrder);
      cursor.setNotificationUri(getContext().getContentResolver(), uri); 
      return cursor;
   }
  
  @Override
  public Uri insert(Uri uri, ContentValues values) 
  {
      switch (URI_MATCHER.match(uri)) {
          case ALL_ITEMS:
              long id = dbHelper.getWritableDatabase()
                      .insert(DatabaseHelper.TABLE_ITEMS, null, values);
              getContext().getContentResolver().notifyChange(uri, null);
              return Uri.parse(CONTENT_URI + "/" + id);
          default:
              throw new IllegalArgumentException("Unsupported URI: " + uri);
      }
  }
  }
  </code></pre>
  
  <p>Could someone find the error(s)? I understand that adding data to the database causes it to be called recursively but I don't really know how to avoid this. And why do I have so many things on the main thread? As I can't load my screen without the data, it doesn't really make sense to use an asynchronous task for reading the database. And I have no idea how to initialize the content provider in another thread.</p>