Почему моя БД пуста после вставки элемента с помощью ContentProvider в Xamarin? - PullRequest
0 голосов
/ 10 июля 2020

Я создал собственный ContentProvider и реализовал метод Insert, например:

ServiceDB _s_DB; // implements SQLiteOpenHelper, I'll add the code bellow
public const string AUTHORITY = "com.***.***.CustomProvider";
static string BASE_PATH = "accesstokens";
static string DATABASE_TABLE = "accesstokens";
public static Android.Net.Uri CONTENT_URI = Android.Net.Uri.Parse("content://" + AUTHORITY + "/" + BASE_PATH);
// MIME types used for getting a list, or a single access token
public const string MIME_TYPES = ContentResolver.CursorDirBaseType + "/vnd.com.***.***.AccessTokens";
public const string MIME_TYPE = ContentResolver.CursorItemBaseType + "/vnd.com.***.***.AccessTokens";
// Column names
public static class InterfaceConsts
{
    public const string Id = "_id";
    public const string Token = "token";
    //ubaci exparation date
}


public override Android.Net.Uri Insert(Android.Net.Uri uri, ContentValues values)
{
    Android.Util.Log.Debug("Test", "Insert");
    //---add a new token---  
    var _database = _s_DB.WritableDatabase;
    _database.BeginTransaction();
    long rowID = _database.Insert(DATABASE_TABLE, "",  values);

    //---if added successfully---  
    if (rowID > 0)
    {
        var _uri = ContentUris.WithAppendedId(CONTENT_URI, rowID);
        Context.ContentResolver.NotifyChange(_uri, null);
        _database.SetTransactionSuccessful();
        _database.EndTransaction();
        return _uri;
    }
    throw new SQLException("Failed to insert row into " + uri);
}

В моем объекте ServiceDB _s_DB реализован этот метод:

const string DatabaseName = "accesstokens.db";
const string DatabaseTable = "accesstokens";
const string create_table_sql = "CREATE TABLE " + DatabaseTable + " (_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE, token TEXT NOT NULL UNIQUE)";
const int DatabaseVersion = 1;
public ServiceDB(Context context) : base(context, DatabaseName, null, DatabaseVersion) { }


public override void OnCreate(SQLiteDatabase db)
{
    Android.Util.Log.Debug("Test", "Service Database Created");
    db.ExecSQL(create_table_sql);
    // seed with data
    db.ExecSQL("INSERT INTO accesstokens (token) VALUES ('token1')");
    db.ExecSQL("INSERT INTO accesstokens (token) VALUES ('token2')");
}

И, наконец, моя MainActivity class, где я сначала читаю 2 автоматически созданных токена, затем добавляю третий токен, затем снова читаю все три ...

MainActivity onCreate имеет это:

string[] projection = new string[] { CustomProvider.InterfaceConsts.Id, CustomProvider.InterfaceConsts.Token};
string[] fromColumns = new string[] { CustomProvider.InterfaceConsts.Token };

    // CursorLoader introduced in Honeycomb (3.0, API_11)
    var loader = new CursorLoader(this, CustomProvider.CONTENT_URI, projection, null, null, null);
    var cursor = (ICursor)loader.LoadInBackground();
    if (cursor != null)
    {
        while (cursor.MoveToNext())
        {
            String s = cursor.GetString(cursor.GetColumnIndexOrThrow("token"));
            Android.Util.Log.Debug("Test","aaa " + s);
        }
        cursor.Close();
    }

    Android.Util.Log.Debug("Test", "Create new item");
    ContentValues content = new ContentValues();
    content.Put(CustomProvider.InterfaceConsts.Id, "3"); 
    content.Put(CustomProvider.InterfaceConsts.Token, "token3");
    var ddd = ApplicationContext.ContentResolver.Insert(CustomProvider.CONTENT_URI, content);

    Android.Util.Log.Debug("Test", "ddd: " + ddd);
    ICursor c = ApplicationContext.ContentResolver.Query(CustomProvider.CONTENT_URI, null, null, null, null);

    if (c != null)
    {
        while (c.MoveToNext())
        {
            String s = c.GetString(c.GetColumnIndexOrThrow("token"));
            Android.Util.Log.Debug("Test","ccc " + s);
        }
        c.Close();
    }

Затем я беру моя созданная БД из коробки (я работаю на AndroidTV) и открываю ее в браузере БД, а БД пуста, даже таблица не создана !!

Вывод из консоли показывает:

aaa token1
aaa token2

Insert

ddd: content://com.***.***.CustomProvider/accesstokens/3

ccc token1
ccc token2
ccc token3

Я снова закрываю приложение, затем извлекаю файл accesstokens.db из телевизора, затем открываю его в браузере БД, и даже таблица не создается, а из c строк тоже нет.

Что мне не хватает?

Спасибо за ваше время.

Редактировать 1:

Это может иметь какое-то отношение к разрешениям, поэтому здесь атрибуты провайдеров:

[ContentProvider(new string[] { CustomProvider.AUTHORITY }, Exported = true, GrantUriPermissions = true, Label ="CustomProvider")]

Редактировать 2: мне удалось c зафиксируйте эту ошибку в консоли:

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.***.***/com.***.***.MainActivity}: android.database.SQLException: Failed to insert row into content://com.***.***.CustomProvider/accesstokens

Ответы [ 2 ]

0 голосов
/ 13 июля 2020

Оказывается, я запросил разрешение у поставщика контента в своей основной деятельности через эту строку:

ApplicationContext.ContentResolver.TakePersistableUriPermission(CustomProvider.CONTENT_URI, Android.Content.ActivityFlags.GrantWriteUriPermission);

Но поскольку это приложение изначально имеет компонент поставщика контента, который я использую, ему не требуется это разрешение, поскольку оно уже есть по умолчанию.

Итак, его удаление решило мою проблему.

0 голосов
/ 13 июля 2020

Я внесу изменения в ваш код, он хорошо работает на моей стороне. Вы можете проверить исходный файл на GitHub. Я использую Listview для отображения элементов в базе данных.

GitHub: https://github.com/WendyZang/Test/tree/master/SimpleContentProvider

Я мой пользовательский ContentProvider: VegetableProvider, переопределите метод OnCreate и внесите некоторые изменения с помощью код.

пользовательский ContentProvider: VegetableProvider

//---add a new book---  
_s_DB = new VegetableDatabase(this.Context);
var _database = _s_DB.WritableDatabase;

MainActivity: для отображения элементов в списке.

cursor = ContentResolver.Query(VegetableProvider.CONTENT_URI, projection, null, null, null);
        adapter = new SimpleCursorAdapter(this, Android.Resource.Layout.SimpleListItem1, cursor,
            fromColumns, toControlIds);

        listView.Adapter = adapter;

введите описание изображения здесь

У меня нет AndroidTV для тестирования, сначала проверьте код.

...