I have just begun working with the Android SDK and I am having problems with my first app. Currently, I am trying to list all of the users in a big list. However, no matter what I try, the app continues to force close. I found the code in the sample files, but this is still giving me issues. Below is the code I am using.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
String[] projection = new String[] {
People._ID,
People._COUNT,
People.NAME,
People.NUMBER
};
//Get the base URI for the People table in the Contacts content provider.
Uri contacts = People.CONTENT_URI;
//Make the query.
Cursor managedCursor = managedQuery(contacts,
projection, // Which columns to return
null, // Which rows to return (all rows)
null, // Selection arguments (none)
// Put the results in ascending order by name
People.NAME + " ASC");
Cursor c = getContentResolver().query(Contacts.CONTENT_URI, null, null, null, null);
startManagingCursor(c);
String[] columns = new String[] {People.NAME};
int[] names = new int[] {R.id.text1};
SimpleCursorAdapter mAdapter = new SimpleCursorAdapter(this,
R.layout.main, c, columns, names);
setListAdapter(mAdapter);
}
This is directly from the sample file, yet it still errors out. I have found that the line that causes the problem is the "Cursor managedCursor = managedQuery(contacts," line. Has anyone else out there seen this? I am at a loss and have not found any solutions after 2 hours or research.
Also, I have added the following line to my app's manifest file:
<uses-permission android:name="android.permission.READ_CONTACTS"></uses-permission>
Thanks, and if you need more information please let me know.
I believe the example from the SDK docs is out of date. Try getting rid of the People._COUNT column from the cursor projection.
It's probably causing an IllegalArgumentException (see the output from adb logcat)
Related
I have a AutoCompleteTextView that uses a SimpleCursorAdapter to filter emails for an input field. I have it working, although there are some deprecated commands that I am not sure how to rework.
The only problem I am having is that when I select a value from the list provided, I am not getting the email address selected, but something like the following:
android.content.ContentResolver$CursorWrapperInner#13a08d9c
Here is the code I have:
final AutoCompleteTextView edt_Contact = (AutoCompleteTextView)findViewById(idTo);
ContentResolver cr = getContentResolver();
String[] projection={ContactsContract.CommonDataKinds.Email._ID,ContactsContract.CommonDataKinds.Email.ADDRESS};
Cursor cursor = cr.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, projection, null, null, null);
startManagingCursor(cursor);
String[] from = new String[] { ContactsContract.CommonDataKinds.Email.ADDRESS};
int[] to = new int[] { android.R.id.text1};
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, cursor, from, to);
adapter.setFilterQueryProvider(new FilterQueryProvider() {
public Cursor runQuery(CharSequence constraint) {
return getContentResolver().query(ContactsContract.CommonDataKinds.Email.CONTENT_URI,
new String[] {},
ContactsContract.CommonDataKinds.Email.ADDRESS + " LIKE '%" + constraint + "%'",
null, null);
}
});
edt_Contact.setAdapter(adapter);
Any suggestions on how to get the actual selected value to populate the AutoCompleteTextView when selected?
Also, as mentioned, the deprecated items are startManagingCursor and SimpleCursorAdapter.
Found the solution and I am posting it here for anyone else with a similar situation
I needed to add the following
adapter.setStringConversion(1);
I added it right before the last line in the example above. This changed the result from the
android.content.ContentResolver$CursorWrapperInner#13a08d9c
to the selected email address.
Just a heads-up too for anyone using the MultiAutoCompleteTextView to do the same thing, this code works for that as well... just change add Multi before the AutoCompleteTextView and add the .setTokenizer of your choice.
I want to display a list of the contact names from the SMS inbox and outbox (like in the native messaging app). I have come up with the following code:
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
Uri messagesUri = Uri.parse("content://sms/");
Cursor cursor = getContentResolver().query(messagesUri,new String[] { "_id", "thread_id", "address", "person", "date", "body", "type" }, null, null, null);
startManagingCursor(cursor);
String[] columns = new String[] { "address", "person", "date", "body", "type" };
String sms = "";
if (cursor.getCount() > 0) {
while (cursor.moveToNext()){
String address = cursor.getString(cursor.getColumnIndex(columns[0]));
sms += address + " ";
String contact=address;
Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(address));
Cursor cs= getContentResolver().query(uri, new String[]{PhoneLookup.DISPLAY_NAME},PhoneLookup.NUMBER+"='"+address+"'",null,null);
startManagingCursor(cs);
if(cs.getCount()>0)
{
cs.moveToFirst();
contact=cs.getString(cs.getColumnIndex(PhoneLookup.DISPLAY_NAME));
}
listItems.add(contact);
}
}
adapter=new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1,
listItems);
setListAdapter(adapter);
}
This works when I run the application in an emulator, but when I try to run it on a phone I get a NullPointerException. If I double-click on the error message in the LogCat the following line gets highlighted:
if(cs.getCount()>0)
What is the problem here?
From the documentation for ContentResolver.query(...)
A Cursor object, which is positioned before the first entry, or null
You must always check for null when using a ContentResolver to query for data.
Also from the same documentation.
Use question mark parameter markers such as 'phone=?' instead of explicit values in the selection parameter, so that queries that differ only by those values will be recognized as the same for caching purposes.
So instead of:
Cursor cs= getContentResolver().query(uri, new String[ {PhoneLookup.DISPLAY_NAME},PhoneLookup.NUMBER+"='"+address+"'",null,null);
Do:
Cursor cs= getContentResolver().query(uri, new String[]{PhoneLookup.DISPLAY_NAME},PhoneLookup.NUMBER+"=?",new String[]{address},null);
My first guess would be that cs is null. As to why it is null, I suppose that the carrier/manufacturer could have changed how this is implemented on your device. Without knowing too much about how these systems work, it looks like you are querying against some kind of database and then using a cursor to iterate over the data. If the representation has been changed, the cursor will break. My suggestion would be to see if there is some other solution that is more Google/API driven (as opposed to reading the raw data).
I currently use the old contacts API (that was deprecated on Android 2.0), and I am wondering if the is a way to get all contacts along with their's phone number, without making a separate query for each contact as was advised in a few sites I found.
for instance in the old API, I could do something like this:
String[] projection = new String[] { Phones._ID, Phones.NAME,
Phones.NUMBER };
Uri contacts = Phones.CONTENT_URI;
Cursor managedCursor = managedQuery(contacts,
projection, // Which columns to return
null, // Which rows to return (all rows)
null, // Selection arguments (none)
// Put the results in ascending order by name
Phones.NAME + " ASC");
thanks.
I found what I was looking for, and using the new API is even simpler, here is the new way of querying all the contact along with their names and phone number:
Cursor managedCursor = getContentResolver()
.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
new String[] {Phone._ID, Phone.DISPLAY_NAME, Phone.NUMBER}, null, null, Phone.DISPLAY_NAME + " ASC");
I'm trying to simply get contacts from the Device phone book and display them on a Spinner, the code:
// Form an array specifying which columns to return.
String[] PROJECTION = new String[] {
People._ID, People.NAME
};
// Get the base URI for the People table in the Contacts content provider.
Uri contacts = People.CONTENT_URI;
Spinner contactsSpinner = (Spinner) findViewById(R.id.recipient_names);
// Make the query.
Cursor contactsCursor = managedQuery(contacts,
PROJECTION, // Which columns to return
null, // Which rows to return (all rows)
null, // Selection arguments (none)
// Put the results in ascending order by name
People.NAME + " ASC");
Log.e("EE", String.valueOf(contactsCursor.getCount()));
SimpleCursorAdapter sca = new SimpleCursorAdapter(
this, android.R.layout.simple_spinner_item,
contactsCursor, new String[] {People.NAME}, new int[] {android.R.id.text1}
);
Log.e("EE", String.valueOf(sca.getCount()));
sca.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
contactsSpinner.setAdapter(sca);
Compiles and runs fine, just that... The logs is showing 1 for both Log.e() call, which I think imply that contacts were actually retrieved successfully, however the Spinner is empty... Could anyone tell me I am doing wrong?
Turns out that it's not supported on sdk > 2.0
I'm torn about how to implement this because Content Provider URI querys do not support the simple SQL "DISTINCT" query method to return a cursor to the Artists of the songs in the mediastore, removing any duplicate entries.
I can query and get a cursor to all the artists, I'm just torn as to how to remove the dupes, or simply not show them.
I've tried using matrixcursor to construct a new cursor with the dupe entries removed, but it's slow (build an array of artists, if in that array don't copy to the new matrixcursor, etc.)
Can anyone recommend a better solution, or point me in the proper direction??
I've also thought about pre-loading the information i need into an array of objects - I'm just concerned with memory overhead in my application.
Thank You for any help you may provide.
The easiest way to get a list of all the artist (and albums is the same method) is to use the MediaStore.Audio.Artist for the quest. For Example something like this would get and show all the artist:
String[] proj = {MediaStore.Audio.Artists._ID, MediaStore.Audio.Artists.ARTIST, MediaStore.Audio.Artists.NUMBER_OF_ALBUMS, MediaStore.Audio.Artists.NUMBER_OF_TRACKS };
musiccursor = managedQuery(MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI, proj, null, null, MediaStore.Audio.Artists.ARTIST + " ASC");
String[] from= new String[]{ MediaStore.Audio.Artists.ARTIST, MediaStore.Audio.Artists.NUMBER_OF_ALBUMS, MediaStore.Audio.Artists.NUMBER_OF_TRACKS };
int[] to = new int[] { R.id.songname, R.id.rowlength, R.id.rowartist };
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.musicrow, musiccursor, from, to);
SongsView.setAdapter(adapter);
Where SongsView would be your list to display them in. Everything else is using a simple Cursor adapter
Hope this helps
You might want to try creating stateful CursorWrapper, overriding the appropriate methods. Simply ensure every call to next() iterates through the cursor until it finds an artist name you consider appropriately unique, optionally storing seen artists in an ArrayList instance variable.
ArrayList<SongBeen> genresList=new ArrayList<SongBeen>();
String value=search+ "%";
String[] inValue=new String[] {value};
ContentResolver musicResolver = activity.getContentResolver();
/*Uri musicInUri = android.provider.MediaStore.Audio.Genres.INTERNAL_CONTENT_URI;
Cursor mInternalCursor = musicResolver.query(musicInUri, null, null, null, null);
*/
Uri musicExUri = android.provider.MediaStore.Audio.Genres.EXTERNAL_CONTENT_URI;
Cursor mExternalCursor = musicResolver.query(musicExUri, null, MediaStore.Audio.Genres.NAME+ " like ?",
inValue, "LOWER(" + MediaStore.Audio.Genres.NAME + ") ASC");
Cursor[] cursors = {mExternalCursor};
final MergeCursor mMergeCursor = new MergeCursor(cursors);
if (mMergeCursor.moveToFirst()) {
do {
SongBeen been=new SongBeen();
long thisId= mMergeCursor.getLong(mMergeCursor.getColumnIndexOrThrow(MediaStore.Audio.Genres._ID));
String thisTrack = mMergeCursor.getString(mMergeCursor.getColumnIndexOrThrow(MediaStore.Audio.Genres.NAME));
been.setId(thisId);
been.setTrack(thisTrack);
genresList.add(been);
} while (mMergeCursor.moveToNext());
}
mMergeCursor.close();
return genresList;