getting values from columns through cursor - java

I am trying to get values of rows from requested columns using cursor but I am not getting that how to do it,what is the index inside cursor.getLong(?) ,Here is my code it works but I don't how is it working? Please help.
private Message cursorToMessage(Cursor cursor) {
Message message = new Message();
message.setId(cursor.getLong(0));
message.setmessage(cursor.getString(1));
message.setthreadid(cursor.getLong(0));
return message;
}

the index is the position of the column in your projection of the query.
do if you have in your projection that you want columns id,message,threadid then you would do
long id = cursor.getLong(0);
String message = cursor.getString(1);
long threadId = cursor.getLong(2);
the proper way to get a column so that you dont mix the indexes up would be to do this
cursor.getLong(cursor.getColumnIndex("id"));
I dont know if you did this or not but you should also be checking if the cursor has anything in it.
if(cursor != null && cursor.moveToFirst()){
message.setId(cursor.getLong(0));
message.setmessage(cursor.getString(1));
message.setthreadid(cursor.getLong(0));
}

Related

android.database.CursorIndexOutOfBoundsException: Index -1 requested, with a size of 1 while im not explicitly setting index [duplicate]

i want to select value from my database but i got error
Caused by: android.database.CursorIndexOutOfBoundsException: Index -1 requested, with a size of 1
i don't know where is the wrong in my code..
this is my code in dbHelper.
public Cursor pilihKontak( String nomor ) {
Cursor c = dba.rawQuery("SELECT idkontak FROM TB_kontak where nomor = '"+nomor+"'", null);
return c;
}
and i want to get the value in other class.
i use this code.
Cursor cursorKontak = data.pilihKontak(nomor);
idkontak = cursorKontak.getString(cursorKontak.getColumnIndex("k_id"));
i've searching and i didn't get the solution of my error.
can somebody help me?
i really need the solution, please help me..
thanks..
Regards..
You need to move the cursor to first and "k_id" should be "idkontak".
Cursor cursorKontak = data.pilihKontak(nomor);
if (cursorKontak.moveToFirst()) {
idkontak = cursorKontak.getString(cursorKontak.getColumnIndex("idkontak"));
}
The Cursor official docs say:
Function: getColumnIndex(String columnName):
It returns the zero-based index for the given column name, or -1 if the column doesn't exist.
So if you are getting Index -1 requested in the error, it means the column does not exist. So try to include the column as #StinePike suggested, or you may try to get all the rows:
Cursor c = dba.rawQuery("SELECT * FROM TB_kontak where nomor = '"+nomor+"'", null);
Then use the correct column name:
Cursor cursorKontak = data.pilihKontak(nomor);
idkontak = cursorKontak.getString(cursorKontak.getColumnIndex("CORRECT_COLUMN_NAME"));
Hope that helps.
use
Cursor c = dba.rawQuery("SELECT k_id FROM TB_kontak where nomor = '"+nomor+"'", null);

Displaying SQLite data in textview returning null

MainData myDBHlpr = new MainData(getActivity());
Cursor csr = myDBHlpr.getAllQuestions(UsageSettings.this);
while (csr.moveToFirst()) {
mMostMessagesSent.setText(csr.getString(csr.getColumnIndex("Reviews")));
mMostMessagesSent.setTextColor(Color.WHITE);
}
I checked row count and it showed 16
Then i checked
Log.d("TAG", csr.getString(cst.getColumnIndex("Reviews")));
And it showed error saying Log needs a message(Which means its null)
But why is it showing null even when the table has 16rows and column name exists
HELPER METHOD
public Cursor getAllQuestions(UsageSettings usageSettings) {
return this.getWritableDatabase().query(TABLE_NAME,null,null,null,null,null,null);
}

Telephony.Sms.Inbox.PERSON uses deprecated Contacts.People._ID

