【问题标题】:Android - Content Provider query cursorAndroid - 内容提供程序查询光标
【发布时间】:2014-11-03 13:41:36
【问题描述】:

我似乎无法理解内容提供者的概念。我个人认为它使代码膨胀,使代码过于复杂,而且显然很糟糕。

顺便说一句,这将是您可以在网络上找到的多表 ContentProvider 的第一个示例代码。绝对没有其他的,除了可能是 ContactsProvider(“veeeerrrry 有用” - 被超级填充和难以形容)。我相信很多像我这样的菜鸟都会喜欢这个。

请帮助我从内容提供商处制作一个简单的光标。我有下面的 NORMAL 代码(使用简单的 SQLiteOpenHelper),我需要将其转换为内容提供程序代码:

    Button btnp = (Button) findViewById(R.id.btnproc);
    btnp.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
        Context mycontext = getApplicationContext();
        SQLiteDatabase db = new myDbHelper(mycontext).getWritableDatabase();
        String sql = "select _id,data,titlu,cont from notificari where date(data)<=date(datetime())";
        Cursor cursor = db.rawQuery(sql, null);
        Log.w("...MainActivity...", "Record count:"+Integer.toString(curu.getCount()));
            while(curu.moveToNext()){
                String lista = curu.getString(0)+",'"+curu.getString(1)+"',"+curu.getString(2)+",'"+
                        curu.getString(3)+"'";
                Log.e("...MainActivity...", lista);
            }

        }
    });

所以我需要从 content-provider 获取光标。我已经开始开发这个“令人兴奋的”内容提供者,但我不知道我所做的是否可以,因为它过于复杂。就这样(我的内容提供者需要引用多个表):

public class MyFirstProvider extends ContentProvider {
static final String PROVIDER_NAME = "com.mystuff.myapp.MyFirstProvider";
    static final String URL = "content://" + PROVIDER_NAME + "/cte";
    static final String URL2 = "content://" + PROVIDER_NAME + "/clienti";
    static final String URL3 = "content://" + PROVIDER_NAME + "/uzeri";
    static final String URL4 = "content://" + PROVIDER_NAME + "/notificari";
    static final Uri CONTENT_URI = Uri.parse(URL);
    static final Uri CONTENT_URI2 = Uri.parse(URL2);
    static final Uri CONTENT_URI3 = Uri.parse(URL3);
    static final Uri CONTENT_URI4 = Uri.parse(URL4);


    static final int uriCode = 1;
    static final int uriCode1 = 2;
    static final int uriCode2 = 3;
    static final int uriCode3 = 4;
    static final int uriCode4 = 5;
    static final int uriCode5 = 6;
    static final int uriCode6 = 7;
    static final int uriCode7 = 8;


    static final UriMatcher uriMatcher;
    private static HashMap<String, String> values;
    static {
        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        uriMatcher.addURI(PROVIDER_NAME, "cte", uriCode);
        uriMatcher.addURI(PROVIDER_NAME, "cte/*", uriCode1);
        uriMatcher.addURI(PROVIDER_NAME, "clienti", uriCode2);
        uriMatcher.addURI(PROVIDER_NAME, "clienti/*", uriCode3);
        uriMatcher.addURI(PROVIDER_NAME, "uzeri", uriCode4);
        uriMatcher.addURI(PROVIDER_NAME, "uzeri/*", uriCode5);
        uriMatcher.addURI(PROVIDER_NAME, "notificari", uriCode6);
        uriMatcher.addURI(PROVIDER_NAME, "notificari/*", uriCode7);
    }

    @Override
    public boolean onCreate() {
        Context context = getContext();
        DatabaseHelper dbHelper = new DatabaseHelper(context);
        db = dbHelper.getWritableDatabase();
        if (db != null) {
            return true;
        }
        return false;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder) {
        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
        switch (uriMatcher.match(uri)) {
            case uriCode:
                qb.setTables(TABLE_NAME);
                qb.setProjectionMap(values);
                break;
            case uriCode2:
                qb.setTables(TABLE_CLIENTI);
                qb.setProjectionMap(values);
                if (sortOrder == null || sortOrder == "") {
                    sortOrder = TCL_NUME_CLIENT;
                }
                break;
            case uriCode6:
                qb.setTables(TABLE_NOTIF);
                qb.setProjectionMap(values);
                break;

            default:
                throw new IllegalArgumentException("Unsupported URI: " + uri);
        }
        Cursor c = qb.query(db, projection, selection, selectionArgs, null,null, sortOrder);
        c.setNotificationUri(getContext().getContentResolver(), uri);
        return c;
    }


    // ... there is other code here regarding the insert,update and delete (not relevant now)

    private SQLiteDatabase db;
    static final String DATABASE_NAME = "mydb";
    static final String TABLE_NAME = "names";
    public static final String TABLE_UZERI = "uzeri";
    public static final String TABLE_NOTIF = "notificari";


    static final int DATABASE_VERSION = 3;
    static final String CREATE_DB_TABLE = " CREATE TABLE " + TABLE_NAME
            + " (_id INTEGER PRIMARY KEY AUTOINCREMENT, "
            + " name TEXT NOT NULL);";

