我被困在这一段时间,我不知道如何继续前进。我已经尝试了Stack和其他来源中列出的所有解决方案,但问题仍然没有解决。我正在开发一个必须从另一个应用程序访问的内容提供程序。 APP1有内容提供程序,其中包含SQLite数据和工作正常,因为我使用查询运行它。问题是当我尝试从App2访问此内容提供程序时,我收到以下错误
Failed to find provider info for 'Provider'
Unhandled Exception:
System.NullReferenceException: Object reference not set to an instance of an object
以下是我的APP1代码
NamesProvider.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.Database;
using Android.Net;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Database.Sqlite;
namespace CustomContentProvider
{
[ContentProvider(new[] { "customcontentprovider.customcontentprovider.NamesProvider" }, Name = "customcontentprovider.customcontentprovider.NamesProvider")]
class NamesProvider : ContentProvider
{
public static string PROVIDER_NAME = "customcontentprovider.customcontentprovider.NamesProvider";
public static Android.Net.Uri CONTENT_URI = Android.Net.Uri.Parse("content://" + PROVIDER_NAME + "/locations");
private MyProviderDBHelper dbHelper;
// "content://customcontentprovider.customcontentprovider.NamesProvider/locations"
public const string _ID = "_id";
public const string NAME = "name";
private const string DEFAULT_SORT_ORDER = "name DESC";
//private const int uriCode = 1;
private static UriMatcher uriMatcher;
private static Dictionary<String, String> values;
private const string DATABASE_NAME = "Locations";
private const string DATABASE_TABLE_NAME = "Location";
private const int LOCATIONS = 1;
private const string LOCATION_TYPE = "vnd.android.cursor.dir/vnd.customcontentprovider.location";
private const int DATABASE_VERSION = 1;
static NamesProvider()
{
values = new Dictionary<string, string>();
values.Add(_ID, _ID);
values.Add(NAME, NAME);
uriMatcher = new UriMatcher(UriMatcher.NoMatch);
uriMatcher.AddURI(PROVIDER_NAME, "locations", LOCATIONS);
}
public override Android.Net.Uri Insert(Android.Net.Uri uri, ContentValues values)
{
if (uriMatcher.Match(uri) != LOCATIONS)
{
throw new ArgumentException("Unknown URI " + uri);
}
SQLiteDatabase db = dbHelper.WritableDatabase;
long rowID = db.Insert(DATABASE_TABLE_NAME, NAME, values);
if (rowID >= 0)
{
Android.Net.Uri _uri = ContentUris.WithAppendedId(CONTENT_URI, rowID);
Context.ContentResolver.NotifyChange(_uri, null);
return _uri;
}
throw new SQLException("Failed to add a record into " + uri);
}
public override ICursor Query(Android.Net.Uri uri, string[] projection, string selection, string[] selectionArgs, string sortOrder)
{
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.Tables = DATABASE_TABLE_NAME;
switch (uriMatcher.Match(uri))
{
case LOCATIONS:
qb.SetProjectionMap(values);
break;
default:
throw new ArgumentException("Unknown URI " + uri);
}
string orderBy;
if (sortOrder.Length < 1)
{
orderBy = DEFAULT_SORT_ORDER;
}
else
{
orderBy = sortOrder;
}
SQLiteDatabase db = dbHelper.WritableDatabase;
ICursor c = qb.Query(db, projection, selection, selectionArgs, null,
null, orderBy);
c.SetNotificationUri(Context.ContentResolver, uri);
return c;
}
public override bool OnCreate()
{
dbHelper = new MyProviderDBHelper(Context);
return true;
}
public override int Update(Android.Net.Uri uri, ContentValues values, string selection, string[] selectionArgs)
{
SQLiteDatabase db = dbHelper.WritableDatabase;
int count = 0;
switch (uriMatcher.Match(uri))
{
case LOCATIONS:
count = db.Update(DATABASE_TABLE_NAME, values, selection, selectionArgs);
break;
default:
throw new ArgumentException("Unknown URI " + uri);
}
Context.ContentResolver.NotifyChange(uri, null);
return count;
}
public override int Delete(Android.Net.Uri uri, string selection, string[] selectionArgs)
{
SQLiteDatabase db = dbHelper.WritableDatabase;
int count = 0;
switch (uriMatcher.Match(uri))
{
case LOCATIONS:
count = db.Delete(DATABASE_TABLE_NAME, selection, selectionArgs);
break;
default:
throw new ArgumentException("Unknown URI " + uri);
}
Context.ContentResolver.NotifyChange(uri, null);
return count;
}
public override string GetType(Android.Net.Uri uri)
{
switch (uriMatcher.Match(uri))
{
case LOCATIONS:
return LOCATION_TYPE;
default:
throw new ArgumentException("Unsupported URI: " + uri);
}
}
private class MyProviderDBHelper : SQLiteOpenHelper
{
public MyProviderDBHelper(Context context)
: base(context, DATABASE_NAME, null, DATABASE_VERSION)
{
}
public override void OnCreate(SQLiteDatabase db)
{
db.ExecSQL(@"
CREATE TABLE " + DATABASE_TABLE_NAME + " ("
+ _ID + " INTEGER PRIMARY KEY NOT NULL,"
+ NAME + " TEXT NOT NULL)"
);
}
public override void OnUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
db.ExecSQL("DROP TABLE IF EXISTS " + DATABASE_TABLE_NAME);
OnCreate(db);
}
}
}
}
MainActivity.cs
using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
namespace CustomContentProvider
{
[Activity(Label = "CustomContentProvider", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
QueryValues();
// Get our button from the layout resource,
// and attach an event to it
Button btn = FindViewById<Button>(Resource.Id.btnAdd);
btn.Click += delegate
{
EditText nameEditText = FindViewById<EditText>(Resource.Id.txtName);
if (nameEditText.Text.Length < 0)
{
Toast.MakeText(this, "Name cannot be empty.", ToastLength.Long).Show();
return;
}
ContentValues values = new ContentValues();
values.Put(NamesProvider.NAME, (FindViewById<EditText>(Resource.Id.txtName).Text));
Android.Net.Uri uri = ContentResolver.Insert(NamesProvider.CONTENT_URI, values);
if (uri != null)
{
nameEditText.Text = "";
Toast.MakeText(this, "record added !!! ", ToastLength.Long).Show();
QueryValues();
}
else
{
Toast.MakeText(this, "record add failed!!! ", ToastLength.Long).Show();
}
};
}
private void QueryValues()
{
Android.Net.Uri allLocations = NamesProvider.CONTENT_URI;
Android.Database.ICursor c = ManagedQuery(allLocations, null, null, null, "_id");
if (c.MoveToFirst())
{
System.Diagnostics.Debug.WriteLine("\n****************************\n");
do
{
// This will show in the output window of Visual Studio // MonoDevelop when you run it in debug mode
System.Diagnostics.Debug.WriteLine("NameProvider:\n"
+ "ID: " + c.GetString(c.GetColumnIndex(NamesProvider._ID)) + "\n"
+ "Name: " + c.GetString(c.GetColumnIndex(NamesProvider.NAME))
);
} while (c.MoveToNext());
}
}
}
}
的Manifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="CustomContentProvider.CustomContentProvider" android:versionCode="1" android:versionName="1.0" android:installLocation="auto">
<uses-sdk android:minSdkVersion="16" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_USER_DICTIONARY" />
<uses-permission android:name="android.permission.WRITE_USER_DICTIONARY" />
<application android:label="CustomContentProvider">
<provider android:name="customcontentprovider.customcontentprovider.NamesProvider"
android:authorities="customcontentprovider.customcontentprovider.NamesProvider"
android:exported="true"
android:enabled="true"
android:syncable="true"
android:grantUriPermissions="true"
android:multiprocess="true"></provider>
</application>
</manifest>
APP2代码:
MainActivity.cs
using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using Android.Database;
using Android.Content.PM;
using System.Collections.Generic;
using Java.Util;
namespace ContentProviderConsumer
{
[Activity(Label = "ContentProviderConsumer", MainLauncher = true, Icon = "@drawable/icon")]
public class MainActivity : Activity
{
ListView listview;
Android.Database.ICursor cursor;
public static string PROVIDER_NAME = "customcontentprovider.customcontentprovider.NamesProvider";
public static Android.Net.Uri CONTENT_URI = Android.Net.Uri.Parse("content://" + PROVIDER_NAME + "/locations");
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
Android.Net.Uri allLocations = CONTENT_URI;
ContentResolver cr = ContentResolver;
cursor = cr.Query(allLocations , null, null, null, null);
StartManagingCursor(cursor);
if (cursor.MoveToFirst())
{
do
{
System.Diagnostics.Debug.WriteLine("NamesProvider:\n"
+ "ID: " + cursor.GetString(cursor.GetColumnIndex("_id")) + "\n"
+ "Name: " + cursor.GetString(cursor.GetColumnIndex("name"))
);
} while (cursor.MoveToNext());
}
}
}
}
Manifes.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="ContentProviderConsumer.ContentProviderConsumer" android:versionCode="1" android:versionName="1.0" android:installLocation="auto">
<uses-sdk android:minSdkVersion="16" />
<uses-permission android:name="CustomContentProvider.READ_DATABASE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_USER_DICTIONARY" />
<uses-permission android:name="android.permission.WRITE_USER_DICTIONARY" />
<application android:label="ContentProviderConsumer"></application>
</manifest>
我的猜测是,我应该将包名称与权限和提供者名称混淆。也许我在我的清单中缺少一些权限。我还是放了代码。请仔细研究并建议我如何做对。提前谢谢。