hello i have a problem with android. In my app i get data from a webservice and i read it into a sql lite database . In my activity i have multiple spinners who are filled with data from the DB. After selecting all the spinners and clicking the button i go to an other activty where i click a link and the data is written into another table.
I will explain what the app is like a form where a student can choose with school , study area,.. till you have the tuition you want. You can subscribe than for the course(that data is written to another table).
In the other app you can see the tuition whit the number of subscribers.
the first app works but my problem is that i need the table of subscibers used in app 1 for app2
i have read about COntent providers ,shared user id but none of it works.
Can somebody help me?
public class SchemaHelper extends SQLiteOpenHelper {
private final static String DATABASE_NAAM ="av_helpdesk.be.db";
private static final int DATABASE_VERSIE = 10;
public SchemaHelper(Context context) {
super(context, DATABASE_NAAM, null, DATABASE_VERSIE);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE "
+ GegevensTabel.TABEL_NAAM
+ " (" + GegevensTabel.ID
+ " INTEGER PRIMARY KEY,"
+ GegevensTabel.INSTELLING
+ " TEXT,"
+ GegevensTabel.OPLEIDINGSTYPE
+ " TEXT,"
+ GegevensTabel.OPLEIDINGSGEBIED
+ " TEXT,"+ GegevensTabel.OPLEIDING+" TEXT,"
+ GegevensTabel.MODULE+" TEXT,"
+ GegevensTabel.LESPLAATS_ADRES+" TEXT,"
+ GegevensTabel.AAVANGS_DATUM+" TEXT"+");"
);
db.execSQL("CREATE TABLE "
+ InschrijvingTabel.TABEL_NAAM
+ " (" + InschrijvingTabel.ID
+ " INTEGER PRIMARY KEY,"
+ InschrijvingTabel.LESPLAATS
+ " TEXT, "
+ InschrijvingTabel.OPLEIDING
+ " TEXT, "
+ InschrijvingTabel.Module
+ " TEXT, "+ InschrijvingTabel.AANTAL+" INTEGER"+");"
);
}
public interface InschrijvingTabel {
String ID="_id";
String Module = "_module";
String TABEL_NAAM = "TBL_INSCHRIJVING1";
String AANTAL="_aantal";
String OPLEIDING="_opleiding";
String LESPLAATS="_lesplaats";
}
public class InschrijvingDB extends SchemaHelper {
public InschrijvingDB(Context context) {
super(context);
}
public void adVakken()
{
SQLiteDatabase sd=getWritableDatabase();
// String xx=x.getModule();
// sd.rawQuery("insert into "+InschrijvingTabel.TABEL_NAAM+"("+ InschrijvingTabel.Module+") values("+xx+")",null);
// sd.rawQuery("insert into "+InschrijvingTabel.TABEL_NAAM+"(_module) values('cc')",null);
}
public class contentPV extends ContentProvider {
static final String PROVIDER_NAME = "com.example.derae.lessenrooster.databank.contentPV";
static final String URL = "content://" + PROVIDER_NAME + "/*";
static final Uri CONTENT_URI = Uri.parse(URL);
#Override
public boolean onCreate() {
Context context = getContext();
InschrijvingDB x= new InschrijvingDB(context);
return false;
}
#Nullable
#Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
return null;
}
#Nullable
#Override
public String getType(Uri uri) {
return null;
}
#Nullable
#Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
#Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
}
If you're using 1 database that has all the tables you want to use and you're logging in to that database from app 2, then you should be able to access every table there.
Try debugging techniques to see what's going wrong with app 2, like print debugging.
If you can connect to your database normally from app2, then check if there's anything wrong with your Queries to get data from the desired table. Break your problem down into parts.
-I'm sorry if this is not helpful enough, I'm no expert myself, but I hope my tips help you discover the problem yourself.
Related
I'm working on an Android application in Java. In my application I need, among other things, to store an address in a database. My address is stored in a table named "adresse". This table is defined as below:
CREATE TABLE "adresse" (
"numero_rue" TEXT,
"type_voie" TEXT,
"voie" TEXT,
"code_postal" TEXT,
"ville" TEXT
);
I've tried to insert an address in my table by two different methods:
public void setAdresse(String numRue, String typeVoie, String voie, String codePostal, String ville) {
// First one
ContentValues values = new ContentValues();
values.put("numero_rue" , numRue );
values.put("type_voie" , typeVoie );
values.put("voie" , voie );
values.put("code_postal", codePostal);
values.put("ville" , ville );
db.insert("adresse", null, values);
// Second one
String req = "insert into adresse (numero_rue, type_voie, voie, code_postal, ville) values";
req += "(\"" + numRue + "\",\"" + typeVoie + "\",\"" + voie + "\",\"" + codePostal + "\",\"" + ville + "\")";
db.execSQL(req);
}
I call the setAdresse(...) method in this method:
public void valider(View paramView) {
[ data recovery without problems ]
final DatabaseAccess db = DatabaseAccess.getInstance(this.getApplicationContext());
db.open();
db.setAdresse(numRue, typeVoie, voie, codePostal, ville);
db.close();
}
I show you my constructor, my open(), close() and getInstance() methods:
private DatabaseAccess(Context context) { this.openHelper = new DatabaseOpenHelper(context); }
public static DatabaseAccess getInstance(Context context) {
if( instance == null ) instance = new DatabaseAccess(context);
return instance;
}
public void open() { this.db = openHelper.getWritableDatabase(); }
public void close() { if( this.db != null ) this.db.close(); }
My problem is that inserting the data into the table is not working. I don't find errors in the logs and my application does not crash. I don't think it is a code error and someone told me it could be linked to my "driver utilisation".
can you check this link. It is a github sample project for inserting in sqlite table
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 2 years ago.
So I am getting
Attempt to invoke interface method 'int android.database.Cursor.getCount()' on a null object reference
when trying to get into my MovieDetailActivity to see MovieDetails with a Favourite Button. Based on the state of the movie (if it's favourited or not) the button should change its text accordingly to add or remove the movie to the favourites list.
But all I am getting is a crash when trying to entering the screen.
screenshot from the Logs
Here is my isMovieFavourited method:
public boolean isMovieFavourited(String id){
mSelectionClause = FavouritesContract.FavouritesAdd.COLUMN_MOVIE_ID + " = ?";
mSelectionArgs[0] = id;
Cursor mCursor = getContentResolver().query(
FavouritesContract.FavouritesAdd.CONTENT_URI,
mProjection,
mSelectionClause,
mSelectionArgs,
null);
if(mCursor.getCount() <= 0){
mCursor.close();
mFavourites.setText(getString(R.string.add_to_favourites));
return false;
}
mCursor.close();
mFavourites.setText(getString(R.string.remove_from_favourites));
return true;
}
Here is my FavouritesContract class:
public class FavouritesContract {
public static final String AUTHORITY = "com.riceplant.popularmovies";
public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + AUTHORITY);
public static final String PATH_FAVOURITES = "favourites";
public static final class FavouritesAdd implements BaseColumns {
public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon()
.appendPath(PATH_FAVOURITES)
.build();
public static final String TABLE_NAME = "favorites";
public static final String COLUMN_MOVIE_ID = "movieId";
public static final String COLUMN_MOVIE_NAME = "movieName";
public static final String COLUMN_MOVIE_POSTER = "moviePoster";
public static final String COLUMN_MOVIE_RATE = "movieRate";
public static final String COLUMN_MOVIE_RELEASE = "movieRelease";
public static final String COLUMN_MOVIE_OVERVIEW = "movieOverview";
}
}
EDIT:
Here is my Content Provider class:
public class FavouritesContentProvide extends ContentProvider{
public static final int FAVOURITES = 700;
public static final int FAVOURITES_WITH_ID = 701;
private static final UriMatcher sUriMatcher = buildUriMatcher();
private static UriMatcher buildUriMatcher() {
UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(FavouritesContract.AUTHORITY, FavouritesContract.PATH_FAVOURITES, FAVOURITES);
uriMatcher.addURI(FavouritesContract.AUTHORITY, FavouritesContract.PATH_FAVOURITES + "/#", FAVOURITES_WITH_ID);
return uriMatcher;
}
private FavouritesDbHelper mFavouritesDbHelper;
#Override
public boolean onCreate() {
Context context = getContext();
mFavouritesDbHelper = new FavouritesDbHelper(context);
return true;
}
#Nullable
#Override
public Cursor query(#NonNull Uri uri, #Nullable String[] projection, #Nullable String selection, #Nullable String[] selectionArgs, #Nullable String sortOrder) {
final SQLiteDatabase db = mFavouritesDbHelper.getReadableDatabase();
int match = sUriMatcher.match(uri);
Cursor returnCursor;
switch (match){
case FAVOURITES:
returnCursor = db.query(TABLE_NAME,
projection,
selection,
selectionArgs,
null,
null,
sortOrder);
break;
case FAVOURITES_WITH_ID:
String id = uri.getPathSegments().get(1);
String mSelection = "_id=?";
String[] mSelectionArgs = new String[]{id};
returnCursor = db.query(TABLE_NAME,
projection,
mSelection,
mSelectionArgs,
null,
null,
sortOrder);
break;
default:
throw new UnsupportedOperationException("Unknown uri: "+ uri);
}
returnCursor.setNotificationUri(getContext().getContentResolver(), uri);
return returnCursor;
}
#Nullable
#Override
public String getType(#NonNull Uri uri) {
int match = sUriMatcher.match(uri);
switch (match){
case FAVOURITES:
return "vnd.android.cursor.dir" + "/" + FavouritesContract.AUTHORITY + "/" + FavouritesContract.PATH_FAVOURITES;
case FAVOURITES_WITH_ID:
return "vnd.android.cursor.item" + "/" + FavouritesContract.AUTHORITY + "/" + FavouritesContract.PATH_FAVOURITES;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
}
#Nullable
#Override
public Uri insert(#NonNull Uri uri, #Nullable ContentValues values) {
final SQLiteDatabase db = mFavouritesDbHelper.getWritableDatabase();
int match = sUriMatcher.match(uri);
Uri returnUri; //Uri to be returned
switch (match){
case FAVOURITES:
long id = db.insert(TABLE_NAME, null, values);
if (id > 0 ){
returnUri = ContentUris.withAppendedId(FavouritesContract.FavouritesAdd.CONTENT_URI, id);
} else {
throw new android.database.SQLException("Failed to insert row into" + uri);
}
break;
default:
throw new UnsupportedOperationException("Unknow uri: " +uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return returnUri;
}
#Override
public int delete(#NonNull Uri uri, #Nullable String selection, #Nullable String[] selectionArgs) {
final SQLiteDatabase db = mFavouritesDbHelper.getWritableDatabase();
int match = sUriMatcher.match(uri);
int favoritesDeleted;
switch (match) {
case FAVOURITES:
favoritesDeleted = db.delete(TABLE_NAME, selection, selectionArgs);
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
if (favoritesDeleted != 0){
getContext().getContentResolver().notifyChange(uri,null);
}
return favoritesDeleted;
}
#Override
public int update(#NonNull Uri uri, #Nullable ContentValues values, #Nullable String selection, #Nullable String[] selectionArgs) {
int favoriteUpdated;
int match = sUriMatcher.match(uri);
switch (match){
case FAVOURITES_WITH_ID:
String id = uri.getPathSegments().get(1);
favoriteUpdated = mFavouritesDbHelper.getWritableDatabase()
.update(TABLE_NAME, values, "_id=?", new String[]{id});
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
if (favoriteUpdated != 0){
getContext().getContentResolver().notifyChange(uri, null);
}
return favoriteUpdated;
}
}
Here is the Dbhelper class:
public class FavouritesDbHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "favourites.db";
private static final int DATABASE_VERSION = 3;
public FavouritesDbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
final String SQL_CREATE_FAVOURITES_TABLE = "CREATE TABLE " +
FavouritesAdd.TABLE_NAME + " (" +
FavouritesAdd._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
FavouritesAdd.COLUMN_MOVIE_ID + " INTEGER NOT NULL," +
FavouritesAdd.COLUMN_MOVIE_NAME + " TEXT NOT NULL," +
FavouritesAdd.COLUMN_MOVIE_POSTER + " TEXT NOT NULL," +
FavouritesAdd.COLUMN_MOVIE_RATE + " TEXT NOT NULL," +
FavouritesAdd.COLUMN_MOVIE_RELEASE + " TEXT NOT NULL," +
FavouritesAdd.COLUMN_MOVIE_OVERVIEW + " TEXT NOT NULL" +
"); ";
sqLiteDatabase.execSQL(SQL_CREATE_FAVOURITES_TABLE);
}
#Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + FavouritesAdd.TABLE_NAME);
onCreate(sqLiteDatabase);
}
}
I am pretty new to this, so please don't hesitate to ask if you need more code samples or anything else.
Thanks in advance!
There are 3 circumstances where the ContentResolver.query method can return null (and yes it is documented that it can return null):
The Uri provider cannot be acquired.
The provider query returned null.
A RemoteException occurred executing the query.
(You can see for yourself in source of ContentResolver.java)
(2) seems unlikely given your code posted. (I glanced at it and it seems like a null result would not be possible - and in theory an SQLiteDatabase.query() can never return null and even if it did you'd get a null pointer at the setNotificationUri call which you didn't.)
(3) cannot comment based on info provided - most likely would mean your provider is accessed across a network or other link.
However
(1) Is worth investigating - does the URI provided actually define a configured provider. Specifically - did you define a <provider> element in your manifest file - reference here . If so then add that portion of the manifest to your post. Have you done anything with the provider successfully? If yes then perhaps the particular URI is not quite right.
EDIT: I still can't find a solution to this issue. For some reason, the database that is queried is empty, despite being full and in the correct place. If you can see any issue with my database helper or anything else that I could try, I would be very grateful.
I am developing an app that returns information from an SQLite database relating to species of bird. When I query this database, I am getting error messages: 'SQLiteLog: (1) no such column: 'size'' etc.
I have verified that my rawQuery() queries are well formed and should be returning the info that I expect by running the queries in an SQLite browser, and by consulting advice on Stackoverflow. I have tried to use the alternative database asset class, SQLiteAssetHelper, but have had the same problems as I have with SQLiteOpenHelper.
I am thinking it may be related to:
the testing phone - Moto g6 play - this phone is not rooted. Could this be an issue migrating the database over to the phone for use by the app during testing?
The formation of the database - this was populated by a python script written by me. Could some metadata etc be malformed or incompatible?
package com.example.newbuild;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class DatabaseHelper extends SQLiteOpenHelper {
//db info
private static final String DATABASE_NAME = "birdsDB.db";
// FileInputStream fis = new FileInputStream(new File(DATABASE_NAME));
// Log info for debugging:
private static final String TAG = "DatabaseHelper";
// set variables to name database
private static final int DATABASE_VERSION = 3;
// name of table 1:
private static final String MAIN_TABLE = "main";
// name of bird image table:
private static final String PIC_TABLE = "picLinks";
// names of MAIN columns:
private static final String ID = "id";
private static final String COMMON = "common";
private static final String SCINAME = "sciname";
private static final String FAMILY = "family";
private static final String BIRDCATEG = "category";
private static final String SIZE = "size";
private static final String DESC = "description";
private static final String RANGEPIC = "rangepicid";
private static final String SIGHTED = "sighted";
// names of BIRD IMAGE columns
private static final String BIRD_IMAGE_NO = "picKey";
private static final String BIRD_ID = "birdId";
private static final String IMAGE_LINK = "link";
private Context mContext;
private SQLiteDatabase mDB;
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
Log.i(TAG, "now calling database helper");
}
#Override
public void onCreate(SQLiteDatabase db) {
Log.d(TAG, "attempting to create table from onCreate");
String CREATE_MAIN_TABLE =
"CREATE TABLE " +
MAIN_TABLE +
"(" +
ID + "INTEGER PRIMARY KEY," +
COMMON + " TEXT," +
SCINAME + " TEXT," +
FAMILY + "TEXT," +
BIRDCATEG + "TEXT," +
SIZE + "TEXT," +
DESC + "TEXT," +
RANGEPIC + "TEXT," +
SIGHTED + "TEXT" +
")";
db.execSQL(CREATE_MAIN_TABLE);
Log.d("table", CREATE_MAIN_TABLE);
}
#Override
public void onUpgrade(SQLiteDatabase db, int i, int i1) {
Log.i(TAG, "now calling onUpgrade");
db.execSQL("DROP TABLE IF EXISTS " + MAIN_TABLE);
onCreate(db);
}
}
public ArrayList<String> getCategory(String[] name) {
String TABLE_BIRDS = "main";
ArrayList<String> categories = new ArrayList<>();
if (name[0] != null) {
Log.d(LOG_TAG, name[0]);
} else {
Log.d(LOG_TAG, "name[0] has not been passed");
}
Log.d(LOG_TAG, "SELECT DISTINCT " + name[0] + " FROM " + TABLE_BIRDS);
Cursor x = db.rawQuery("SELECT DISTINCT " + name[0] + " FROM " + TABLE_BIRDS, null);
if (x.getCount() == 0) {
Log.i(LOG_TAG, "The cursor is not returning any data");
}
while (x.moveToNext()) {
String category = x.getString(0);
categories.add(category);
Log.i("cursor loop", category);
}
return categories;
}
When the above code is passed the string 'category', my database should return six strings of different categories of bird species. Instead, I find error messages including 'E/SQLiteLog: (1) no such column: category'.
I am thinking it may be related to: the testing phone - Moto g6 play -
this phone is not rooted. Could this be an issue migrating the
database over to the phone for use by the app during testing?
I don't think so as you would typically get a table not found before a column not found.
I'd suggest temporarily changing the query to :-
Cursor x = db.rawQuery("SELECT * FROM " + TABLE_BIRDS + " LIMIT 10", null);
Followed by :-
DatabaseUtils.dumpCursor(x);
The first change will extract all columns from 10 rows from the table.
The second line will output the data in the cursor to the log, including the column names.
I suspect that the column names are incorrect or missing. In which case you need to ensure that the file in the assets folder is correct, when it is make sure that you delete the database (delete the Apps data or uninstall the App) and then rerun the App.
I am asking this because I am not quite sure of how to work with Android Content Providers. I have a subset of my database with 8 tables and I need to create complex queries to get some of the data. My content provider works fine with simple queries. For example, I have a table Person on my PersonModel.java class and I get the data using:
String [] projection = {PersonModel.C_FIRST_NAME, PersonModel.C_LAST_NAME};
Cursor cursor = context.getContentResolver().query(
MyProvider.CONTENT_URI_PERSONS, projection, null,
null, null);
and it works perfectly.
On MyProvider I have a bunch of CONTENT_URI constants, on for each of my tables.
public class MyProvider extends ContentProvider {
MyDbHelper dbHelper;
SQLiteDatabase db;
private static final String AUTHORITY = "com.myapp.models";
//Paths for each tables
private static final String PATH_PROFILE_PICTURES = "profile_pictures";
private static final String PATH_PERSONS = "persons";
private static final String PATH_USERS = "users";
....
//Content URIs for each table
public static final Uri CONTENT_URI_PROFILE_PICTURES = Uri
.parse("content://" + AUTHORITY + "/" + PATH_PROFILE_PICTURES);
public static final Uri CONTENT_URI_PERSONS = Uri.parse("content://"
+ AUTHORITY + "/" + PATH_PERSONS);
public static final Uri CONTENT_URI_USERS = Uri.parse("content://"
+ AUTHORITY + "/" + PATH_USERS);
...
private static final int PROFILE_PICTURES = 1;
private static final int PROFILE_PICTURE_ID = 2;
private static final int PERSONS = 3;
private static final int PERSON_ID = 4;
private static final int USERS = 5;
private static final int USER_ID = 6;
private static final UriMatcher sURIMatcher = new UriMatcher(
UriMatcher.NO_MATCH);
static {
sURIMatcher.addURI(AUTHORITY, PATH_PROFILE_PICTURES, PROFILE_PICTURES);
sURIMatcher.addURI(AUTHORITY, PATH_PROFILE_PICTURES + "/#",
PROFILE_PICTURE_ID);
sURIMatcher.addURI(AUTHORITY, PATH_PERSONS, PERSONS);
sURIMatcher.addURI(AUTHORITY, PATH_PERSONS + "/#", PERSON_ID);
sURIMatcher.addURI(AUTHORITY, PATH_USERS, USERS);
sURIMatcher.addURI(AUTHORITY, PATH_USERS + "/#", USER_ID);
...
}
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// Uisng SQLiteQueryBuilder instead of query() method
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
// check if the caller has requested a column which does not exists
//checkColumns(projection);
int uriType = sURIMatcher.match(uri);
switch (uriType) {
case PROFILE_PICTURES:
queryBuilder.setTables(ProfilePictureModel.TABLE_PROFILE_PICTURE);
break;
case PROFILE_PICTURE_ID:
// Adding the ID to the original query
queryBuilder.appendWhere(ProfilePictureModel.C_ID + "="
+ uri.getLastPathSegment());
case PERSONS:
queryBuilder.setTables(PersonModel.TABLE_PERSON);
break;
case PERSON_ID:
// Adding the ID to the original query
queryBuilder.appendWhere(PersonModel.C_ID + "="
+ uri.getLastPathSegment());
case USERS:
queryBuilder.setTables(UserModel.TABLE_USER);
break;
case USER_ID:
// Adding the ID to the original query
queryBuilder.appendWhere(UserModel.C_ID + "="
+ uri.getLastPathSegment());
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
db = dbHelper.getWritableDatabase();
Cursor cursor = queryBuilder.query(db, projection, selection,
selectionArgs, null, null, sortOrder);
// make sure that potential listeners are getting notified
cursor.setNotificationUri(getContext().getContentResolver(), uri);
}
That is a small part of my content provider. So my questions are:
1) How do I implement a rawQuery() in my content provider? or how do I use properly my queryBuilder?, let's say I want to execute this query using several tables, renaming them and also passing the p1.id as a parameter?
SELECT p1.first_name, p1_last_name
FROM Person p1, Person P2, Relationship r
WHERE p1.id = ? AND
p1.id = r.relative_id AND
p2.id = r.related_id;
I tried so by doing this: On my query() method (shown above) I have a new case, called GET_RELATIVES:
case GET_RELATIVES:
db = dbHelper.getWritableDatabase();
queryBuilder.setTables(PersonModel.TABLE_PERSON + " p1, "
+ PersonModel.TABLE_PERSON + " p2, "
+ RelationshipModel.TABLE_RELATIONSHIP + " r");
queryBuilder.appendWhere("p2."+PersonModel.C_ID + "=" + uri.getLastPathSegment());
queryBuilder.appendWhere("p2."+PersonModel.C_ID + "=" + "r.related_id");
queryBuilder.appendWhere("p1."+PersonModel.C_ID + "=" + "r.relative_id");
so I defined a new PATH, CONTENT URI and add it to the UriMatcher, like this:
private static final String PATH_GET_RELATIVES = "get_relatives";
public static final Uri CONTENT_URI_GET_RELATIVES = Uri
.parse("content://" + AUTHORITY + "/"
+ PATH_GET_RELATIVES);
private static final int GET_RELATIVES = 22;
private static final UriMatcher sURIMatcher = new UriMatcher(
UriMatcher.NO_MATCH);
static {
...
sURIMatcher.addURI(AUTHORITY, PATH_GET_RELATIVES, GET_RELATIVES);
}
but this does not seem to work so I think I'm probably defining something wrong on my content provider or inside the query method.
2) I am not quite sure what is the point on having for each table a constant called TABLE_ID and adding it to the switch-case. What is that used for? How do I call it?
Hope anyone can help me with this, thanks in advance!
I actually found the answer to my question in the most obvious place: the android documentation.
First Question: Implement a rawQuery. Did it like this:
Inside of my switch-case in the content provider I added a new URI, which for me is a JOIN between to tables, so I created a new ContentUri constant for it, a new ID, and registered it on the UriMatcher and then wrote the rawQuery. So MyProvider now looks a litte bit like this:
public class MyProvider extends ContentProvider {
...
// JOIN paths
private static final String PATH_RELATIONSHIP_JOIN_PERSON_GET_RELATIVES =
"relationship_join_person_get_relatives";
...
public static final Uri CONTENT_URI_RELATIONSHIP_JOIN_PERSON_GET_RELATIVES = Uri
.parse("content://" + AUTHORITY + "/"
+ PATH_RELATIONSHIP_JOIN_PERSON_GET_RELATIVES);
...
private static final int RELATIONSHIP_JOIN_PERSON_GET_RELATIVES = 21;
private static final UriMatcher sURIMatcher = new UriMatcher(
UriMatcher.NO_MATCH);
static {
...
//JOINS
sURIMatcher.addURI(AUTHORITY, PATH_RELATIONSHIP_JOIN_PERSON_GET_RELATIVES + "/#",
RELATIONSHIP_JOIN_PERSON_GET_RELATIVES);
...
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// Uisng SQLiteQueryBuilder instead of query() method
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
// check if the caller has requested a column which does not exists
//checkColumns(projection);
int uriType = sURIMatcher.match(uri);
switch (uriType) {
...
case RELATIONSHIP_JOIN_PERSON_GET_RELATIVES:
db = dbHelper.getWritableDatabase();
String[] args = {String.valueOf(uri.getLastPathSegment())};
Cursor cursor = db.rawQuery(
"SELECT p1.first_name, p1.last_name " +
"FROM Person p1, Person p2, Relationship r " +
"WHERE p1.id = r.relative_id AND " +
"p2.id = r.related_id AND " +
"p2.id = ?", args);
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
...
}
And to call the query() method and pass the id ad a parameter I did this in my controller:
String[] projection = { PersonModel.C_FIRST_NAME,
PersonModel.C_LAST_NAME };
Cursor cursor = context.getContentResolver().query(
ContentUris.withAppendedId(
AkdemiaProvider.CONTENT_URI_RELATIONSHIP_JOIN_PERSON_GET_RELATED, id),
projection, null, null, null);
Second question: Having the TABLE_ID constant is useful to have a query for each table passing an id as a parameter, I didn't know how to call the query method passing such id and this is how the Android Developer Documentation explains how to do so using ContentUris.withAppendedId
// Request a specific record.
Cursor managedCursor = managedQuery(
ContentUris.withAppendedId(Contacts.People.CONTENT_URI, 2),
projection, // Which columns to return.
null, // WHERE clause.
null, // WHERE clause value substitution
People.NAME + " ASC"); // Sort order.
I you guys want to see the whole documentation go to this link.
Hope this helps to anyone else having the same problem to understand ContentProvider, ContentUris and all that :)
Below code worked for me. Inside your Application's Content Provider:
public static final String PATH_JOIN_TWO_TABLES = "my_path";
public static final Uri URI_JOIN_TWO_TABLES =
Uri.parse("content://" + AUTHORITY + "/" + PATH_JOIN_TWO_TABLES);
private static final int ID_JOIN_TWO_TABLES = 1001;
private static final UriMatcher sURIMatcher = new UriMatcher(
UriMatcher.NO_MATCH);
static {
sURIMatcher.addURI(AUTHORITY,
PATH_JOIN_TWO_TABLES + "/#", ID_JOIN_TWO_TABLES );
}
#Nullable
#Override
public Cursor query(#NonNull Uri uri, String[] projection, String selection,String[] selectionArgs,
String sortOrder, CancellationSignal cancellationSignal) {
int uriType = sURIMatcher.match(uri);
switch (uriType) {
case ID_JOIN_TWO_TABLES:
return getWritableDatabase()
.rawQuery("select * from " +
"table_one" + " LEFT OUTER JOIN "
+ "table_two" + " ON ("
+ "table_one.ID"
+ " = " + "table_two.id" + ")", null);
}
return super.query(uri, projection, selection, selectionArgs, sortOrder, cancellationSignal);
}
And while making the Query inside your Activity or Fragment:
Cursor cursor = getActivity().getContentResolver()
.query(ContentUris.withAppendedId(MYContentProvider.URI_JOIN_TWO_TABLES, MyContentProvider.ID_JOIN_TWO_TABLES), null, null, null, null);
Hope it works for you.
For simple queries use selectionArgs in ContentProvider. It works like below
String[] args = { "first string", "second#string.com" };
Cursor cursor = db.query("TABLE_NAME", null, "name=? AND email=?", args, null);
Having the TABLE_ID inside the to create a different queries for each table.
Refer following class for all multiple table in content providers
Vogella Tutorial 1
Vogella Tutorial 2
Best practices for exposing multiple tables using content providers in Android
I am trying to insert into my database table using the database helper class.
this is where I create the object to insert.
Item item1;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
db = new MyDBAdapter(this);
db.insertEntry(item1 = new Item("Bathtub", "Bathroom", "Typical", "Clean", "fill, wash", "Round, deep", "Bathroom", "Toilet, Bathroom", R.drawable.ic_launcher));
Log.i("item", "item: " + item1.toString());
And this is the Item class
public class Item {
//private variables
int _id;
String _item_name;
String _item_classification;
String _group;
String _use;
String _action;
String _properties;
String _location;
String _association;
int _img_id;
//Empty constructor
public Item(){
}
//constructor
public Item (int _id, String _item_name, String _group, String _item_classification, String _use, String _action, String _properties, String _location, String _association, int _img_id) {
this._id = _id;
this._item_name = _item_name;
this._item_classification = _item_classification;
this._group = _group;
this._use = _use;
this._action = _action;
this._properties = _properties;
this._location = _location;
this._association = _association;
this._img_id = _img_id;
}
public Item (String _item_name, String _group, String _item_classification, String _use, String _action, String _properties, String _location, String _association, int _img_id) {
this._item_name = _item_name;
this._item_classification = _item_classification;
this._group = _group;
this._use = _use;
this._action = _action;
this._properties = _properties;
this._location = _location;
this._association = _association;
this._img_id = _img_id;
with getters and setters of course.Now when i use the insert method for my database helper i get an error that is saying syntax error near "group". Why is my insert failing?
public class MyDBAdapter {
private static final String DATABASE_NAME = "myDatabase.db";
private static final String DATABASE_TABLE = "mainTable";
private static final int DATABASE_VERSION = 1;
//main table columns
public static final String KEY_ITEM = "item_name";
public static final String KEY_GROUP = "group";
public static final String ITEM_CLASSIFICATION = "classification";
public static final String KEY_USE = "use";
public static final String KEY_ACTION = "action";
public static final String KEY_PROPERTIES = "properties";
public static final String KEY_ASSOCIATION = "association";
public static final String KEY_IMG_ID = "img_id";
// The index (key) column name for use in where clauses.
public static final String KEY_ID="_id";
// The name and column index of each column in your database.
public static final int NAME_COLUMN = 1;
public static final int GROUP_COLUMN = 2;
public static final int CLASSIFICATION_COLUMN = 3;
public static final int USE_COLUMN = 4;
public static final int ACTION_COLUMN = 5;
public static final int PROPERTIES_COLUMN = 6;
public static final int ASSOCIATION_COLUMN = 7;
public static final int IMG_ID_COLUMN = 8;
// TODO: Create public field for each column in your table.
// SQL Statement to create a new database.
private static final String DATABASE_CREATE = "create table " +
DATABASE_TABLE + " ("
+ KEY_ID + " integer primary key autoincrement, "
+ KEY_ITEM + " TEXT, "
+ KEY_GROUP + " TEXT, "
+ ITEM_CLASSIFICATION + " TEXT, "
+ KEY_USE + " TEXT, "
+ KEY_ACTION + " TEXT, "
+ KEY_PROPERTIES + " TEXT, "
+ KEY_ASSOCIATION + " TEXT, "
+ KEY_IMG_ID + " INTEGER);";
// Variable to hold the database instance
private SQLiteDatabase db;
// Context of the application using the database.
private final Context context;
// Database open/upgrade helper
private myDbHelper dbHelper;
public MyDBAdapter(Context _context) {
context = _context;
dbHelper = new myDbHelper(context, DATABASE_NAME, null, DATABASE_VERSION);
}
public MyDBAdapter open() throws SQLException {
try {
db = dbHelper.getWritableDatabase();
} catch (SQLiteException e) {
db = dbHelper.getReadableDatabase();
}
return this;
}
public void close() {
db.close();
}
public void insertEntry(Item item) {
// TODO: Create a new ContentValues to represent my row
// and insert it into the database.
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_ITEM, item.get_item_name());
values.put(KEY_GROUP, item.get_group());
values.put(ITEM_CLASSIFICATION, item.get_item_classification());
values.put(KEY_USE, item.get_use());
values.put(KEY_ACTION, item.get_action());
values.put(KEY_PROPERTIES, item.get_properties());
values.put(KEY_ASSOCIATION, item.get_association());
values.put(KEY_IMG_ID, item.get_img_id());
// insert row to table
try{
db.insertOrThrow(DATABASE_TABLE, null, values);
}catch (Exception e){Log.w("insertFail", "insert failed: " + e.toString());}
db.close();
}
I get a syntax error-->sqlite returned: error code = 1, msg = near "group": syntax error
You are forgetting a space after your column names. Change,
private static final String DATABASE_CREATE = "create table " +
DATABASE_TABLE + " (" + KEY_ID +
" integer primary key autoincrement, " +
KEY_ITEM + " text not null, " + KEY_GROUP + "TEXT, " +
ITEM_CLASSIFICATION + "TEXT, " + KEY_USE + "TEXT, " +
KEY_ACTION + "TEXT, " + KEY_PROPERTIES + "TEXT" +
KEY_ASSOCIATION + "TEXT," + KEY_IMG_ID + "INTEGER" + ");";
to
private static final String DATABASE_CREATE = "create table " +
DATABASE_TABLE + " (" + KEY_ID +
" integer primary key autoincrement, " +
KEY_ITEM + " text not null, " + KEY_GROUP + " TEXT, " +
ITEM_CLASSIFICATION + " TEXT, " + KEY_USE + " TEXT, " +
KEY_ACTION + " TEXT, " + KEY_PROPERTIES + " TEXT, " +
KEY_ASSOCIATION + " TEXT," + KEY_IMG_ID + " INTEGER" + ");";
(note the space added before TEXT and INTEGER).
You are creating a string like:
...integer primary key autoincrement, item_name text not null, groupTEXT, classificationTEXT, useTEXT, actionTEXT, propertiesTEXT... (sic).
See the problem?
I was using "group" for on of my column names in my table. Apparently there is an issue with this. I am guessing that "group" is a reserved word for SQLite for android. so if anyone else runs into this issue try changing the column name. Hope this is helpful.