    static final String CREATE_DB_TABLE_NOTIFICARI = "CREATE TABLE IF NOT EXISTS " + TABLE_NOTIF + " (_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
            TNOT_ID_NOT + " INTEGER NOT NULL DEFAULT 0, " +
            TNOT_DATA + " DATE NOT NULL, " +
            TNOT_SURSA + " INTEGER NOT NULL DEFAULT 0, "+
            TNOT_DEST + " INTEGER NOT NULL DEFAULT 0, "+
            TNOT_TIP + " TEXT, "+
            TNOT_TITLU + " TEXT, "+
            TNOT_TITLUCONT + " TEXT, "+
            TNOT_CONT + " TEXT, "+
            TNOT_STERS + " INTEGER DEFAULT 0, "+
            TNOT_NOU + " INTEGER NOT NULL DEFAULT 0)";

   private static class DatabaseHelper extends SQLiteOpenHelper {
        DatabaseHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            db.execSQL(CREATE_DB_TABLE);
            db.execSQL(CREATE_DB_TABLE_UZERI);
            db.execSQL(CREATE_DB_TABLE_NOTIFICARI);
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
            db.execSQL("DROP TABLE IF EXISTS " + TABLE_UZERI);
            db.execSQL("DROP TABLE IF EXISTS " + TABLE_NOTIFICARI);
            onCreate(db);
        }
    }

我试图“翻译”记录光标内容的活动代码,但它什么也没做。这非常令人沮丧。 这是我的“翻译”:

Button btnp = (Button) findViewById(R.id.btnproc);
btnp.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        String[] coloane = {MyFirstProvider.TNOT_ID_ID, MyFirstProvider.TNOT_DATA,MyFirstProvider.TNOT_TITLU, MyFirstProvider.TNOT_CONT};
        Cursor curu = MainActivity.this.getContentResolver().query(MyFirstProvider.CONTENT_URI_NOTIF,coloane,null,null,MyFirstProvider.TNOT_DATA);

        Log.w("...MainActivity...", "Recorduri:"+Integer.toString(curu.getCount()));
        while(curu.moveToNext()){
            String lista = curu.getString(0)+",'"+curu.getString(1)+"',"+curu.getString(2)+",'"+
                    curu.getString(3)+"'";
            Log.e("...MainActivity...", lista);
        }

    }
});

我必须向您保证该表中有 4 条记录(我在创建表后手动插入它们) 此外,如果我将此代码放在 ContentProvider 中,则日志会根据需要显示表的内容:

Cursor c = qb.query(db, projection, selection, selectionArgs, null,null, sortOrder);
        while(c.moveToNext()){
            Log.w("...Provider...",c.getString(0)+"-"+c.getString(1)+"-"+c.getString(2));
        }

但我不想在内容提供者中这样做,我想在活动代码中这样做。 我做错了什么?

请帮忙。

谢谢

【问题讨论】:

  • 首先,你需要一个内容提供者吗?
  • 你最后找到这个了吗?内容提供者是外部访问数据的另一个抽象级别。进行查询时,最好将代码抽象为帮助程序类,以便活动不知道底层数据访问。它将显着简化您的代码并减少您必须复制它的次数。

标签: android android-contentprovider android-cursor


【解决方案1】:

如果您不需要,您不必使用ContentProvider。确定您的要求。如果数据对您的应用程序是私有的,并且必须以表格格式存储,那么您可以直接在 Android 中访问 SQLite 引擎,而无需通过ContentProvider。但是,如果您希望其他应用程序或系统访问您的应用程序的数据,那么可以 - 这是ContentProvider 的合法用例。

尽管如此,我建议您阅读此 article - 它告诉您如何使用和不使用 ContentProvider 访问 SQLite 引擎。

希望这会有所帮助。

无论如何,对于你手头的问题,试试这个 -

Cursor c = qb.query(db, projection, selection, selectionArgs, null,null, sortOrder);
if (c == null) {
  // error - log some message
}
else if (c.getCount() < 1) {
  // nothing to show  - log some message
}
else {
  while(c.moveToNext()){
    Log.w("...Provider...",c.getString(0)+"-"+c.getString(1)+"-"+c.getString(2));
  } 
}

【讨论】:

  • 不幸的是,我不得不这样做。因为稍后我需要将我的 SQLite 数据库与远程 MySQL 数据库同步……我希望有比 ContenrtProvider 更好的方法。我只是讨厌它
  • 奇怪...我的光标不为空,但是如果我不测试它(是否为空),显然它将停止处理代码。太好了...无论如何,感谢您的提醒。你解决了我的问题。 (当然我确定你的意思是第一个 if 语句应该是 "if (c == null)" )
【解决方案2】:

不是这个

btnp.setOnClickListener(new View.OnClickListener

试试

btnp.setOnClickListener(this)

并将 onClickListner 实现到 Activity。

简而言之,不要将 onClickListener 强制转换为按钮,而是将其实现到整个活动并尝试。

【讨论】:

  • 你不懂。我的光标/查询被执行,因为我可以看到 Provider 生成的 logcat。但是在执行光标后,我还可以看到 MainActivity 中的 LogCat 显示光标的 getCount() ,然后什么都没有……而且我在 Activity 上有多个按钮,所以我不想对整体实施 litener活动。另外我认为这不会解决我的问题。正如我已经说过的,点击事件正在工作,但只是部分工作。 while 循环似乎没有执行
  • 非常不切实际的解决方案,不能作为答案
猜你喜欢
  • 2015-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多