为啥我在 Xamarin 中使用 ContentProvider 插入项目后数据库为空?
Posted
技术标签:
【中文标题】为啥我在 Xamarin 中使用 ContentProvider 插入项目后数据库为空?【英文标题】:Why is my DB empty after I insert an item using the ContentProvider in Xamarin?为什么我在 Xamarin 中使用 ContentProvider 插入项目后数据库为空? 【发布时间】:2020-10-31 02:38:02 【问题描述】:我制作了一个自定义的 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 类,我首先读取 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,然后使用数据库浏览器打开它,甚至没有创建表,并且也没有行。
我错过了什么?
感谢您的宝贵时间。
编辑 1:
这可能与权限有关,所以这里是提供者属性:
[ContentProvider(new string[] CustomProvider.AUTHORITY , Exported = true, GrantUriPermissions = true, Label ="CustomProvider")]
编辑 2: 我已设法在控制台中捕获此错误:
java.lang.RuntimeException: Unable to start activity ComponentInfocom.***.***/com.***.***.MainActivity: android.database.SQLException: Failed to insert row into content://com.***.***.CustomProvider/accesstokens
【问题讨论】:
【参考方案1】:我对您的代码进行了更改,它在我这边运行良好。您可以从 GitHub 检查源文件。我使用 Listview 来显示数据库中的项目。
GitHub: https://github.com/WendyZang/Test/tree/master/SimpleContentProvider
我的自定义 ContentProvider:VegetableProvider,重写 OnCreate 方法并对代码进行一些更改。
自定义内容提供者:蔬菜提供者
//---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可以测试,你可以先检查代码。
【讨论】:
很有趣,我使用该示例作为我的代码的起点。但这可能与我正在开发的 Android TV 有关....【参考方案2】:事实证明,我在我的主要活动中通过此行向内容提供者请求了许可:
ApplicationContext.ContentResolver.TakePersistableUriPermission(CustomProvider.CONTENT_URI, Android.Content.ActivityFlags.GrantWriteUriPermission);
但是,由于这是最初具有我正在使用的内容提供程序组件的应用程序,因此它不需要该权限,因为默认情况下它已经拥有它。
所以,删除它解决了我的问题。
【讨论】:
以上是关于为啥我在 Xamarin 中使用 ContentProvider 插入项目后数据库为空?的主要内容,如果未能解决你的问题,请参考以下文章
为啥在 xamarin 表单中写入操作后,我在 iOS 中获得 BLE 配对请求对话框?
为啥我在 Xamarin iOS 中的 WebRequest 在 ipv6 环境中失败?