Bounty Award - The bounty will be awarded to an answer that gets from a populated Telephony.Sms.Inbox.PERSON value, to the associated Contact using only ContractsContact tables.
I'm reading SMS messages in the standard way in my application:
final String[] projection = {Telephony.Sms.Inbox.BODY,
Telephony.Sms.Inbox.ADDRESS,
Telephony.Sms.Inbox.READ,
Telephony.Sms.Inbox.DATE,
Telephony.Sms.Inbox.PERSON};
final Cursor cursor = ctx.getContentResolver().query(Telephony.Sms.Inbox.CONTENT_URI,
projection, null, null, Telephony.Sms.Inbox.DEFAULT_SORT_ORDER);
When populated, the id returned from the index Telephony.Sms.Inbox.PERSON relates to the id of the deprecated Contacts.People._ID and can be used to query further contact information in the following way:
final String[] projection = {Contacts.People.DISPLAY_NAME};
final String[] selectionArgs = {contactId};
final Cursor cursor = ctx.getContentResolver().query(Contacts.People.CONTENT_URI,
projection, Contacts.People._ID + " = ?", selectionArgs, null);
Why would the relatively new Telephony API use deprecated tables, instead of ContactsContract?
Telephony.Sms.Inbox.PERSON documentation states:
Type: INTEGER (reference to item in content://contacts/people)
I've tried unsuccessfully (but not unsurprisingly?) to find a mapping to the id in any of the ContactsContract id fields, so I'm left having to use deprecated APIs in order to resolve the queries I need to perform quickly.
Such queries include searching for messages by a particular contact, for which I only have the name. The contact could have multiple numbers, which may not be in the correct format to potentially match Telephony.Sms.Inbox.ADDRESS entries.....
The workaround of using Telephony.Sms.Inbox.ADDRESS and ContactsContract.PhoneLookup is not the end of the world when going from the number to the contact, but I still feel I must be missing something here?
Here is the process I'm using to get the messages for 'Joe Bloggs'.
1) Query the ContactsContract table to confirm a contact by the name of Joe Bloggs exists on the device - or get a close match if the contact is actually listed as 'Joe Blogs'.
2) Using the confirmed name, I query the deprecated Contact.People table to get all associated ids for the contact in the following way:
final String selection = Contacts.People.DISPLAY_NAME + " LIKE ?";
final String[] projection = {Contacts.People.DISPLAY_NAME,
Contacts.People._ID};
final String[] selectionArgs = {contactName};
final Cursor cursor = ctx.getContentResolver().query(Contacts.People.CONTENT_URI,
projection, selection, selectionArgs, null);
3) Using the list of deprecated contact ids, I query the message table as so:
final String[] referredArgs = new String[contactIdArray.size()];
for (int i = 0; i < contactIdArray.size(); i++) {
referredArgs[i] = contactIdArray.get(i);
}
final String referredSelection = Telephony.Sms.Inbox.PERSON + " IN "
+ "(" + TextUtils.join(",", referredArgs) + ")";
final String[] projection = {Telephony.Sms.Inbox.BODY,
Telephony.Sms.Inbox.ADDRESS,
Telephony.Sms.Inbox.READ,
Telephony.Sms.Inbox.DATE,
Telephony.Sms.Inbox.PERSON};
final Cursor cursor = ctx.getContentResolver().query(Telephony.Sms.Inbox.CONTENT_URI,
projection, referredSelection, null, Telephony.Sms.Inbox.DEFAULT_SORT_ORDER);
I'm hoping someone will tell me I'm going round the houses here and there is a more obvious solution using current APIs. I don't consider iterating the entire message table using ContactsContract.PhoneLookup an optimised solution.
Thanks in advance.
I wouldn't use the Telephony.Sms.Inbox.PERSON field, and definitely wouldn't query the deprecated People apis if I were you.
The People apis had been deprecated for so long you can't count on all devices our there to properly support it anymore.
First thing you need to understand is that there isn't a one-to-one link between sms and contacts.
An SMS can come from a non-contact phone number, a single contact, multiple contacts, a mixture of contacts and non-contacts, alpha-numeric ids, and even other, more rare options.
Next thing, you should read carefully the stock code and how it handles a properly called "Recipient ID" that you can get from the SMS collection, there's a collection called canonical-addresses (or canonical-address) that serves as a mapping between a phone number (or a comma-separated list of phones) and a recipient id.
The code does a single query on launch to cache the entire table in memory, and then uses it to map between phones and recipient-ids.
Here's the mapping class
Why would the relatively new Telephony API use deprecated tables, instead of ContactsContract?
What you are referring to is not new. In Telephony.java, you see it relies on the existing content://sms provider:
public static final class Inbox implements BaseColumns, TextBasedSmsColumns {
/**
* The {#code content://} style URL for this table.
*/
public static final Uri CONTENT_URI = Uri.parse("content://sms/inbox");
It was already there in Donut (and probably before, but I didn't check).
What's new in Kitkat is the ability to change the SMS app.
It's been five years and it's still relevant. You still need to do endlessly phoneLookup and hang up callbacks on contact tables if all you need to do is synchronize text messages.
I do not understand your concern properly but I am working on similar project, here is the basic code, and basic, important columns for fetching and display a message:
ContentResolver contentResolver = getContentResolver();
final String[] projection = new String[]{"*"};
Cursor SMSL = contentResolver.query(Telephony.Sms.CONTENT_URI, projection, null, null, "date ASC");
int msgscount = SMSL.getCount();
if (msgscount>0) {
msgs = new String[SMSL.getCount()][msgs_column_count];
int i = 0;
while (SMSL.moveToNext()) {
progress.setProgress(i);
msgs[i][0] = SMSL.getString(SMSL.getColumnIndex("address"));
msgs[i][1] = SMSL.getString(SMSL.getColumnIndex("date_sent"));
msgs[i][2] = SMSL.getString(SMSL.getColumnIndex("date"));
msgs[i][3] = SMSL.getString(SMSL.getColumnIndex("type"));
msgs[i][4] = SMSL.getString(SMSL.getColumnIndex("body"));
msgs[i][5] = SMSL.getString(SMSL.getColumnIndex("read"));
if (SMSL.getString(SMSL.getColumnIndex("service_center")) != null){
msgs[i][6] = SMSL.getString(SMSL.getColumnIndex("service_center"));
}else{
msgs[i][6] = "";
}
i++;
}
SMSL.close();
}else{
msgs = new String[0][0];
Toast.makeText(getApplicationContext(),"No messages found!",Toast.LENGTH_LONG).show();
}
If you want any help with this or fetching messages, let me know.

Android Telephony.Sms.Conversations

How can Telephony.Sms.Conversations be used to retrieve convo information to String?
I tried:
ContentResolver cr = context.getContentResolver();
Cursor convo = cr.query(Telephony.Sms.Conversations.CONTENT_URI,
new String[] { Telephony.Sms.Conversations.ADDRESS,
Telephony.Sms.Conversations.PERSON },
null,
null,
Telephony.Sms.Conversations.DEFAULT_SORT_ORDER);
How ever I get error invalid column address. when I remove address I get invalid column person. What column's does this class provide? (I couldn't find anything on the API reference page or any examples online. btw I already have a working code to retrieve inbox and outbox but I would like to get conversations too (I mean title and num of msges), without matching inbox and outbox results)
You can only get "msg_count" and "snippet" values from Telephony.Sms.Conversations, and you can get the "address" value from Telephony.TextBasedSmsColumns.
private static final String[] SMS_CONVERSATIONS_PROJECTION = new String[]{"msg_count", "snippet"};
Cursor cursor = cr.query(Telephony.Sms.Conversations.CONTENT_URI,
SMS_CONVERSATIONS_PROJECTION, null, null,Telephony.Sms.Conversations.DEFAULT_SORT_ORDER);
while(cursor.moveToNext()) {
int msg_count = cursor.getInt(cursor.getColumnIndex("msg_count"));
String snippet = cursor.getString(cursor.getColumnIndex("snippet"));
}
cursor.close;
It's inconvenient for us without "address", "date" and so on.
Telephony.Sms.Conversation

General weirdness with SQLite / Android

I have this simple application that I'm currently writing as practice. Its purpose is to allow the user to send a quote and the author of that quote on a server (in this case a Parse.com backend I have registered) and then show those quotes to other users of the app randomly. So by opening the app, you get a random comment that someone has posted.
The way I'm trying to accomplish this is:
On start-up, the app connects to the Parse.com backend and downloads all the currently available quotes (I call those Inanity objects because the quotes are supposedly enlightened but should actually be stupid and nonsensical - anyway, doesn't matter). This is the code:
query.findInBackground(new FindCallback<ParseObject>() {
SQLi sqlite = new SQLi(MainActivity.this);
SQLiteDatabase dbz = sqlite.getWritableDatabase();
#Override
public void done(List<ParseObject> list, ParseException e) {
//sqlite.dbDelete();
if (e == null) {
int size = list.size();
for (int i = 0; i < size; i++) {
ParseObject object = list.get(i);
String author = object.get("author").toString();
String content = object.get("content").toString();
Inanity inan = new Inanity(content, author, 1);
Log.d("FOR LOOP" + i, inan.toString());
sqlite.insertInanity(dbz, inan);
}
}
}
});
Pretty simple. (dbz is an SQLiteDatabase acquired by calling getWritableDatabase(), by the way). The code below is the code for the SQLiteOpenHelper insertInanity() method that I use to put the retrieved data from the server in the local SQLite database:
public void insertInanity(SQLiteDatabase db, Inanity inanity) {
ContentValues values = new ContentValues();
values.put(CONTENT_INANITIES, inanity.getContent());
values.put(AUTHOR_INANITIES, inanity.getAuthor());
values.put(UPVOTE_INANITIES, inanity.getUpvotes());
db.insert(TABLE_INANITIES, null, values);
}
I pass an SQLiteDatabase object to the method simply to avoid having to call getWriteableDatabase() - I had some trouble with recurring calls if I kept doing that.
After writing the server data on the local SQLite database, the user is taken to an Activity that starts showing the quotes and the author of the quotes in a couple of TextViews. This is the code the retrieves a quote/author object from the SQLite database:
public Inanity retrieveInanity(int id) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(TABLE_INANITIES, new String[] {
CONTENT_INANITIES, AUTHOR_INANITIES, UPVOTE_INANITIES },
ID_INANITIES + " = " + id, null, null, null, null);
if (cursor == null || cursor.getCount() == 0) {
return new Inanity("a", "b", 1);
}
else {
cursor.moveToFirst();
String contentL = cursor.getString(cursor
.getColumnIndex(CONTENT_INANITIES));
String authorL = cursor.getString(cursor
.getColumnIndex(AUTHOR_INANITIES));
int upvotesL = cursor.getInt(cursor
.getColumnIndex(UPVOTE_INANITIES));
Inanity inanity = new Inanity(contentL, authorL, upvotesL);
return inanity;
}
}
Finally, the quote to be displayed is randomly selected from the locally stored results thusly ("a" is an int variable declared earlier by the way)
final SQLi sql = new SQLi(this);
a = sql.getRowCount() + 1;
Button button = (Button) findViewById(R.id.button1);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Random rand = new Random();
int e = rand.nextInt(a);
if (e != 0) {
Inanity inanity = sql.retrieveInanity(e);
String content = inanity.getContent();
String author = inanity.getAuthor();
ImageView imageView = (ImageView) findViewById(R.id.downloaded);
TextView contentView = (TextView) findViewById(R.id.content);
TextView authorView = (TextView) findViewById(R.id.author);
Picasso.with(ShowActivity.this)
.load("http://img1.etsystatic.com/000/0/5356113/il_fullxfull.314192275.jpg")
.into(imageView);
contentView.setAlpha(0.9f);
authorView.setAlpha(0.9f);
Animation alpha = new AlphaAnimation(0.1f, 1.0f);
alpha.setDuration(2000);
contentView.setText(content);
authorView.setText(author);
contentView.startAnimation(alpha);
authorView.startAnimation(alpha);
}
else {
Toast.makeText(ShowActivity.this,
"Cursor trouble in wonderland!", Toast.LENGTH_LONG)
.show();
}
}
});
}
The getRowCount() method of the SQLi class is this:
public int getRowCount() {
int count = 1;
SQLiteDatabase db = getReadableDatabase();
Cursor cursor = db.rawQuery("SELECT * FROM " + TABLE_INANITIES, null);
if (cursor != null && cursor.getCount() > 0 && cursor.moveToFirst()) {
count = cursor.getCount();
}
return count;
}
For the most part. this works great. So, what's the problem, I hear you ask? Well, since I want to refresh the quotes every time the application starts up and get fresh ones from the server, the way I'm trying to accomplish that is by deleting the contents of the Inanity table of the database and re-populate them on start-up. So, I have created this method in the SQLi database helper class that's called dbDelete() which I call right at the start of the done() method of the FindCallback class of the Parse.com library (although I have commented this out from this code, it works swimmingly: it deletes the contents of the database just fine). Unfortunately, when I do that, it appears that the local SQLite database is not repopulated on app startup for some infernal reason, so I keep getting the placeholder "a", "b" and 1 values that are returned when the retrieveInanity() method cannot find cursor contents. Here is the dbDelete() method, which is quite simple:
public void dbDelete() {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_INANITIES, null, null);
}
I have been trying to solve this for quite some time and it's driving me crazy. I understand that the question is pretty convoluted, big and that it doesn't contain any catchy NullPointerExceptions/logcat action but any help would be appreciated. I must be missing something obvious related to the SQLite database use but I simply can't figure it out.
I wrote a similar app (one that made calls to a remote database and updated the info on local db). You should try using db.insertOrThrow. You will need to wrap the method in a Try...Catch statement. It will try to insert rows, and will throw an exception when a row already exists. You can then ignore the errors by leaving the Catch part blank. This will avoid the deletion and rebuild of the table.
try {
db.insertOrThrow(TABLE_INANITIES, null, values);
} catch SQLException s {
\\do nothing, as we don't care about existing rows
}
If you set up the quote server to have unique identifiers for the quote, then the local copy, your SQLite DB, will not insert duplicate entries. For example, your quote DB table on the server would look something like this
ID | Quote | Author
1 | blah | J. smith
Where the column ID is set as the unique identifier (or unique key). When your app calls the server and queries the remote DB, your local DB has only records that don't exist added to it.
You also want to make sure, I believe, that you update your cursor adapter in onResume().

Categories