Hey guys,im working on a simple quiz and im gone crazy !!
The problem is that everything is working (database created as it shoulds) except when i am trying to get string from database shows java.lang.NullPointerException.I checked the uri is corrected and the number of items in array!!I am trying to find out why this is happening for 5 hours and i am stucked here!!!I dont know what elso to do!!Your help is more than appreciated!!
My main class where i am trying to get string is that one with bold
Uri newUri = ContentUris.withAppendedId(
QuestionsProvider.CONTENT_URI,
this.currentQuestion);
Log.d(TAG, "SHOWQUESTION " + " URI="+newUri.toString());
Cursor cursor = cr.query(newUri,
null, null, null, null);
if (cursor.moveToFirst()) {
**question.setText(cursor.getString(
QuestionsProvider.QUESTION_COLUMN)); //HERE I AM GETTING THE ERROR
currentAnswer = cursor.getString(
QuestionsProvider.ANSWER_COLUMN);**
submit.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
String text;
String answerGiven =
answer.getText().toString();
answer.setText("");
if (answerGiven.
equalsIgnoreCase(currentAnswer))
{text = "Correct";
}else{
text = "Wrong - "+currentAnswer;
Toast.makeText(getApplicationContext(),
text, Toast.LENGTH_SHORT).show();
}
}});
}
cursor.close();
dialog.show();
and in my manifest i add succesfully the provider and is loading as it should!!
Why this error happens??I can see anything wrong!!
It doesn't look like you're specifying a projection in the query:
Cursor cursor = cr.query(newUri, null, null, null, null);
Try adding a projection with the columns you want returned:
Cursor cursor = cr.query(newUri, new String[] {KEY_ID, KEY_QUESTION, KEY_ANSWER}, null, null, null);
I found the solution guys! Thank you for helping me unstucking heh :P
This is the solution i found!!
String columns[] = new String[] { QuestionsProvider.KEY_QUESTION, QuestionsProvider.KEY_ANSWER };
Uri mUri = QuestionsProvider.CONTENT_URI;
Cursor cur = managedQuery(mUri, columns, // Which columns to return
QuestionsProvider.KEY_ID+"="+currentQuestionNumber, // WHERE clause; which rows to return(all rows)
null, // WHERE clause selection arguments (none)
null // Order-by clause (ascending by name)
Related
So I'm having trouble getting the phone number of a contact using its id.
This is the code I'm using to retrieve the number:
public String getNumber(){
//gets numbers by id
if (hasPhoneNumber){
ContentResolver contentResolver=context.getContentResolver();
Cursor cursor=contentResolver.query(
ContactsContract.Contacts.CONTENT_URI,
null,
ContactsContract.Contacts._ID+" = "+id,
null,
null
); //TODO : resolve empty cursor error
//contact seems to have no data available?
if (cursor.moveToFirst()){
cursor.moveToNext();
String contactId=cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
Cursor phones=contentResolver.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID+" = "+contactId,
null,
null);
if (phones.moveToFirst()){
while (phones.moveToNext()) {
this.number=phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
}
}
phones.close();
} else {
test("cursor error...");
}
cursor.close();
return number;
} else {
return null;
}
}
It works with a few contacts but most show the "cursor error..." Toast (test("cursor error...") )
It's always the
Cursor cursor
that has the error.
My guess is it's empty but I know I have those contacts phone numbers saved. How do I fix this? Are there other values I have to request?
Thanks in advance!
EDIT:
this is how I retrieve ID and Name:
contactCursor=getActivity().getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
new String[]{
ContactsContract.Contacts._ID,//0 - Long
ContactsContract.Contacts.DISPLAY_NAME_PRIMARY,//1 - String
ContactsContract.Contacts.HAS_PHONE_NUMBER,//2 - Integer
},
null,
null,
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME+" ASC");
EDIT 2:
I have everything in a github repository: https://github.com/nicolas-d-torres/Syncc
The first block of Code is inside app/src/main/java/gtsarandum/syncc/SynccContact
the second in app/src/main/java/gtsarandum/syncc/ContactFragment
I know this answer is a little late but hopefully it will help someone else with a similiar issue. Both of your cursor queries use the id as a string
ContactsContract.Contacts._ID+" = "+id,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID+" = "+contactId,
should be
ContactsContract.Contacts._ID + " = " + Uri.encode(id),
ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = "+ Uri.encode(contactId),
I want to search if there are exact course_no, semester ,and year value in the table.
I problem is that I can only filter course_no.
Cursor cursor = database.query(DatabaseHelper.TABLE_COURSE, CourseItemDataSource.allColumns, DatabaseHelper.KEY_COURSE_COURSE_NO + "=?", new String[] { notiItem.getCourseNo() }, null, null, null);
When I tried to add other filter it doesn't seems to work
[Edited] Sorry for being not informative, the problem is that when I pass the below code filter don't work. Note that notiItem.getCourseNo() and notiItem.getYear() is a String.
The following column in the table is a TEXT.
Cursor cursor = database.query(DatabaseHelper.TABLE_COURSE, CourseItemDataSource.allColumns, DatabaseHelper.KEY_COURSE_COURSE_NO + "=? AND "+DatabaseHelper.KEY_COURSE_YEAR+"=?", new String[] { notiItem.getCourseNo() ,notiItem.getYear()}, null, null, null);
This is code the method I tried
public CourseItem searchToCourse(NotificationItem notiItem){
/**Check if exact course_no, semester, year of notiItem exist in Course Table
* return null if not found
*
*/
String [] columns = new String[]{ "*"};
Cursor cursor = database.query(DatabaseHelper.TABLE_COURSE, CourseItemDataSource.allColumns, DatabaseHelper.KEY_COURSE_COURSE_NO + "=?", new String[] { notiItem.getCourseNo() }, null, null, null);
Log.i("DATA SOURCE", "AFTER QUERY ");
if (cursor != null) {
cursor.moveToFirst();
}
CourseItem courseItem = CourseItemDataSource.cursorToCourseItem(cursor);
return courseItem;
}
How can I search multiple column at a time??
I'm trying to retrieve the metadata from a video file (title, language, artist) using the method MediaStore.Video.query(). However, the method is always returning null. The code is bellow:
String[] columns = {
MediaStore.Video.VideoColumns._ID,
MediaStore.Video.VideoColumns.TITLE,
MediaStore.Video.VideoColumns.ARTIST
};
Cursor cursor = MediaStore.Video.query(getApplicationContext().getContentResolver(), videoUri,columns);
if (cursor != null) {
cursor.moveToNext();
}
String title = cursor.getString(cursor.getColumnIndex(MediaStore.Video.VideoColumns.TITLE));
Any suggestion about how to return video metadata using android?
==Update
As I searched in many places, I tried one solution using CursorLoader. However, the method loadInBackground() from CursorLoader is also returning null. The code is showed bellow:
String[] columns = {
MediaStore.Video.VideoColumns.TITLE
};
Uri videoUri = Uri.parse("content://mnt/sdcard/Movies/landscapes.mp4");
CursorLoader loader = new CursorLoader(getBaseContext(), videoUri, columns, null, null, null);
Cursor cursor = loader.loadInBackground();
cursor.moveToFirst();
String title = cursor.getString(cursor.getColumnIndex(MediaStore.Video.VideoColumns.TITLE));
Uri.parse("content://mnt/sdcard/Movies/landscapes.mp4") is not an Uri for MediaStore. It would try to find a ContentProvider for authority mnt which does not exist.
MediaStore can handle only content://media/... Uris which you should get exclusively via MediaStore, not by using Uri.parse().
In your case use the following for example
Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
String[] columns = {
MediaStore.Video.VideoColumns._ID,
MediaStore.Video.VideoColumns.TITLE,
MediaStore.Video.VideoColumns.ARTIST
};
String selection = MediaStore.Video.VideoColumns.DATA + "=?";
String selectionArgs[] = { "/mnt/sdcard/Movies/landscapes.mp4" };
Cursor cursor = context.getContentResolver().query(uri, columns, selection, selectionArgs, null);
The MediaStore.Video.VideoColumns.DATA field holds the path to the videos and you search for a certain video this way. At least for now, future versions of Android may change that.
Your second example is using CursorLoader the wrong way. If you call loader.loadInBackground() yourself, you load the data in foreground. See e.g. http://mobile.tutsplus.com/tutorials/android/android-sdk_loading-data_cursorloader/
The next thing you do is
Cursor cursor = getCursor();
cursor.moveToFirst();
String title = cursor.getString(/* some index */);
This will lead to a CursorIndexOutOfBoundsException if your cursor has 0 rows and cursor.moveToFirst() failed because there is no first row. The cursor stays before the first row (at -1) and that index does not exist. That would mean in your case that the file was not found in the database.
To prevent that use the return value of moveToFirst - it will only be true if there is a first row.
Cursor cursor = getCursor(); // from somewhere
if (cursor.moveToFirst()) {
String title = cursor.getString(/* some index */);
}
A more complete example including checks for null and closing the cursor in all cases
Cursor cursor = getCursor(); // from somewhere
String title = "not found";
if (cursor != null) {
if (cursor.moveToFirst()) {
title = cursor.getString(/* some index */);
}
cursor.close();
}
I guess the file you try to find is either not indexed in the database (rebooting forces the indexer to run again) or the path is wrong.
Or the path you use is actually a symlink in which case MediaStore might use a different path.
Use this to get rid of symlinks
String path = "/mnt/sdcard/Movies/landscapes.mp4";
try {
path = new File(path).getCanonicalPath();
} catch (IOException e) {
e.printStackTrace();
}
Yes, I tested now and it is throwing IndexOutOfBoundsException. When I'm using cursor.getColumnCount() it returns 1
cursor.getColumnCount() is the column count, not the row count. It should always be the same as the number of columns you requested in columns. You need to check cursor.getCount() if you want to check the row count.
Try dumping all the videos known to MediaStore into logcat in case it does not show as expected.
public static void dumpVideos(Context context) {
Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
String[] projection = { MediaStore.Video.VideoColumns.DATA };
Cursor c = context.getContentResolver().query(uri, projection, null, null, null);
int vidsCount = 0;
if (c != null) {
vidsCount = c.getCount();
while (c.moveToNext()) {
Log.d("VIDEO", c.getString(0));
}
c.close();
}
Log.d("VIDEO", "Total count of videos: " + vidsCount);
}
I updated your code, it works, just check it
public static void dumpVideos(Context context) {
Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
String[] projection = { MediaStore.Video.VideoColumns.DATA };
Cursor c = context.getContentResolver().query(uri, projection, null, null, null);
int vidsCount = 0;
if (c != null) {
c.moveToFirst();
vidsCount = c.getCount();
do {
Log.d("VIDEO", c.getString(0));
}while (c.moveToNext());
c.close();
}
Log.d("VIDEO", "Total count of videos: " + vidsCount);
}
I need to pass a parameter from an EditText and when I click the button, it'll start another activity and get that parameter and pass it to a query. It follows:
final Button ara = (Button) findViewById(R.id.maddebutton);
ara.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
String maddeno = madde.getText().toString(); //madde is my EditText
Intent intent = new Intent(Anayasa.this, MaddeBul.class);
intent.putExtra("maddeler", maddeno);
startActivity(intent);
}
});
my second class is as follows:
Intent intent = getIntent();
int maddebul = intent.getIntExtra("maddeler", 0); //I don't want to set a default value but it pushes me
try {
Cursor cursor = FetchRecord(db.query("anayasa", SELECT,
"no = maddebul", null, null, null, null));
ShowRecord(cursor);
} finally {
database.close();
}
my FetchRecord(Cursor c) and ShowRecord(Cursor cursor) functions work fine, since I'm using them in other classes. There is "no" column in my "anayasa" database which holds integer values.
On LogCat, it says "no column such maddebul". It is true, there isn't. It suppose to be:
SELECT * FROM anayasa WHERE no = maddebul; //as sql command
Any help?
You are adding your extra as a String here:
intent.putExtra("maddeler", maddeno);
But when you try to retrieve the extra you are retrieving it as an int:
int maddebul = intent.getIntExtra("maddeler", 0);
Try using this insteald
String maddebul = intent.getStringExtra("maddeler", "");
For reference here are the docs for the getStringExtra() method.
On LogCat, it says "no column such maddebul". It is true, there isn't.
due to in whereClause "no = maddebul", maddebul is not a variable it is string part so change the whereClause to take it's value
Cursor cursor = FetchRecord(db.query("anayasa", SELECT,
"no = maddebul", null, null, null, null));
should be
Cursor cursor = FetchRecord(db.query("anayasa", SELECT,
"no = "+maddebul, null, null, null, null));
There are multiple problems:
You put maddebul as String here so need to get it like this:
String maddebul = intent.getStringExtra("maddeler", "");
Also you are forming your SQL query wrong, maddebul is passed as a String to the db, whereas you actually want to pass the value of that variable. So it could be like this instead:
Cursor cursor = FetchRecord(db.query("anayasa", SELECT,
"no = ?",new String[]{maddebul}, null, null, null));
you are writing maddebul in Double Quotes.
Replace
Cursor cursor = FetchRecord(db.query("anayasa", SELECT,
"no = maddebul", null, null, null, null));
By
Cursor cursor = FetchRecord(db.query("anayasa", SELECT,
"no = "+maddebul, null, null, null, null));
Better use following
Cursor cursor = FetchRecord(db.query("anayasa", SELECT,
"no = ?",new String[]{String.valueOf(maddebul)}, null, null, null));
You are put Extra as String and geting it as Integer - maybe that's the problem?
What would be the correct way to add DISTINCT and/or GROUPBY to ContentResolver-based queries?
Right now I have to create custom URI for each special case.
Is there a better way?
(I still program for 1.5 as lowest common denominator)
You can do nice hack when querying contentResolver, use:
String selection = Models.SOMETHING + "=" + something + ") GROUP BY (" + Models.TYPE;
If you want to use DISTINCT with SELECT more then one column, You need to use GROUP BY.
Mini Hack over ContentResolver.query for use this:
Uri uri = Uri.parse("content://sms/inbox");
Cursor c = getContentResolver().query(uri,
new String[]{"DISTINCT address","body"}, //DISTINCT
"address IS NOT NULL) GROUP BY (address", //GROUP BY
null, null);
if(c.moveToFirst()){
do{
Log.v("from", "\""+c.getString(c.getColumnIndex("address"))+"\"");
Log.v("text", "\""+c.getString(c.getColumnIndex("body"))+"\"");
} while(c.moveToNext());
}
This code select one last sms for each of senders from device inbox.
Note: before GROUP BY we always need to write at least one condition.
Result SQL query string inside ContentResolver.query method will:
SELECT DISTINCT address, body FROM sms WHERE (type=1) AND (address IS NOT NULL) GROUP BY (address)
Since no one came to answer I'm just going to tell how I solved this. Basically I would create custom URI for each case and pass the criteria in selection parameter. Then inside ContentProvider#query I would identify the case and construct raw query based on table name and selection parameter.
Here's quick example:
switch (URI_MATCHER.match(uri)) {
case TYPES:
table = TYPES_TABLE;
break;
case TYPES_DISTINCT:
return db.rawQuery("SELECT DISTINCT type FROM types", null);
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
return db.query(table, null, selection, selectionArgs, null, null, null);
In your overridden ContentProvider query method have a specific URI mapping to using distinct.
Then use SQLiteQueryBuilder and call the setDistinct(boolean) method.
#Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder)
{
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
boolean useDistinct = false;
switch (sUriMatcher.match(uri))
{
case YOUR_URI_DISTINCT:
useDistinct = true;
case YOUR_URI:
qb.setTables(YOUR_TABLE_NAME);
qb.setProjectionMap(sYourProjectionMap);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
// If no sort order is specified use the default
String orderBy;
if (TextUtils.isEmpty(sortOrder))
{
orderBy = DEFAULT_SORT_ORDER;
}
else
{
orderBy = sortOrder;
}
// Get the database and run the query
SQLiteDatabase db = mDBHelper.getReadableDatabase();
// THIS IS THE IMPORTANT PART!
qb.setDistinct(useDistinct);
Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy);
if (c != null)
{
// Tell the cursor what uri to watch, so it knows when its source data changes
c.setNotificationUri(getContext().getContentResolver(), uri);
}
return c;
}
Though I have not used Group By, I have used Distinct in content resolver query.
Cursor cursor = contentResolver
.query(YOUR_URI,
new String[] {"Distinct "+ YOUR_COLUMN_NAME},
null,
null, null);
Adding the Distinct keyword in the projection worked for me too, however, it only worked when the distinct keyword was the first argument:
String[] projection = new String[]{"DISTINCT " + DBConstants.COLUMN_UUID, ... };
In some condition, we can use "distinct(COLUMN_NAME)" as the selection,
and it work perfect.
but in some condition, it will cause a exception.
when it cause a exception, i will use a HashSet to store the column values....
// getting sender list from messages into spinner View
Spinner phoneListView = (Spinner) findViewById(R.id.phone_list);
Uri uri = Uri.parse("content://sms/inbox");
Cursor c = getContentResolver().query(uri, new String[]{"Distinct address"}, null, null, null);
List <String> list;
list= new ArrayList<String>();
list.clear();
int msgCount=c.getCount();
if(c.moveToFirst()) {
for(int ii=0; ii < msgCount; ii++) {
list.add(c.getString(c.getColumnIndexOrThrow("address")).toString());
c.moveToNext();
}
}
phoneListView.setAdapter(new ArrayAdapter<String>(BankActivity.this, android.R.layout.simple_dropdown_item_1line, list));
When you have multiple columns in your projection you should do like this:
val uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val projection = arrayOf(
"DISTINCT " + MediaStore.Images.Media.BUCKET_ID,
MediaStore.Images.Media.BUCKET_DISPLAY_NAME,
MediaStore.Images.Media.BUCKET_ID,
MediaStore.MediaColumns.DATA
)
val groupBySelection = " 1) GROUP BY (${MediaStore.Images.Media.BUCKET_ID}"
contentResolver.query(
uri,
projection,
null,
groupBySelection,
null,
null
)
groupBySelection with closing bracket and number "1" inside is a tiny hack, but it works absolutely fine
I created a utility method for using group by and distinct.
Usage
Here is an example of selecting unseen thread_id with the last message date from the MMS database.
query(contentResolver= contentResolver,
select = arrayOf(Mms.THREAD_ID, "max(${Mms.DATE}) as date"),
from = Mms.CONTENT_URI,
where = "${Mms.SEEN} = 0",
groupBy = "1",
orderBy = "2 desc"
).use {
while (it?.moveToNext() == true){
val threadId = it.getInt(0)
val date = it.getLong(1)
}
}
Source
fun query(
contentResolver: ContentResolver,
from: Uri,
select: Array<String>,
where: String? = null,
groupBy: Array<out String>? = null,
distinct: Boolean = false,
selectionArgs: Array<out String>? = null,
orderBy: String? = null,
): Cursor? {
val tmpSelect = select[0]
val localWhere =
if (groupBy == null) where
else "${where ?: "1"}) group by (${groupBy.joinToString()}"
if (distinct) {
select[0] = "distinct $tmpSelect"
}
val query = contentResolver.query(from, select, localWhere, selectionArgs, orderBy)
select[0] = tmpSelect
return query
}
Maybe its more simple to get distinct values,
try to add the DISTINCT word before the column name you want into the projection table
String[] projection = new String[]{
BaseColumns._ID,
"DISTINCT "+ Mediastore.anything.you.want
};
and use it as an argument to query method of the content resolver!
I hope to help you, cause I have the same question before some days