2015-09-27 50 views
0

因此,我的应用程序中存储了一个SQLite数据库,用于存储最喜欢的项目(壁纸)。我开始学习数据库管理,所以这对我来说很新鲜。但是,我设法使基本数据库工作,包括添加,删除和查询...除了查询需要一些工作。在Android SQLite数据库中删除第一项后光标大小为零

基本上,用户打开一个包含图像的活动。他们打开一个菜单项,将当前图像添加到数据库(使用字符串值,因为图像是从互联网上检索的)。

接下来,我有一个特殊的片段列出了我的最爱。当你长按列表中的一个项目时,它将从数据库中删除。

这是我的问题:删除项目工作正常,除非我删除数据库中的第一项。出于某种原因,导致getFavorite()中的光标变为零,我得到一个异常。

看到我的代码在下面...很多种类,但我希望有人能帮助我!

代码

SQLite数据库助手

public class FavoritesHandler extends SQLiteOpenHelper { 

    // All Static variables 
    // Database Version 
    private static final int DATABASE_VERSION = 1; 

    // Database Name 
    private static final String DATABASE_NAME = "favoritesManager"; 

    // Contacts table name 
    private static final String TABLE_FAVORITES = "favoriteWallpapers"; 
    // Contacts Table Columns names 
    private static final String KEY_ID = "id"; 
    private static final String KEY_URL = "url"; 
    private static final String KEY_FILENAME = "file_name"; 

    private static final String[] COLUMNS = {KEY_ID, KEY_URL, KEY_FILENAME}; 

    public FavoritesHandler(Context context) { 
     super(context, DATABASE_NAME, null, DATABASE_VERSION); 
    } 

    @Override 
    public void onCreate(SQLiteDatabase sqLiteDatabase) { 
     String CREATE_CONTACTS_TABLE = "CREATE TABLE " + TABLE_FAVORITES + "(" 
       + KEY_ID + " INTEGER PRIMARY KEY, " 
       + KEY_URL + " TEXT, " 
       + KEY_FILENAME + " TEXT" + ");"; 
     sqLiteDatabase.execSQL(CREATE_CONTACTS_TABLE); 
    } 

    @Override 
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) { 
     sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + TABLE_FAVORITES + ";"); 
     onCreate(sqLiteDatabase); 
    } 

    public void addFavorite(Favorite favorite) { 
     SQLiteDatabase db = this.getWritableDatabase(); 

     ContentValues values = new ContentValues(); 
     values.put(KEY_URL, favorite.getURL()); // Favorite URL 
     values.put(KEY_FILENAME, favorite.getFilename()); // Favorite Filename 

     // Inserting Row 
     db.insert(TABLE_FAVORITES, null, values); 
     db.close(); // Closing database connection 
    } 

    public Favorite getFavorite(int id) { 
     SQLiteDatabase db = this.getReadableDatabase(); 

     Cursor cursor = db.query(TABLE_FAVORITES, new String[]{KEY_ID, 
         KEY_URL, KEY_FILENAME}, KEY_ID + "=?", 
       new String[]{String.valueOf(id)}, null, null, null, null); 
     if (cursor != null) 
      cursor.moveToFirst(); 

     // line 74 
     return new Favorite(Integer.parseInt(cursor.getString(0)), 
       cursor.getString(1), cursor.getString(2)); 

    } 

    public ArrayList<Favorite> getAllFavorites() { 
     ArrayList<Favorite> favoriteList = new ArrayList<>(); 
     // Select All Query 
     String selectQuery = "SELECT * FROM " + TABLE_FAVORITES; 

     SQLiteDatabase db = this.getWritableDatabase(); 
     Cursor cursor = db.rawQuery(selectQuery, null); 

     // looping through all rows and adding to list 
     if (cursor.moveToFirst()) { 
      do { 
       Favorite favorite = new Favorite(); 
       favorite.setID(cursor.getInt(0)); 
       favorite.setURL(cursor.getString(1)); 
       favorite.setFilename(cursor.getString(2)); 
       favoriteList.add(favorite); 
      } while (cursor.moveToNext()); 
     } 

     // return contact list 
     return favoriteList; 
    } 

    public int getFavoritesCount() { 
     SQLiteDatabase db = this.getReadableDatabase(); 
     String countQuery = "SELECT * FROM " + TABLE_FAVORITES + ";"; 
     Cursor cursor = db.rawQuery(countQuery, null); 
     int count = cursor.getCount(); 
     cursor.close(); 

     // return count 
     return count; 
    } 

    public void deleteFavorite(Favorite favorite) { 
     SQLiteDatabase db = this.getWritableDatabase(); 
     db.delete(TABLE_FAVORITES, " id = ?", 
       new String[]{String.valueOf(favorite.getID())}); 
     db.close(); 
    } 
} 

喜爱职业

public class Favorite { 

    int _ID; 
    String _URL; 
    String _FILENAME; 

    public Favorite() { 
    } 

    public Favorite(int ID, String URL, String Filename) { 
     this._ID = ID; 
     this._URL = URL; 
     this._FILENAME = Filename; 
    } 

