SQLite / Android的一般怪异

时间:2014-04-29 16:22:56

标签: java android database sqlite

我有这个简单的应用程序,我目前正在写作练习。其目的是允许用户在服务器上发送报价和该报价的作者(在这种情况下是我已经注册的Parse.com后端),然后随机地向应用的其他用户显示这些报价。因此,通过打开应用程序,您会收到某人发布的随机评论。

我试图实现这个目标的方式是:

  1. 在启动时,应用程序连接到Parse.com后端并下载所有当前可用的引号(我称之为Inanity对象,因为引用应该是开明的,但实际上应该是愚蠢和无意义的 - 无论如何,不没问题。这是代码:

    query.findInBackground(new FindCallback<ParseObject>() {
            SQLi sqlite = new SQLi(MainActivity.this);
            SQLiteDatabase dbz = sqlite.getWritableDatabase();
    
            @Override
            public void done(List<ParseObject> list, ParseException e) {
    
                            //sqlite.dbDelete();    
                if (e == null) {
    
                    int size = list.size();
    
                    for (int i = 0; i < size; i++) {
    
                        ParseObject object = list.get(i);
    
                        String author = object.get("author").toString();
                        String content = object.get("content").toString();
    
                        Inanity inan = new Inanity(content, author, 1);
    
                        Log.d("FOR LOOP" + i, inan.toString());
                        sqlite.insertInanity(dbz, inan);
    
                    }
    
                }
    
            }
    
        });
    
  2. 非常简单。 ( dbz 是顺便调用 getWritableDatabase()获取的SQLiteDatabase)。下面的代码是SQLiteOpenHelper insertInanity()方法的代码,我用它将来自服务器的检索数据放在本地SQLite数据库中:

    public void insertInanity(SQLiteDatabase db, Inanity inanity) {
    
            ContentValues values = new ContentValues();
    
            values.put(CONTENT_INANITIES, inanity.getContent());
            values.put(AUTHOR_INANITIES, inanity.getAuthor());
            values.put(UPVOTE_INANITIES, inanity.getUpvotes());
    
            db.insert(TABLE_INANITIES, null, values);
    
        }
    

    我将一个SQLiteDatabase对象传递给该方法只是为了避免必须调用getWriteableDatabase() - 如果我一直这样做,我在重复调用时遇到了一些麻烦。

    在本地SQLite数据库上写入服务器数据之后,用户将被带到一个Activity,该Activity开始在几个TextView中显示引号和引号的作者。这是从SQLite数据库中检索引用/作者对象的代码:

    public Inanity retrieveInanity(int id) {
    
            SQLiteDatabase db = this.getReadableDatabase();
    
            Cursor cursor = db.query(TABLE_INANITIES, new String[] {
                    CONTENT_INANITIES, AUTHOR_INANITIES, UPVOTE_INANITIES },
                    ID_INANITIES + " = " + id, null, null, null, null);
    
            if (cursor == null || cursor.getCount() == 0) {
                return new Inanity("a", "b", 1);
            }
    
            else {
    
                cursor.moveToFirst();
    
                String contentL = cursor.getString(cursor
                        .getColumnIndex(CONTENT_INANITIES));
                String authorL = cursor.getString(cursor
                        .getColumnIndex(AUTHOR_INANITIES));
                int upvotesL = cursor.getInt(cursor
                        .getColumnIndex(UPVOTE_INANITIES));
    
                Inanity inanity = new Inanity(contentL, authorL, upvotesL);
                return inanity;
            }
    
        }
    

    最后,要显示的引用是从本地存储的结果中随机选择的(“a”是先前声明的int变量)

    final SQLi sql = new SQLi(this);
    
            a = sql.getRowCount() + 1;
    
            Button button = (Button) findViewById(R.id.button1);
    
            button.setOnClickListener(new OnClickListener() {
    
                @Override
                public void onClick(View v) {
                    Random rand = new Random();
                    int e = rand.nextInt(a);
    
                    if (e != 0) {
    
    
                        Inanity inanity = sql.retrieveInanity(e);
                        String content = inanity.getContent();
                        String author = inanity.getAuthor();
    
                        ImageView imageView = (ImageView) findViewById(R.id.downloaded);
                        TextView contentView = (TextView) findViewById(R.id.content);
                        TextView authorView = (TextView) findViewById(R.id.author);
    
                        Picasso.with(ShowActivity.this)
                                .load("http://img1.etsystatic.com/000/0/5356113/il_fullxfull.314192275.jpg")
                                .into(imageView);
                        contentView.setAlpha(0.9f);
                        authorView.setAlpha(0.9f);
    
                        Animation alpha = new AlphaAnimation(0.1f, 1.0f);
                        alpha.setDuration(2000);
    
                        contentView.setText(content);
                        authorView.setText(author);
    
                        contentView.startAnimation(alpha);
                        authorView.startAnimation(alpha);
                    }
    
                    else {
                        Toast.makeText(ShowActivity.this,
                                "Cursor trouble in wonderland!", Toast.LENGTH_LONG)
                                .show();
                    }
                }
            });
    
    
        }
    

    SQLi类的 getRowCount()方法是这样的:

    public int getRowCount() {
    
            int count = 1;
    
            SQLiteDatabase db = getReadableDatabase();
            Cursor cursor = db.rawQuery("SELECT * FROM " + TABLE_INANITIES, null);
    
            if (cursor != null && cursor.getCount() > 0 && cursor.moveToFirst()) {
                count = cursor.getCount();
            }
    
            return count;
    
        }
    

    大部分时间。这很棒。那么,问题是什么,我听到你的问题?好吧,因为每次应用程序启动时我想刷新引号并从服务器获取新的引号,我试图完成的方法是删除数据库的Inanity表的内容并重新填充它们启动。所以,我在SQLi数据库助手类中创建了这个方法,该类称为 dbDelete(),我在FindCallback类的 done()方法的开头调用了该方法。 Parse.com库(尽管我已经从这段代码中对此进行了评论,它可以游戏地工作:它可以很好地删除数据库的内容)。不幸的是,当我这样做时,似乎本地SQLite数据库没有在应用程序启动时因某些地狱原因而重新填充,所以我不断获得占位符“a”,“b”和 retrieveInanity时返回的1个值()方法无法找到游标内容。这是 dbDelete()方法,非常简单:

    public void dbDelete() {
            SQLiteDatabase db = this.getWritableDatabase();
            db.delete(TABLE_INANITIES, null, null);
        }
    

    我一直试图解决这个问题已经有一段时间了,这让我发疯了。我理解这个问题很复杂,很大,并且它不包含任何吸引人的NullPointerExceptions / logcat动作,但任何帮助都将不胜感激。我必须遗漏与SQLite数据库使用明显相关的东西,但我根本无法理解。

1 个答案:

答案 0 :(得分:2)

我写了一个类似的应用程序(一个调用远程数据库并更新本地数据库的信息)。您应该尝试使用db.insertOrThrow。您需要将该方法包装在Try ... Catch语句中。它将尝试插入行,并在行已存在时抛出异常。然后,您可以通过将Catch部件留空来忽略错误。这将避免删除和重建表。

try { db.insertOrThrow(TABLE_INANITIES, null, values); } catch SQLException s { \\do nothing, as we don't care about existing rows }

如果您将报价服务器设置为具有报价的唯一标识符,则本地副本(您的SQLite DB)将不会插入重复的条目。例如,服务器上的引用数据库表看起来像这样

ID | Quote | Author 1 | blah | J. smith

将列ID设置为唯一标识符(或唯一键)。当您的应用程序调用服务器并查询远程数据库时,您的本地数据库只会添加不存在的记录。

我还想确保您在onResume()中更新游标适配器。