1

I have been stuck on this for a while and I have no idea how to proceed forward. I have tried all the solutions listed in Stack and other sources but the problem still unsolved. I am developing a content provider which must be accessed from another application. APP1 has the content provider with the SQLite data AND IT IS WORKING FINE as i have run it using a query. The proble is when i try to access this content provider from App2 and i get the following error

Failed to find provider info for 'Provider'
Unhandled Exception:

System.NullReferenceException: Object reference not set to an instance of an object

The following is my code for 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 Code:

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>

My guess is that either I should have mixed up the package name with Authority and provider name. Also maybe i am missing some permissions in my manifest. I have put the code anyways. Do look into it and suggest me how to make it right. Thanks in advance.

Rakesh
  • 11
  • 1
  • I am stuck with this for days. Please, any kinda help will be appreciated. More eager to know what am I doing wrong than to see what the output is. – Rakesh Nov 08 '16 at 20:23

0 Answers0