    public Favorite(String URL, String Filename) { 
     this._URL = URL; 
     this._FILENAME = Filename; 
    } 

    public int getID() { 
     return _ID; 
    } 

    public void setID(int _ID) { 
     this._ID = _ID; 
    } 

    public String getURL() { 
     return _URL; 
    } 

    public void setURL(String _URL) { 
     this._URL = _URL; 
    } 

    public String getFilename() { 
     return _FILENAME; 
    } 

    public void setFilename(String _FILENAME) { 
     this._FILENAME = _FILENAME; 
    } 
} 

自定义图像适配器在收藏片段

private class ImageAdapter extends BaseAdapter { 

    @Override 
    public int getCount() { 
     FavoritesHandler favoritesHandler = new FavoritesHandler(getActivity().getBaseContext()); 
     return favoritesHandler.getFavoritesCount(); 
    } 

    @Override 
    public Object getItem(int position) { 
     return null; 
    } 

    @Override 
    public long getItemId(int position) { 
     return position; 
    } 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) { 
     View view = convertView; 
     final ViewHolder gridViewImageHolder; 
     if (convertView == null) { 
      view = getActivity().getLayoutInflater().inflate(R.layout.util_grid_item_image, parent, false); 
      gridViewImageHolder = new ViewHolder(); 
      gridViewImageHolder.imageView = (ImageView) view.findViewById(R.id.util_wallpaper_image); 
      view.setTag(gridViewImageHolder); 
     } else { 
      gridViewImageHolder = (ViewHolder) view.getTag(); 
     } 

     FavoritesHandler db = new FavoritesHandler(getActivity()); 

     List<Favorite> favorites = db.getAllFavorites(); 

     for (Favorite favorite : favorites) { 
      favorite = db.getFavorite(position + 1); 

      // line 136 
      imageLoader.displayImage(favorite.getURL() + favorite.getFilename(), 
        gridViewImageHolder.imageView, 
        ImageLoaderUtil.setupOptions()); 
     } 

     return view; 
    } 
} 

异常后删除在显示的列表中第一个项目

09-27 02:04:38.641 30338-30338/? E/libEGL: call to OpenGL ES API with no current context (logged once per thread) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime: FATAL EXCEPTION: main 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime: Process: com.hidden.hidden, PID: 30338 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime: android.database.CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.database.AbstractCursor.checkPosition(AbstractCursor.java:460) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:136) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:50) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at com.hidden.hidden.FavoritesHandler.getFavorite(FavoritesHandler.java:74) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at com.hidden.hidden.fragments.FavoritesFragment$ImageAdapter.getView(FavoritesFragment.java:136) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.widget.AbsListView.obtainView(AbsListView.java:2346) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.widget.GridView.onMeasure(GridView.java:1065) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.view.View.measure(View.java:18788) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.widget.FrameLayout.onMeasure(FrameLayout.java:194) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.view.View.measure(View.java:18788) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:715) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:461) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.view.View.measure(View.java:18788) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.widget.FrameLayout.onMeasure(FrameLayout.java:194) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.view.View.measure(View.java:18788) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.support.v4.widget.DrawerLayout.onMeasure(DrawerLayout.java:940) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.view.View.measure(View.java:18788) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.widget.FrameLayout.onMeasure(FrameLayout.java:194) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.support.v7.internal.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:124) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.view.View.measure(View.java:18788) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.widget.FrameLayout.onMeasure(FrameLayout.java:194) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.view.View.measure(View.java:18788) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.widget.FrameLayout.onMeasure(FrameLayout.java:194) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.view.View.measure(View.java:18788) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.widget.LinearLayout.measureVertical(LinearLayout.java:748) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.widget.LinearLayout.onMeasure(LinearLayout.java:630) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.view.View.measure(View.java:18788) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.widget.FrameLayout.onMeasure(FrameLayout.java:194) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at com.android.internal.policy.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2643) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.view.View.measure(View.java:18788) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2100) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1216) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1452) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1107) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6013) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.view.Choreographer.doCallbacks(Choreographer.java:670) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.view.Choreographer.doFrame(Choreographer.java:606) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:844) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.os.Handler.handleCallback(Handler.java:739) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.os.Handler.dispatchMessage(Handler.java:95) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.os.Looper.loop(Looper.java:148) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at android.app.ActivityThread.main(ActivityThread.java:5417) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at java.lang.reflect.Method.invoke(Native Method) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
09-27 02:04:40.195 30338-30338/com.hidden.hidden E/AndroidRuntime:  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 

我一直在努力尝试,现在找到这个约3天的解决方案...我认为这需要一套的新眼睛。

编辑

添加行号。

+0

whats在FavoritesHandler.java:74你可以请编辑和删除所有的基本代码和堆栈跟踪的基本位 – e4c5

+0

@ e4c5 - 我已更新我的问题,标有行号。 –

回答

0

嗨,我看到您的发布代码和例外。看起来问题是由于索引超出索引。在你的适配器中,问题是适配器的getCount()方法和getView(..)方法内部请参阅下面我已更新适配器代码。

