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
Related
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 facing one problem and not getting solution on internet.
I am able to list all user profile contacts but its not showing contacts from work profile.
please refer to below links for detail about work profile
https://support.google.com/work/android/answer/6191949?hl=en
https://support.google.com/work/android/answer/7029561?hl=en
`
private static final String[] PROJECTION =
{
Contacts._ID,
Contacts.LOOKUP_KEY,
Build.VERSION.SDK_INT
>= Build.VERSION_CODES.HONEYCOMB ?
Contacts.DISPLAY_NAME_PRIMARY :
Contacts.DISPLAY_NAME
};
private static final String SELECTION =
Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ?
Contacts.DISPLAY_NAME_PRIMARY + " LIKE ?" :
Contacts.DISPLAY_NAME + " LIKE ?";
#Override
public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) {
/*
* Makes search string into pattern and
* stores it in the selection array
*/
mSelectionArgs[0] = "%" + mSearchString + "%";
// Starts the query
return new CursorLoader(
getActivity(),
Contacts.CONTENT_URI,
PROJECTION,
SELECTION,
mSelectionArgs,
null
);
}
`
For example: i have a contact with name "todd" in normal profile on the other hand i have a "tom" in contact under my work profile. Now in native message app during compose it shows todd and tomm both. i want same to happen in my implementation.
How should i get work profile contacts?
refer to the code below that solved my problem
private static final String[] PROJECTION_ENTERPRISE = new String[]{
ContactsContract.Contacts._ID,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.DATA1,
ContactsContract.CommonDataKinds.Phone.MIMETYPE,
ContactsContract.CommonDataKinds.Phone.TYPE,
ContactsContract.CommonDataKinds.Phone.LABEL
};
#RequiresApi(api = Build.VERSION_CODES.N)
private Cursor getEnterpriseContact(String searchString, String[] cols, ContactSearchType mContactSearchType, String digits, String sortOrder) {
// Get the ContentResolver
ContentResolver cr = mContext.getContentResolver();
// Get the Cursor of all the contacts
Uri phoneUri = ContactsContract.CommonDataKinds.Phone.ENTERPRISE_CONTENT_FILTER_URI.buildUpon().appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(ContactsContract.Directory.ENTERPRISE_DEFAULT)).build();
Uri phoneUriWithSearch = Uri.withAppendedPath(phoneUri, Uri.encode(searchString));
Cursor pCursor = cr.query(phoneUriWithSearch, cols, null, null, sortOrder);
Cursor workCur = null;
if (mContactSearchType != ContactSearchType.CONTACT_WITH_PHONE_NO) {
Uri emailUri = ContactsContract.CommonDataKinds.Email.ENTERPRISE_CONTENT_FILTER_URI.buildUpon().appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(ContactsContract.Directory.ENTERPRISE_DEFAULT)).build();
Uri emailUriWithSearch = Uri.withAppendedPath(emailUri, Uri.encode(searchString));
Cursor eCursor = cr.query(emailUriWithSearch, cols, null, null, sortOrder);
workCur = new MergeCursor(new Cursor[]{pCursor, eCursor});
} else {
workCur=pCur;
}
return workCur;
}
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.
I'm working on a Searchable dictionary. Its Raw database is separated by "-" like
ColumnA(Key_Word) ColumnB(Key_defination)
Apple - One kind of Fruit
Mango - One fruit also
But I want to make it 3 column, (Column C will be Key_details)
ColumnA ColumnB ColumnC (Key_details)
Apple - One kind of Fruit - Round shape
Mango - One fruit also - Found in Bangladesh
When people search A, application will show Column B and C. The reason why i splited string is I want to show Coumn B and C on different window. How to do that? Here is my source-
/**
* Contains logic to return specific words from the dictionary, and
* load the dictionary table when it needs to be created.
*/
public class DictionaryDatabase {
private static final String TAG = "DictionaryDatabase";
//The columns we'll include in the dictionary table
public static final String KEY_WORD = SearchManager.SUGGEST_COLUMN_TEXT_1;
public static final String KEY_DEFINITION = SearchManager.SUGGEST_COLUMN_TEXT_2;
private static final String DATABASE_NAME = "dictionary";
private static final String FTS_VIRTUAL_TABLE = "FTSdictionary";
private static final int DATABASE_VERSION = 2;
private final DictionaryOpenHelper mDatabaseOpenHelper;
private static final HashMap<String,String> mColumnMap = buildColumnMap();
public DictionaryDatabase(Context context) {
mDatabaseOpenHelper = new DictionaryOpenHelper(context);
}
private static HashMap<String,String> buildColumnMap() {
HashMap<String,String> map = new HashMap<String,String>();
map.put(KEY_WORD, KEY_WORD);
map.put(KEY_DEFINITION, KEY_DEFINITION);
map.put(BaseColumns._ID, "rowid AS " +
BaseColumns._ID);
map.put(SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID, "rowid AS " +
SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID);
map.put(SearchManager.SUGGEST_COLUMN_SHORTCUT_ID, "rowid AS " +
SearchManager.SUGGEST_COLUMN_SHORTCUT_ID);
return map;
}
public Cursor getWord(String rowId, String[] columns) {
String selection = "rowid = ?";
String[] selectionArgs = new String[] {rowId};
return query(selection, selectionArgs, columns);
}
public Cursor getWordMatches(String query, String[] columns) {
String selection = KEY_WORD + " MATCH ?";
String[] selectionArgs = new String[] {query+"*"};
return query(selection, selectionArgs, columns);
}
private Cursor query(String selection, String[] selectionArgs, String[] columns) {
SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
builder.setTables(FTS_VIRTUAL_TABLE);
builder.setProjectionMap(mColumnMap);
Cursor cursor = builder.query(mDatabaseOpenHelper.getReadableDatabase(),
columns, selection, selectionArgs, null, null, null);
if (cursor == null) {
return null;
} else if (!cursor.moveToFirst()) {
cursor.close();
return null;
}
return cursor;
}
private static class DictionaryOpenHelper extends SQLiteOpenHelper {
private final Context mHelperContext;
private SQLiteDatabase mDatabase;
private static final String FTS_TABLE_CREATE =
"CREATE VIRTUAL TABLE " + FTS_VIRTUAL_TABLE +
" USING fts3 (" +
KEY_WORD + ", " +
KEY_DEFINITION + ");";
DictionaryOpenHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
mHelperContext = context;
}
#Override
public void onCreate(SQLiteDatabase db) {
mDatabase = db;
mDatabase.execSQL(FTS_TABLE_CREATE);
loadDictionary();
}
private void loadDictionary() {
new Thread(new Runnable() {
public void run() {
try {
loadWords();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}).start();
}
private void loadWords() throws IOException {
Log.d(TAG, "Loading words...");
final Resources resources = mHelperContext.getResources();
InputStream inputStream = resources.openRawResource(R.raw.definitions);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
try {
String line;
while ((line = reader.readLine()) != null) {
String[] strings = TextUtils.split(line, "-");
if (strings.length < 2) continue;
long id = addWord(strings[0].trim(), strings[1].trim());
if (id < 0) {
Log.e(TAG, "unable to add word: " + strings[0].trim());
}
}
} finally {
reader.close();
}
Log.d(TAG, "DONE loading words.");
}
public long addWord(String word, String definition) {
ContentValues initialValues = new ContentValues();
initialValues.put(KEY_WORD, word);
initialValues.put(KEY_DEFINITION, definition);
return mDatabase.insert(FTS_VIRTUAL_TABLE, null, initialValues);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
+ newVersion + ", which will destroy all old data");
db.execSQL("DROP TABLE IF EXISTS " + FTS_VIRTUAL_TABLE);
onCreate(db);
}
}
}
String[] arr = string.split("-");
String#split(String regex)
Returns the array of strings computed by splitting this string around
matches of the given regular expression.
EDIT:
long id = addWord(strings[0].trim(), strings[1].trim());
Above line should be:
long id = addWord(strings[0].trim(), strings[1].trim(),strings[2].trim());
And change your addWord function as I mentioned below.
public long addWord(String word, String definition,String details) {
ContentValues initialValues = new ContentValues();
initialValues.put(KEY_WORD, word);
initialValues.put(KEY_DEFINITION, definition);
initialValues.put(KEY_DETAILS, details);
return mDatabase.insert(FTS_VIRTUAL_TABLE, null, initialValues);
}
A better way to handle the tokenization is by using StringTokenizer
StringTokenizer token = new StringTokenizer(str,"-");
To access the tokens,
while(token.hasNext())
{
String tmp = token.nextToken();
...
}