0

My app uses an SQLite DB, wrapped with a SQLiteOpenHelper and a ContentProvider. I added a sign-in feature to the app, and now I want every user to only be able to see his own data. The way I thought to achieve this is for the app to create a separate DB for every user that signs in to the app, and use the user's ID in the filename of the database.

I have this ContentProvider:

public class MyProvider extends ContentProvider {

    //...

    @Override
    public boolean onCreate() {
    dbHelper = new MyDBHelper(getContext());
    return true;
}

I have this SQLiteOpenHelper:

public class MyDBHelper extends SQLiteOpenHelper {

Which has this constructor:

public MyDBHelper(Context context) {
    super(context, DB_NAME, null, DB_VERSION);
}

Up until now the app couldn't have multiple users, so it just had one database. so DB_NAME was always the same String. I now tried to set it like that:

private static String UID = FirebaseAuth.getInstance().getCurrentUser().getUid();
public static final String DB_NAME = String.format("data%s.db", UID);

(As you can see, I'm using Firebase Authentication)

but this resulted in a crash, because apparently the content provider is created on app start, before the user has authenticated. (so user is null. Yeah, I should check that user is not null before I try to call getUid(). but this won't make this thing work)

So this doesn't seem like the right approach. How can I use a different DB according to the signed user? Can I make the content provider to first be created after a user has authenticated?

I could also just keep everything in one database and add a UID column. But will this be protect the different users' data good enough from each other? Also, this would mean a lot more code changes.

talz
  • 1,004
  • 9
  • 22

2 Answers2

0

How can I use a different DB according to the signed user?

The simple solution is to get rid of the ContentProvider. The only reason to use a ContentProvider is if you are going to be serving this data to other apps.

Also, I would be wary of just taking getUid() and putting it in a filename. You are not in control over what getUid() returns, and it might someday contain characters that are invalid in filenames.

Can I make the content provider to first be created after a user has authenticated?

No, sorry.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • I'm using a `ContentProvider` because I'm using a `CursorLoader`. – talz Jul 07 '18 at 17:40
  • Then get rid of that too and use Room instead. – Thracian Jul 07 '18 at 17:55
  • Yes, definitely just use Room, and also I would definitely recommend just using multiple tables instead of an entire database for each user – Nick Mowen Jul 07 '18 at 18:03
  • @talz: Whether you use Room, another ORM, or just the native SQLite API (`SQLiteOpenHelper`, etc.) is up to you. However, do not use a `ContentProvider` just to use a `CursorLoader`. – CommonsWare Jul 07 '18 at 18:24
0

Seems that the right solution here is to not use ContentProviders. So I accepted the other answer.

But to answer my actual question, for people that are determined to make different DBs work with one ContentProvider, here is how it can be done:

I changed the custom SQLiteOpenDBHelper's constructor to also take a uid:

    public MyDBHelper(Context context, String uid) {
        super(context, String.format(DB_NAME, uid), null, DB_VERSION);
        UID = uid;
    }

and I changed the onCreate of my ContentProvider not to create the DBHelper. I created this function that initializes the DBHelper instead:

    public void initDB(Uri uri) {
        String uid = uri.getPathSegments().get(0);
        if (dbHelper == null){
            dbHelper = new MyDBHelper(getContext(), uid);
        } else if (!uid.equals(dbHelper.UID)){
            dbHelper.close();
            dbHelper = new MyDBHelper(getContext(), uid);
        }
    }

and I call this method at the start of the query, insert, update and delete methods.

So the DBHelper which holds the open connection to the DB, is initialized whenever the content provider is preforming some action on the DB but there is either not yet an existing connection with the DB, or the connection is with a DB of a different user.

This is not the right way to solve this problem and this probably has consequences in some cases. But I didn't want to leave the question I asked unanswered.

talz
  • 1,004
  • 9
  • 22