private class ImageAdapter extends BaseAdapter { 

    private List<Favorite> favorites = new ArrayList(); 
    private FavoritesHandler db; 

    public ImageAdapter(){ 
     db = new FavoritesHandler(getActivity()); 
     favorites.addAll(db.getAllFavorites()); 
    } 

    @Override 
    public int getCount() { 
     return favorites.size(); 
    } 

    @Override 
    public long getItemId(int position) { 
     return position; 
    } 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) { 
     View view = convertView; 
     final ViewHolder gridViewImageHolder; 
     if (convertView == null) { 
      gridViewImageHolder = new ViewHolder(); 
      view = getActivity().getLayoutInflater().inflate(R.layout.util_grid_item_image, parent, false); 
      gridViewImageHolder.imageView = (ImageView) view.findViewById(R.id.util_wallpaper_image); 
      view.setTag(gridViewImageHolder); 
     } else { 
      gridViewImageHolder = (ViewHolder) view.getTag(); 
     } 

     Favorite favorite = favorites.gePosition(position); 
    imageLoader.displayImage(favorite.getURL() + favorite.getFilename(),gridViewImageHolder.imageView,ImageLoaderUtil.setupOptions()); 

     return view; 
    } 
} 

让我知道你是否有任何问题。谢谢。

+0

完美。谢谢。 –

+0

不客气:_) –

1

我认为这个错误是由你试图获取你刚才删除的不存在的元素引起的。

favorite = db.getFavorite(position + 1); 

当位置为0时,这将查询删除的项目。

if (cursor != null) 
     cursor.moveToFirst(); 

这会使您的代码失败,因为您正在查询已删除的项目。这会返回一个空的游标,它不是null,但尝试移动到第一个结果行会导致IndexOutOfBounds异常。

您所犯的一般错误是您将您的物品清单位置与他们的身份证绑定,这是一种不好的做法。您为用户呈现项目的方式应该独立于其数据库表示。

如果我可以为你提供一些更多的指针:

  • 适配器实现相当无效的。您正在多次访问数据库 - 一次查找计数,一次查找您为用户呈现的每个项目。如果您使用CursorAdapter或Loader,可以避免这种情况,它会为您提取收藏夹列表并创建某种自定义ArrayAdapter实例。
  • 您绝对应该考虑将DB访问从主线程移出,以确保性能安全。
+0

感谢您的强烈批评!我会考虑让这更有效。 –

+1

我建议您还查看'ContentProviders'以进一步了解如何在Android中使用SQLite。这些例子写得很好,它们强调最佳实践。希望这可以帮助你。 –

1

在这里做几个要点。

首先,一个问题在于你的getFavorite()方法的构建。

此方法采用int参数,该参数指定要从游标检索的行的KEY_ID。因此,每次调用getFavorite()时,它只返回一行数据库。当您在getView()中调用此方法时,您通过position + 1作为它的参数。由于此行不再存在于您的数据库中(因为_id列自动增量,并且第一行是位置(0 + 1)),因此您的Cursor将返回为空,因此如果尝试访问它,则会出现错误。

要解决该问题,请不要在getView()中拨打db.getAllFavorites()db.getFavorite()。从性能的角度来看,除了从这个角度来持续运行查询,这是一个非常糟糕的想法,KEY_IDCursor的行号并不总是完全一致。例如,假设有一个Cursor有三项:

_id name 
1  Cheddar 
2  Parmesan 
3  Brie 

如果你的1KEY_ID值删除行,然后调用你的光标会说,这有两个条目getCount()。但是,如果您尝试query()您的数据库与KEY_ID1,那么您将返回一个空的游标(无结果)。你改为访问的是行号之一的光标,而不是_id

要做到这一点,你需要query()getView()外数据库,存储返回Cursor到一个变量,要么使用直接填充列表项,或将其写入到某种形式的List和使用改为List。您的getAllFavorites()方法似乎是这样做的,所以您应该使用从此返回的ArrayList来填充您的列表。

一旦您对用于填充适配器的数据进行了任何更改(例如,删除之后),一定要在适配器上调用notifyDataSetChanged()

我已经编写了一个couple of blog posts的源代码和一个示例应用程序,主题为Android中的SQLite数据库,如果您有兴趣,可以详细了解SQLite数据库。

值得一提的最后一点是,您可以改善您的方法的性能。 Android中的数据库操作速度很慢,因此您希望尽可能少地调用直接与它们交互的方法,如query()。理想的情况是数据库被查询一次,然后所有进一步的操作都在返回的cursor上。如果数据库中的数据发生了重大变化,则再次查询一次并致电notifyDataSetChanged()。目前,您每次调用getView()时都会调用getAllFavorites(),这会查询整个数据库(实际上只要您的列表滚动)。然后,即使getAllFavorites()返回您需要多次的所有信息,通过调用getFavorite()可以不必要地重写每个条目。另外,大的query()调用应该在主线程之外发生,否则它们可以将UI锁定几秒钟。 AsyncTasks对此很有帮助。

+0

感谢您的详细解答。我做了上面提到的Bhavdip和固定的东西。 –